Creating Brainfuck

FreakCdev - Jun 6 '21 - - Dev Community

Brainfuck is one of the most iconic programming languages out there, and probably the king of esolangs. So today, I will share how to create Brainfuck.

Understanding Brainfuck

So as we all might have known, Brainfuck has 8 commands:

  • ">" increment the data pointer (to point to the next cell to the right).
  • "<" decrement the data pointer (to point to the next cell to the left).
  • "+" increment (increase by one) the byte at the data pointer.
  • "-" decrement (decrease by one) the byte at the data pointer.
  • "." output the byte at the data pointer.
  • "," accept one byte of input, storing its value in the byte at the data pointer.
  • "[" if the byte at the data pointer is zero, then instead of moving the instruction pointer forward to the next command, jump it forward to the command after the matching ] command.
  • "]" if the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward to the next command, jump it back to the command after the matching [ command.

Choosing a way to run our code

Normally, you would have these programs to execute a programming language's codes:

  • Compiler (compiles to machine code)
  • Interpreter
  • Transpiler (compiles to source code)

Compilers are quite complex and they require you to have machine code's understanding which is not our choice when just creating a simple esolang. Interpreters and transpilers are good ones since they are easy to create, especially for esolangs. In this article, I will create a transpiler as it's the easiest.

Creating a transpiler

Language to use

I will use Javascript to create the transpiler, and the compilation target will be Javascript as well. Now, let's get our hand dirty.

Create a transpile function

We just simply create a function which takes all the codes as input, and return the compiled codes to output.

const transpile = input => {
    let output = 'let cells = Array(30000).fill(0), ptr=0;';
    return output;
}
Enter fullscreen mode Exit fullscreen mode

The output variable already has 1 line to declare an array cells which has 30000 elements all start at 0 and a ptr variable which is the pointer of the cell.

Parsing commands

We can create a simple lexer like this:

const transpile = input => {
    let output = 'let cells = Array(30000).fill(0), ptr=0;';
    input.split('').forEach(token => {

    })
    return output;
}
Enter fullscreen mode Exit fullscreen mode

Now, we want to do stuffs which each token (command), we just need to add a switch statement:

const transpile = input => {
    let output = 'let cells = Array(30000).fill(0), ptr=0;';
    input.split('').forEach(token => {
        switch (token) {
            case '+':
                break;
            case '-':
                break;
            case '>':
                break;
            case '<':
                break;
            case '.':
                break;
            case ',':
                break;
            case '[':
                break;
            case ']':
                break;
        }
    })
    return output;
}
Enter fullscreen mode Exit fullscreen mode

Then, we just implement each token's functionality in JS:

const transpile = input => {
    let output = 'let cells = Array(30000).fill(0), ptr=0;';
    input.split('').forEach(token => {
        switch (token) {
            case '+':
                output+='++cells[ptr];';
                break;
            case '-':
                output+='--cells[ptr];';
                break;
            case '>':
                output+='++ptr;';
                break;
            case '<':
                output+='--ptr;';
                break;
            case '.':
                output+='document.write(String.fromCharCode(cells[ptr]));';
                break;
            case ',':
                output+='cells[ptr]=prompt();';
                break;
            case '[':
                output+='while (cells[ptr] > 0) {';
                break;
            case ']':
                output+='}';
                break;
        }
    })
    return output;
}
Enter fullscreen mode Exit fullscreen mode

There you go, that's how you can create a Brainfuck transpiler, you just need to take the output codes and run them in a browser, then it should work fine.

Running it immediately

If you're tired of copying the output codes and run it in a different place, you can create a version that runs the code immediately like this:

const transpile = input => {
    let output = 'let cells = Array(30000).fill(0), ptr=0;';
    input.split('').forEach(token => {
        switch (token) {
            case '+':
                output+='++cells[ptr];';
                break;
            case '-':
                output+='--cells[ptr];';
                break;
            case '>':
                output+='++ptr;';
                break;
            case '<':
                output+='--ptr;';
                break;
            case '.':
                output+='document.write(String.fromCharCode(cells[ptr]));';
                break;
            case ',':
                output+='cells[ptr]=prompt();';
                break;
            case '[':
                output+='while (cells[ptr] > 0) {';
                break;
            case ']':
                output+='}';
                break;
        }
    })
    new Function(output)();
}
Enter fullscreen mode Exit fullscreen mode

Basically, we just create a new function and execute the codes.

Thanks for your time, if you're interested in programming languages, please consider checking out my language "FreakC".

. . . . . . . . .