In the last article of this series on brainfuck, I will write a
brainfuck → JavaScript transpiler.
Instead of interpreting each brainfuck instruction, it will be converted
into a JS function once and for all.
Basics
The compiler will be a simple function, taking the brainfuck code
as first parameter and returning the corresponding JS function.
1 2 3 4 5
var bf = function(code){ var brainfuck_function; // ... return brainfuck_function; };
At some point, we will have a javascript source code. It will be turned
into a function with eval.
1 2 3 4 5 6 7 8 9
var bf = function(code){ var js_code = 'function(input){'; var brainfuck_function; // ... js_code += '};'; // close the js code
Exactly like with the interpreter, we need some place to store the cells: an array.
We also needs pointers. One for the memory, and one
for the input. We don’t need a code pointer anymore.
I also added the out variable. This is the output string, it’s what
the brainfuck_function will return at the end.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
var bf = function(code){ var js_code = [ // array of code fragments, concatenated later 'function(input){', 'var mem_ptr = 0,', 'input_ptr = 0,', 'mem = [],', 'out = "";' ];
for(var i = 0, l = code.length; i < l; i++){ var op = code.charAt(i); switch(op){ case'>': break; case'<': break; case'+': break; case'-': break; case'.': break; case',': break; case'[': break; case']': break; } }
Let’s transpile!
> move the data pointer forward
< move the data pointer backward
+ increments (+1) the current cell
- decrements (-1) the current cell
Cases > and < are obvious (mem_ptr++/--;). + and - are simple
too. Since the memory isn’t initialized, we can’t just do mem[mem_ptr]++/--;.
Instead, we ensure the cell is set to zero: mem[mem_ptr] = (mem[mem_ptr] || 0) +/- 1;
, reads one character from the input and writes it in the current cell
. and , are not much complex. . converts the cell value to the
corresponding character (ascii) and outputs it. The cell may be empty,
we use 0 as the default value.
Reading from the input is as easy. The only thing not to forget is to
increment the input pointer.
>>> var printFooBar = bf('++++++++++[>++++++++++>+++++++++++<<-]>++.>+..<----.-.>+++.') >>> printFooBar() foobar
>>> var reverse = bf('>,[>,]<[.<]') >>> reverse('mirror my words') sdrow ym rorrim
>>> var printBigB = bf('+++++++++++[->+++>++++++>+<<<]>->>->>>++>+>+>++>+>+>++<<<<<<[-[<+<+>>-]<<[>>+<<-]+>[[-]<[<]>>....>.[>]<->]<[[<]>>.<...>.>.[>]<-]+>>[-]>]') >>> printBigB() BBBB B B B B BBBB B B B B BBBB
The bf() function is included in this page so you can open your
javascript console and test it yourself!
Conclusion
I hope you liked this little exercise, now you can forget all about it.
This article is part of a series on brainfuck, a weird programming language: