Programming in Brainfuck: Part 3 — Using a preprocessor

Thu 30 June 2016 by TWal

This post is part 3 of the "Brainfuck tutorial" series:

  1. Programming in Brainfuck: Part 0 — Introduction
  2. Programming in Brainfuck: Part 1 — Common patterns & conditions
  3. Programming in Brainfuck: Part 2 — Arrays
  4. Programming in Brainfuck: Part 3 — Using a preprocessor

Here are the corrections for the exercises of part 2:

Compute the sum of an array:

[Tape: zero data1 flag1 ... datan flagn sum zero]
>+++>+>+++++>+>++++>+>++++++>+>> initialize array
<< [  loop on the array
    - clear the current flag
    < [ 
        > >>[>>]< go to sum
        + add 1
        <[<<]< go back to the current data
        - remove 1
    >+ set the current flag
    << go to the next flag

Test if two strings are the same:

[Tape: zero nothing flag1 data1 ... flagn datan zero isgood]
>> + [ go on the first flag and start the reading loop
    - clear the flag so we can use this cell as a "else flag" cell
    > , read the current character in data
    ---------- [ test if it is not a newline
        <+ set the else flag
        >[>+<-] go out of the loop using the next flag which is currently 0
    ] >[<+>-] move back the value of data
    <++++++++++ add 10 to it (to restore its value)
    <[>>+<<-] if the else flag is set then we must set the next flag to continue the loop
    + set our current flag to 1 (its original value before we used it as a else flag)
    >> go to the next flag
< [-] > the last data is a newline and we want the last character to be a 0 (which is by convention the EOF character)
> + set the isgood flag do 1
<<<[<<]>> go on our first flag
[ loop on the array
    - clear the current flag to remember our position
    , since the current flag is 0 we can use it as a temporary cell to read the current character
    [>-<-] > [ if the characters are different
        >[>>]>[-] clear the isgood flag
        <<<[<<] go back to the array
        >[-] clear the cell to go out of the loop
    <+ set the current flag back to 1
    >> go on the next flag
we are now at the zero cell
++++++[>++++++++<-] add 48 to the isgood flag
>. print it
<++++++++++. print a newline

You may notice that when I know that a cell is set to 0 I use it as a temporary cell, but you have to double-check that this is not interfering with other techniques (eg. the array flag is set to 0 so I used it to store the current character, but I can’t go outside the array because the array flag is no more 0!)

Using a preprocessor

You might notice that programming in brainfuck is unpleasant because there are no variable names and we spend most of the time to think about “Well, which cell am I currently at?” and not to think about how to make the actual program.

That’s why I designed a language above Brainfuck that compiles to Brainfuck: SimpleBrainfuck. I won’t explain how the language works because it’s explained in the README, but I will show you the code of the second exercise in simplebrainfuck

#_ That's a macro written in C
#_ We use it like this: _add(5) is like +++++ and _add(-3) is like ---
    int i;
    int nb = atoi(argv[0]);
    if(nb < 0) {
        for(i = 0; i < -nb; ++i) {
    } else {
        for(i = 0; i < nb; ++i) {

#_ That's a macro that moves the value of the cell v1 to the cell v2
#macro(moveTo; v1; v2;;
    =v1; [=v2; + =v1; -]

#_ We define what is in our tape
#_ nflag stands for "next flag"
#variables(Begin; zero; nothing; firstFlag) #_ Before the array
#variables(Array; flag; data; nflag) #_ Inside the array
#variables(End; lastFlag; lastData; zero; isgood) #_ At the end of the array

#_ That's a macro to go at the end of the array when we are inside it
    =nflag; [>>] @End@zero;

    =lastFlag; [<<] @Array@flag;

#_ Now the actual program
@Begin@zero; #_ This is how we tell to the preprocessor where we are
=firstFlag; #_ Go the cell named firstFlag. Here the preprocessor will insert ">>"
@Array@flag; + [
    =data; ,
    _add(-10) [
        =flag; +
        _moveTo(data; nflag)
    ] _moveTo(nflag; data)
    =data; _add(10)
    _moveTo(flag; nflag)
    =flag; +
< [-] >
=isgood; +
=zero; <<[<<]>> @Array@flag;
    , [=data; - =flag; -]
    =data; [
        _arrayToEnd() =isgood; [-]
        =data; [-]
    =flag; + >>
_add(6) [=isgood; _add(8) =zero; -]
=isgood; .
=zero; _add(10) .

In my opinion, the above code is more readable that the first one in pure brainfuck. An other advantage is that if you discover that you need an other temporary cell somewhere, it will be a lot easier to change your tape scheme than in pure brainfuck.


Exercise 1 (for the lazy writer): use SimpleBrainfuck to solve the previous exercises

Exercise 2: Now you learned enough things to craft big programs: why don’t you make a brainfuck interpreter in brainfuck? Given an input like code!in (! is a separator), you must run the code code with the input in

Here is a hint if you don’t know how to start: first, you read the code in an array, and then you have another array which will be the tape of the brainfuck program you interpret. Here is one solution if you want

Online resources

You can find several brainfuck programs on Esolang: algorithms and constants