Home About Me

Brainfuck and the Fine Art of Seriously Absurd Programming Languages

The world has never had a shortage of strange things. Nature has them, people have them, and computing has more than its fair share. In programming languages, oddity can be a matter of syntax, philosophy, or sheer stubborn minimalism. But the truly outrageous examples are not just weird programs written in normal languages; they are languages that are strange from the ground up.

One of the classic examples is Brainfuck. Despite the name, this is not merely a joke language. It is, in its own alarming way, a serious language. Please proceed with the appropriate degree of reverence.

A short introduction to BF

Brainfuck is an extremely minimal programming language created by Urban Müller in 1993. Because of the profanity in its name, it is sometimes written as brainfk, brainf* or simply BF**.

The language was designed around the idea of being Turing complete while using as few concepts as possible. Brainfuck has only eight commands. Every operation in the language is built from combinations of those eight characters.

The abstract machine behind BF is also deliberately simple. Besides the eight instructions, it consists of:

  • an array of bytes, initialized to zero;
  • a pointer into that array, initially pointing at the first byte;
  • one byte stream for input and one byte stream for output.

The full instruction set is as follows:

<table> <thead> <tr> <th>Character</th> <th>Meaning</th> </tr> </thead> <tbody> <tr> <td>></td> <td>Increment the pointer</td> </tr> <tr> <td><</td> <td>Decrement the pointer</td> </tr> <tr> <td>+</td> <td>Increment the byte at the pointer</td> </tr> <tr> <td>-</td> <td>Decrement the byte at the pointer</td> </tr> <tr> <td>.</td> <td>Output the byte at the pointer as an ASCII character</td> </tr> <tr> <td>,</td> <td>Read one byte of input into the current cell as ASCII</td> </tr> <tr> <td>[</td> <td>If the byte at the pointer is zero, jump forward to the command after the matching ]</td> </tr> <tr> <td>]</td> <td>If the byte at the pointer is nonzero, jump back to the command after the matching [</td> </tr> </tbody> </table>

A shorter way to describe ] is: jump back to the matching [ while the current cell is nonzero. That is equivalent to the more formal explanation above.

Another equivalent description is: [ jumps forward to the matching ] when the current byte is zero; ] jumps backward to the command after the matching [ when the current byte is nonzero.

If translated into C-like operations, assuming ptr is of type char*, the mapping is almost embarrassingly direct:

<table> <thead> <tr> <th>Brainfuck</th> <th>C</th> </tr> </thead> <tbody> <tr> <td>></td> <td>++ptr;</td> </tr> <tr> <td><</td> <td>--ptr;</td> </tr> <tr> <td>+</td> <td>++*ptr;</td> </tr> <tr> <td>-</td> <td>--*ptr;</td> </tr> <tr> <td>.</td> <td>putchar(*ptr);</td> </tr> <tr> <td>,</td> <td>*ptr =getchar();</td> </tr> <tr> <td>[</td> <td>while (*ptr) {</td> </tr> <tr> <td>]</td> <td>}</td> </tr> </tbody> </table>

A BF interpreter

Because Brainfuck has only eight instructions, no keywords, and no user-defined identifiers, writing an interpreter for it is surprisingly easy. Someone who has only recently learned C could still put one together.

Here is a compact interpreter written in ANSI C. It is just over 50 lines long, and any ordinary C compiler should be enough to build it.


#include <stdio.h>;

int  p, r, q;
char a[5000], f[5000], b, o, *s=f;

void interpret(char *c)
{
    char *d;

    r++;
    while( *c ) {
        //if(strchr("<>;+-,.[]\n",*c))printf("%c",*c);
        switch(o=1,*c++) {
            case '<': p--;        break;
            case '>;': p++;       break;
            case '+': a[p]++;     break;
            case '-': a[p]--;     break;
            case '.': putchar(a[p]); fflush(stdout); break;
            case ',': a[p]=getchar();fflush(stdout); break;
            case '[':
                for( b=1,d=c; b && *c; c++ )
                b+=*c=='[', b-=*c==']';
                if(!b) {
                    c[-1]=0;
                    while( a[p] )
                    interpret(d);
                    c[-1]=']';
                    break;
                }
            case ']':
                puts("UNBALANCED BRACKETS"), exit(0);
            case '#':
                if(q>;2)
                printf("%2d %2d %2d %2d %2d %2d %2d %2d %2d %2d\n%*s\n",
                *a,a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],3*p+2,"^");
                break;
            default: o=0;
        }
        if( p<0 || p>;100)
            puts("RANGE ERROR"), exit(0);
    }
    r--;
    //        chkabort();
}

