Crainfuck
Crainfuck is a derivative of Brainfuck by User:Stump that combines the beauty of Brainfuck with the power of C. The name comes from a combination of Brainfuck and C.
Crainfuck allows the programmer to access any API that C can normally access, as well as define functions that can be called from C. Crainfuck does not (yet) provide for functions to access their own arguments, but functions written in Crainfuck can return values or pointers, call C functions without arguments, and call C functions with the Crainfuck tape pointer as an argument. Extension to multiple arguments is planned, as is getting at the return value from C functions.
Many of the new features of Crainfuck are illustrated in the "Hello World" program which uses ncurses to demonstrate calling C functions. In C one would do something like this:
#include <ncurses.h> #include <stdlib.h> int main() { initscr(); printw("Hello World!"); refresh(); getch(); endwin(); exit(0); }
The equivalent program in Crainfuck is this:
&&&ncurses i:main:icpp({initscr}++++++++++[>+++++++>++++++++++>+++++++++++>+++ ++++++++>+++++++++++>+++>+++++++++>+++++++++++>+++++++++++>+++++++++++>+++++++ +++>+++<<<<<<<<<<<<-]>++>+>-->-->+>++>--->+>++++>-->>+++<<<<<<<<<<<{printw:p} {refresh}{getch}{endwin}[-]*@)
A Crainfuck program has the following syntactic elements:
- Comments can be added as in C and C++, /* multiline comments */ and // line comments
- C headers are #include'd in the resulting metacompiled C file using the &&& command, as in &&&ncurses in the hello world program. "#include <" and ".h>" are automatically added. (stdio.h and stdlib.h are always included to support Brainfuck code.) The name of the header is terminated by a space or a newline.
- Code is organized into functions, just like in C. Prototypes will be generated automatically by the metacompiler. A function definition looks like returntype:functionname:args(code). From the returntype to the ( must be contiguous (no spaces or newlines allowed). Returntype is a type code (see below), functionname is the function name (in the hello world program it is main), and args is a bunch of type codes run together to represent the arguments the function accepts. (Not that there is yet any way to work with those arguments...) Code within ( ... ) may be freely formatted but is terminated by the first ) that is not in a comment.
- The code inside a function is extended Brainfuck. See below for just what extensions there are.
- Anything that is not a Crainfuck function will be written into the C file verbatim, so you can freely mix C and Crainfuck functions.
Type Codes are used to tell the metacompiler how to make your function look to C. One character expands to one word.
Type code | C equivalent |
---|---|
u | unsigned |
l | long |
s | short |
i | int |
c | char |
v | void |
f | float |
d | double |
p | * |
So the definition "i:main:icpp(...)" in the hello world program metacompiles to the ubiquitous "int main(int arg1, char** arg2) { ... }".
I wish you the best of luck if you decide to try doing anything with floats and doubles in Brainfuck ;-)
The final element of Crainfuck is the extended Brainfuck that functions are written with. This has the following syntactic elements:
- Each invocation of a function has its own 30,000 space tape of unsigned chars, which is initialized to all zeros at the beginning and has the pointer at the beginning. Writing past the beginning or end of the tape will cause the program to segfault at runtime.
- + - < > . , [ ] are all exactly the same as in Brainfuck. (, sets 255 on EOF.)
- To call a C function without arguments, use {function}. For example, {initscr} metacompiles to initscr();
- To call a C function with the pointer as an argument, use {function:p}. For example, {printw:p} metacompiles to printw(ptr);
- To exit the program with the pointer as argument, use @ (inspired by Befunge). Dereferencing the pointer (which you almost certainly want to do to return a meaningful value!) is achieved by adding the correct number of * immediately before the @. For example, the hello world program ends with [-]*@, which sets the current cell to 0 then dereferences the pointer and calls exit(), thus exiting the program with a return code of 0 (success).
- To return a value from the function, do the same thing as exiting but just use % instead of @. The same rules for dereferencing the pointer apply, except in this case you may actually want to return the pointer (for example if your function sets up some data structure - watch out as this ties your code to a specific endianness and word length).
The limited set of features in Crainfuck right now can still be used for some interesting constructs by passing the tape pointer to some function (written in C) that constructs some data structure at the pointer it is given. The data structure will be on the Brainfuck tape when the function returns.
The language is Turing complete because it incorporates the Turing complete languages Brainfuck and C.
External resources
- The Official Crainfuck Distribution (dead link) (can someone please mirror this?) Contains the hello world program, a metacompiler in Perl, and a frontend in bash shell script. Written with GNU/Linux in mind but will probably work under Cygwin, the BSDs, and Mac OS X.