Brainfuck

From Esolang
Jump to: navigation, search
The title of this article may well be brainfuck, due to typically being lowercased except, often, at the start of a sentence.

Brainfuck is the most famous esoteric programming language, and has inspired the creation of a host of other languages. Due to the fact that the last half of its name is often considered one of the most offensive words in the English language, it is sometimes referred to as brainf***, brainf*ck, brainfsck, b****fuck, brainf**k or BF. This can make it a bit difficult to search for information regarding brainfuck on the web, as the proper name might not be used at all in some articles.

Language overview[edit]

Brainfuck operates on an array of memory cells, also referred to as the tape, each initially set to zero. There is a pointer, initially pointing to the first memory cell. The commands are:

Command Description
> Move the pointer to the right
< Move the pointer to the left
+ Increment the memory cell under the pointer
- Decrement the memory cell under the pointer
. Output the character signified by the cell at the pointer
, Input a character and store it in the cell at the pointer
[ Jump past the matching ] if the cell under the pointer is 0
] Jump back to the matching [ if the cell under the pointer is nonzero

All characters other than ><+-.,[] should be considered comments and ignored. But see extensions below.

History[edit]

Brainfuck was invented by Urban Müller in 1993, in an attempt to make a language for which he could write the smallest possible compiler for the Amiga OS, version 2.0. He managed to write a 240-byte compiler. The language was inspired by False, which had a 1024-byte compiler. Müller chose to name the language brainfuck (with the initial letter in lower case, although it is now often capitalised).

It is not known to what extent Müller was aware of or influenced by Böhm's language P'' published in 1964, of which brainfuck can be considered a minor variation.

Examples[edit]

Hello, World![edit]

This program prints out the words Hello World!:

 1 +++++ +++               Set Cell #0 to 8
 2 [
 3     >++++               Add 4 to Cell #1; this will always set Cell #1 to 4
 4     [                   as the cell will be cleared by the loop
 5         >++             Add 4*2 to Cell #2
 6         >+++            Add 4*3 to Cell #3
 7         >+++            Add 4*3 to Cell #4
 8         >+              Add 4 to Cell #5
 9         <<<<-           Decrement the loop counter in Cell #1
10     ]                   Loop till Cell #1 is zero
11     >+                  Add 1 to Cell #2
12     >+                  Add 1 to Cell #3
13     >-                  Subtract 1 from Cell #4
14     >>+                 Add 1 to Cell #6
15     [<]                 Move back to the first zero cell you find; this will
16                         be Cell #1 which was cleared by the previous loop
17     <-                  Decrement the loop Counter in Cell #0
18 ]                       Loop till Cell #0 is zero
19 
20 The result of this is:
21 Cell No :   0   1   2   3   4   5   6
22 Contents:   0   0  72 104  88  32   8
23 Pointer :   ^
24 
25 >>.                     Cell #2 has value 72 which is 'H'
26 >---.                   Subtract 3 from Cell #3 to get 101 which is 'e'
27 +++++ ++..+++.          Likewise for 'llo' from Cell #3
28 >>.                     Cell #5 is 32 for the space
29 <-.                     Subtract 1 from Cell #4 for 87 to give a 'W'
30 <.                      Cell #3 was set to 'o' from the end of 'Hello'
31 +++.----- -.----- ---.  Cell #3 for 'rl' and 'd'
32 >>+.                    Add 1 to Cell #5 gives us an exclamation point
33 >++.                    And finally a newline from Cell #6

The same program in minimised form:

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

This is a slightly more complex variant that often triggers interpreter bugs

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

Move value[edit]

This code piece moves the value of the current cell (cell0) two cells to the right (cell2):

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

With indentation and comments the same code looks like this:

Code:   Pseudo code:
>>      Move the pointer to cell2
[-]     Set cell2 to 0 
<<      Move the pointer back to cell0
[       While cell0 is not 0
  -       Subtract 1 from cell0
  >>      Move the pointer to cell2
  +       Add 1 to cell2
  <<      Move the pointer back to cell0
]       End while

Cat[edit]

A cat program writes its input directly to its output. As there is not a standard way to handle EOF in brainfuck, there are four versions of the program below, labelled by how they match common implementations of the interpreter. (see Implementation issues).

EOF returns 0:

,[.,]

EOF returns -1:

,+[-.,+]

No change on EOF, or EOF returns 0:

,[.[-],]

No change on EOF, or EOF returns -1:

,+[-.[-]-,+]

Self-interpreters[edit]

Writing a self-interpreter in brainfuck is not a simple task, yet, several self-interpreters have been written throughout the years.

  • by Frans Faase - Perhaps the first one.
  • by NYYRIKKI
  • by Keymaker - Designed in the strictest 8-bit, non-wrapping, EOF = no change (EOF 0 works too) environment. The program emulates unbound cell size for cells (the program +[+] is valid and never ends) -- not really a brainfuck feature but it's there anyway -- and of course all the brainfuck programs written for the 8-bit non-wrapping environment work as supposed to. Supports infinite/unbound number of cells and nested loops.
  • by Daniel B Cristofani - The shortest; see also dbfi
  • by Clive Gifford - The fastest
  • by Adam Domurad - Interprets Brainfuck code from the input until a %, then reads remaining input as input for the interpreted program. Comments are allowed, and up to 256-depth nested loops

Computational class[edit]

Brainfuck is Turing-complete, meaning that it is in the same computational class as universal Turing machines. This, plus its dearth of commands, makes it a canonical example of a Turing tarpit.

This can be shown in a number of ways. The following formulations require the tape to be unbounded, but allow the value in each cell to be bounded:

Other formulations allow the tape to be bounded, but require that the value in each cell be unbounded:

  • Frans Faase gives a procedure for translating 5-register Universal Register Machines into brainfuck programs using five cells [1].
  • Ørjan Johansen has made a conversion from iterated Collatz functions to 3-cell brainfuck.

And still others require both the tape and the value in each cell to be unbounded:

Implementation issues[edit]

Brainfuck leaves a lot of things up to the implementation to decide, such as array and cell size, and what happens when EOF is read.

Memory and wrapping[edit]

The size of the cell array varies a lot in different implementations. The original compiler used an array of 30000 cells, while the later interpreter used only 5000.

The original implementation used bytes (0-255, wrapping around) for the memory cells. Most implementations do likewise, but some have been known to allow negative numbers or use bignums, allowing a memory cell to hold an arbitrarily large number.

What happens with a zero memory cell if it is decremented, is not portable. It might become a positive number, negative number, or an exception might be raised. Though, becoming a positive number is not operationally distinguishable from becoming a negative number that will later eventually wrap around to positive (e.g. if -128 wraps to 127, either way "zero minus one" will become 0 after 255 more decrements). Also is not portable to assume that a loop [+] (or [-] when the cell was negative before) will terminate (although it will eventually on most implementations).

Newlines[edit]

The vast majority of brainfuck programs, following Urban Müller's original example programs, use 10 as newline on both input and output; this is also the convention used by Unix-based operating systems, including Linux and Mac OS X. Some other operating systems use different conventions for newline, and may use different conventions on input and on output, and different conventions in different programming environments (e.g. C versus assembly language). Several solutions to the problem are possible:

  • Write brainfuck programs to accept multiple linefeed conventions. (Possible, though clunky, on input; not generally possible on output.)
  • Write many versions of each brainfuck program, one for each programming environment. (Possible, but very unpleasant.)
  • Forget portability and write programs for whatever implementation you are using. (A fairly common approach. May make it hard to share programs if your interpreter doesn't use 10 as newline.)
  • Write brainfuck interpreters and compilers to translate newline to 10 on input, and 10 to newline on output, in environments where that is not already the case. (Easy and helpful, but often overlooked. Also, may break the few brainfuck programs that do binary i/o; so newline translation should ideally be able to be turned off with a switch.)
  • Instead of having the user hit the "Enter" key, expect the user to do something else to give a 10 to the interpreter; e.g., the user can feed the input from a file which uses 10s to end the lines, rather than from the keyboard. Send the output to a file too. (Possible but clunky.)

EOF[edit]

EOF is a controversial issue. Many implementations return 0, some return -1, and several notable brainfuck programmers suggest that on EOF the memory cell should be left as-is, without modification. In the original distribution the compiler left the cell unchanged, while the interpreter used the EOF from C which, strictly speaking, could be any negative integer, but which usually is -1 (which, in the case of byte-sized cells, ends up as 255).

Extensions[edit]

Some implementations also recognize the following symbols as meaningful:

# Print contents of first few memory cells
! Separate code from input

The debug command # comes from brainfuck's original interpreter, written by Urban Müller. Because brainfuck programs have only one input source, brainfuck interpreters written in brainfuck (or other languages without file I/O) require ! to be able to distinguish a program's code from the input it is intended to process.

As all characters other than ><+-.,[] should be considered comments and ignored it is normal for an interpreter to have a method of disabling these extensions if required. This disabling may be automatic for '!' based on such things as if there is currently an open loop and/or if the program is being read from the 'standard input'.

As these commands are non-standard some interpreters use different codes for these functions.

Probably the next most frequently implemented extension is a command to comment out the rest of the line, however, experienced brainfuck programmers generally consider this useless mostly due to the existence of the header comments technique.

Algorithms[edit]

See Brainfuck algorithms, Brainfuck constants.

Related languages[edit]

See also Brainfuck extensions.

In publishing the formal programming language P'' in 1964, Corrado Böhm used six symbols precisely equivalent to the brainfuck commands +, -, <, >, [, and ], and provided an explicit program for each of the basic functions that together serve to compute any partial recursive function. (So in a very real sense, the first "brainfuck" programs appear in Bohm's 1964 paper.)

Many people at various times have tried to extend brainfuck to make it easier to program in, but such efforts have been compared to trying to make a luxury car by gluing parts onto a skateboard. Other people have been interested in variations of the language for theoretical purposes, pedagogical applications, etc. The sheer proliferation of languages equivalent to and derived from brainfuck led Chris Pressey to dub it "the twelve-bar blues of esolang". Some of the more interesting variants:

  • pbrain is a brainfuck extension that supports procedures.
  • cbrain is a derivative of pbrain as implemented in pbrain.c, adding integers and operators.
  • LecRAM is a brainfuck-based language with 30 new instruction, supporting ADS stack, procedures, IF condition and debug instructions
  • RUM stands for "bRainfUck iMproved." and adds procedures, strings and repetition.
  • Toadskin is a brainfuck variant that supports procedures, but uses a stack instead of a tape.
  • Brainfork adds a Y command to fork the current thread.
  • Fm edits a string on alphabet {0,1,...,m-1} (m >= 2).
  • FRAK assemble instructions to brainfuck code.
  • FukYorBrane and BF Joust pit two Brainfuck-like programs against each other, as in Core War (see Redcode).
  • Smallfuck operates only on bits and has no input- or output-commands.
  • Spoon uses a Huffman coded set of instructions corresponding to Brainfuck's commands.
  • BrainDuino BF port on Arduino HW platform (based on Atmel's ATMega). Extended by two special I/O operations and special overflow protection.
  • Puzzlang turns every program into an exercise in patience and logic puzzle skills. The lone X operator becomes any of brainfuck's instructions, depending on the surrounding characters.
  • Alarm Clock Radio throws away the instructions to decrement the memory pointer or memory value.
  • tbf is a language that can be compiled to Brainfuck. It includes variables, strings, macros and improved loops.
  • Grin adds more efficient arithmetic functions to Brainfuck.

Some other funny variants:

  • Ook! works exactly like brainfuck, except the syntax is in Orangutan.
  • Blub is the same for fish.
  • Matisse uses colors to merge brainfuck codes and program comments.
  • Brainloller has the same commands as brainfuck, except they're read from a png image.
  • COW is like Ook!, except with a bovine syntax.
  • Pi obfuscates Brainfuck instructions in random errors in pi digits.

Some languages inspired by brainfuck, but with more major differences:

  • Aura requires data to be stored in the code space.
  • PATH and SNUSP attempt to combine brainfuck with Befunge.
  • Wierd arose out of an earlier attempt to combine brainfuck with Befunge.

See also[edit]

External resources[edit]

Notable implementations[edit]

For a complete list, see brainfuck implementations.

Hardware implementations[edit]