main(int argc,char *argv[])
{
    FILE *z;

    q=argc;

    if(z=fopen(argv[1],"r")) {
        while( (b=getc(z))>;0 )
            *s++=b;
        *s=0;
        interpret(f);
    }
}

Of course, if implementing a Brainfuck interpreter in C feels like an insult to Brainfuck itself, that concern has already been anticipated. There has even been a compiler called awib, written in 100% pure Brainfuck: http://code.google.com/p/awib/

Hello, World in Brainfuck

Here is the traditional greeting, written in BF:

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

Not immediately obvious? That is normal. Expanded with comments, the same program looks like this:

+++ +++ +++ +           initialize counter (cell #0) to 10
[                       use loop to set the next four cells to 70/100/30/10
    > +++ +++ +             add  7 to cell #1
    > +++ +++ +++ +         add 10 to cell #2
    > +++                   add  3 to cell #3
    > +                     add  1 to cell #4
    <<< < -                 decrement counter (cell #0)
]
>++ .                   print 'H'
>+.                     print 'e'
+++ +++ +.              print 'l'
.                       print 'l'
+++ .                   print 'o'
>++ .                   print ' '
<<+ +++ +++ +++ +++ ++. print 'W'
>.                      print 'o'
+++ .                   print 'r'
--- --- .               print 'l'
--- --- --.             print 'd'
>+.                     print '!'
>.                      print '\n'

For further reading, the BF homepage is at http://www.muppetlabs.com/~breadbox/bf/, and the Wikipedia entry is http://en.wikipedia.org/wiki/Brainfuck.

Other unconventional languages

If Brainfuck already seems extreme, it is worth knowing that it is not alone. There are languages that manage to be strange in completely different directions.

Whitespace

Whitespace is a programming language that uses only blank characters: spaces, tabs, and line breaks. Every visible character is treated as a comment.

A sample program might look like this:






If you see nothing, that is exactly the point. The invisible part is the program. Its official site once offered a Hello, World example, with the important instruction that one should press Ctrl+A to reveal what is actually there.

Homepage: http://compsoc.dur.ac.uk/whitespace/index.php

LOLCODE

LOLCODE is based on heavily abbreviated Internet English. In general, if someone can understand the style of the meme language it imitates, they can often understand the source code without much training.

Its Hello, World example is wonderfully direct:

HAI
CAN HAS STDIO?
VISIBLE "HAI WORLD!"
KTHXBYE

In plain English, that is roughly:

Hi
Can I use STDIO?
Display "HAI WORLD!"
Thanks, bye

Homepage: http://lolcode.com/

Chinese programming languages

Do not assume that only foreign programmers create such peculiar languages. Chinese-language programming has produced its own unusual examples too.

Chinese BASIC

Chinese BASIC mapped Chinese commands onto Applesoft BASIC-style statements. For example:

<table> <thead> <tr> <th>Chinese instruction</th> <th></th> <th>Corresponding Applesoft BASIC</th> </tr> </thead> <tbody> <tr> <td>10 卜\=0</td> <td></td> <td>10 Y\=0</td> </tr> <tr> <td>20 入 水, 火</td> <td></td> <td>20 INPUT E, F</td> </tr> <tr> <td>30 從 日 \= 水 到 火</td> <td></td> <td>30 FOR A \= E TO F</td> </tr> <tr> <td>40 卜 \= 卜+對數(日)</td> <td></td> <td>40 Y \= Y + LOG (A)</td> </tr> <tr> <td>50 下一 日</td> <td></td> <td>50 NEXT A</td> </tr> <tr> <td>60 印 卜</td> <td></td> <td>60 PRINT Y</td> </tr> </tbody> </table>

Its original homepage is no longer accessible, but the Wikipedia entry remains: http://en.wikipedia.org/wiki/Chinese_BASIC

Chinese Python

Chinese Python, also known as 中蟒, is another memorable example. The following program is rather cool:

#!/usr/local/bin/cpython
回答 = 读入('你认为中文程式语言有存在价值吗 ? (有/没有)')
如 回答 == '有':
写 '好吧, 让我们一起努力!'
不然 回答 == '没有':
写 '好吧,中文并没有作为程式语言的价值.'
否则:
写 '请认真考虑后再回答.'

Homepage: http://www.chinesepython.org/

That is probably enough for one sitting. Once again, this has been a very serious discussion.