brainfuck

A brainfuck interpreter in pure C (C89 / ANSI C).



brainfuck is a minimalistic programming language that consists entirely of eight commands: . , < > + - [ and ]. When writing brainfuck you visualize the computational environment as a long grid of 8-bit cells which you must use to perform all of your computations. Cells are accessed and modified with a pointer that you control with the < and > commands. The + and - commands will add or subtract from the value of the current cell. [ will jump to the corresponding ] if the current cell is 0. The , command will set the value of the current cell to whatever key the user presses, and the . command will print the ASCII representation of the cell.

I actually wrote two versions of the interpreter: the first was a very simple thing that loaded the entire program text into memory and ran it directly. It suffered from performance issues because of it’s simplicity.

The second version goes through a “compilation” process. Instead of simply holding the program and looking at each character individually, it converts the program into an internal representation, which moves some of the computational cost from runtime to compilation. This means that when we encounter something like a [ command, we don’t need to find the corresponding ] every time we look at it. This approach drastically reduces the run time of most programs.

The switch also made it much easier to add specialized commands based on common brainfuck idioms, like the ones describe on this page. My interpreter contracts commands, detects multiplication loops, clearloops, dead code, and redundant commands, which makes it fast enough to run hanoi.bf in less than a second.

So after running many of the popular bf programs, I started experimenting with non-standard features and add-ons. A (relatively) famous program written in brainfuck is mandelbrot.bf, which generates an ascii visualization of the Mandelbrot set. I searched a bit and found several other versions of the program (which was generated with C preprocessor macros, not actually written by hand), including a “titannic” version that generated a 512x196 fractal:

It looks pretty high-res as text, so I thought it would be cool to interpret it as an image:

Kinda cool! But it’s very very squashed because it was intended to be printed as text, and text characters aren’t squares (like pixels.) The idea of graphics with brainfuck was appealing, so I threw an “image mode” into the interpreter, turned on with an “-img” commandline argument. Once image mode is on it will expect the program being run to print the rgb value of each pixel row by row, and to print the number -1 at the end of every row. This allows it to deduce the resolution of the image without any extra information. Once the program has finished the output is saved to the output file (specified with the “-o” parameter.) Here’s a program that generates a gradient (with 16 bit cells):

>>++++++++++++++++++++++++++++++++[<++++++++++++++++++++++++++++++++<++++++++++++++++++++++++++++++++>>-]<<[>[>><<..<.>>><<-]>++++++++++++++++++++++++++++++++[<++++++++++++++++++++++++++++++++>-]<<-]

I tried to write some other things with bf, but anything nontrivial is pretty tedious to write. I’m not sure what I was expecting. But from what I did write, I learned that many things are very simple and repetitive to write by hand, and could easily be automated. So I did the natural thing, and created a macro language that generates brainfuck. Here’s the gradient program:



var x

x = 128

var y

y = 128 var end_row

end_row = -1 while y

while x

printc x

printc y

printc x

x - 1

end

printc end_row

x = 128

y - 1

end

which generates this (relatively bad) brainfuck (which works with 8-bit cells because of the image resolution):

><[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>>[-]<[-]<[>+>+<<-]>>[<<+>>-]<>>>>>>>>>><[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>>[-]<[-]<[>+>+<<-]>>[<<+>>-]<>>>>>>>>>><[-]->>[-]<[-]<[>+>+<<-]>>[<<+>>-]<<<<<<<<<<<[<<<<<<<<<<[.>>>>>>>>>>.<<<<<<<<<<.<[-]+>>[-]<<[>->+<<-]>>[<<+>>-]<]>>>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<<<<<<<<<<<[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>>[-]<[-]<[>+>+<<-]>>[<<+>>-]<>>>>>>>>>><[-]+>>[-]<<[>->+<<-]>>[<<+>>-]<]

I eventually threw out the entire image mode thing because it was weird, but kept the ability to dump the program’s output to a file. The macro language was cool, so I kept working on it (it’s also in pure ANSI C), and it is now capable of generating relatively complex programs. I’ve now spent faaaar more time on it than on the interpreter. (Most of the brainfuck algorithms were stolen and customized from the EsoLang wiki page)

Here’s a one-dimensional cellular automata program generated with it. To run it, just press the “raw” button on that page, select the entire thing, and paste it into an interpreter like Le Brainfuck.

The macro language is easy enough to write that a graphical variation (that actually creates the image data from scratch) was trivial:



Here’s fizzbuzz, and here’s the macro program that generated it:

var i

var max

i = 1

max = 100 var i_not_done

i_not_done = 1 while i_not_done

var should_print_num

should_print_num = 1



var is_divizz

is_divizz = i

is_divizz % 3

is_divizz == 0



if is_divizz

should_print_num = 0

print fizz

endif



is_divizz = i

is_divizz % 5

is_divizz == 0



if is_divizz

should_print_num = 0

print buzz

endif



if should_print_num

printv i

endif



i_not_done = i

i_not_done == max

not i_not_done



printc 10



i + 1

endwhile

(naming conventions on point)