123 lines
5.4 KiB
Markdown
123 lines
5.4 KiB
Markdown
# Brainfuck
|
||
|
||
Brainfuck is an extremely simple, [minimalist](minimalism.md) untyped [esoteric programming language](esolang.md); simple by its specification (consisting only of 8 commands) but very hard to program in (it is so called [Turing tarpit](turing_tarpit.md)). It works similarly to a pure [Turing machine](turing_machine.md). In a way it is kind of [beautiful](beauty.md) by its [simplicity](minimalism.md), it is very easy to write your own brainfuck [interpreter](interpreter.md) (or [compiler](compiler.md)) -- in fact the Brainfuck author's goal was to make a language for which the smallest compiler could be made.
|
||
|
||
There exist **[self-hosted](self_hosting.md) Brainfuck interpreters and compilers** (i.e. themselves written in Brainfuck) which is pretty fucked up. The smallest one is probably the one called [dbfi](dbfi.md) which has only slightly above 400 characters, that's incredible!!! (Esolang wiki states that it's one of the smallest self interpreters among imperative languages). Of course, **Brainfuck [quines](quine.md)** (programs printing their own source code) also exist, but it's not easy to make them -- one example found on the web was a little over 2100 characters long.
|
||
|
||
The language is based on a 1964 language P´´ which was published in a mathematical paper; it is very similar to Brainfuck except for having no [I/O](io.md). Brainfuck itself was made in 1993 by Urban Muller, he wrote a compiler for it for Amiga, which he eventually managed to get under 200 bytes.
|
||
|
||
Since then Brainfuck has seen tremendous success in the [esolang](esolang.md) community as the **lowest common denominator language**: just as mathematicians use [Turing machines](turing_machine.md) in proofs, esolang programmers use brainfuck in similar ways -- many esolangs just compile to brainfuck or use brainfuck in proofs of [Turing completeness](turing_complete.md) etc. This is thanks to Brainfuck being an actual, implemented and working language with I/O and working on real computers, not just some abstract mathematical model. For example if one wants to encode a program as an integer number, we can simply take the [binary](binary.md) representation of the program's Brainfuck implementation. Brainfuck also has many derivatives and modifications (esolang wiki currently lists over 600 such languages), e.g. [Brainfork](brainfork.md) (Brainfuck with [multithreading](multithreading.md)), Boolfuck (has only binary cells), Brainfuck++ (adds more features like [networking](network.md)), Pi (encodes Brainfuck program in error agains [pi](pi.md) digits), Unary (encodes Brainfuck with a single symbol) etcetc.
|
||
|
||
In [LRS](lrs.md) programs brainfuck may be seriously used as a super simple [scripting language](script.md).
|
||
|
||
Brainfuck can be trivially translated to [comun](comun.md) like this: remove all comments from brainfuck program, then replace `+`, `-`, `>`, `<`, `.`, `,`, `[` and `]` with `++ ` , `-- `, `$>0 `, `$<0 `, `->' `, `$<0 <- `, `@' ` and `. `, respectively, and prepend `$>0 `.
|
||
|
||
## Specification
|
||
|
||
The "vanilla" brainfuck operates as follows:
|
||
|
||
We have a linear memory of **cells** and a **data pointer** which initially points to the 0th cell. The size and count of the cells is implementation-defined, but usually a cell is 8 bits wide and there is at least 30000 cells.
|
||
|
||
A program consists of these possible commands:
|
||
|
||
- `+`: increment the data cell under data pointer
|
||
- `-`: decrement the data cell under data pointer
|
||
- `>`: move the data pointer to the right
|
||
- `<`: move the data pointer to the left
|
||
- `[`: jump after corresponding `]` if value under data pointer is zero
|
||
- `]`: jump after corresponding `[` if value under data pointer is not zero
|
||
- `.`: output value under data pointer as an ASCII character
|
||
- `,`: read value and store it to the cell under data pointer
|
||
|
||
Characters in the source code that don't correspond to any command are normally ignored, so they can conveniently be used for comments.
|
||
|
||
Brainfuck source code files usually have *.bf* or *.b* extension.
|
||
|
||
## Implementation
|
||
|
||
This is a very simple [C](c.md) implementation of brainfuck:
|
||
|
||
```
|
||
#include <stdio.h>
|
||
|
||
#define CELLS 30000
|
||
|
||
const char program[] = ",[.-]"; // your program here
|
||
|
||
int main(void)
|
||
{
|
||
char tape[CELLS];
|
||
unsigned int cell = 0;
|
||
const char *i = program;
|
||
int bDir, bCount;
|
||
|
||
while (*i != 0)
|
||
{
|
||
switch (*i)
|
||
{
|
||
case '>': cell++; break;
|
||
case '<': cell--; break;
|
||
case '+': tape[cell]++; break;
|
||
case '-': tape[cell]--; break;
|
||
case '.': putchar(tape[cell]); fflush(stdout); break;
|
||
case ',': scanf("%c",tape + cell); break;
|
||
case '[':
|
||
case ']':
|
||
if ((tape[cell] == 0) == (*i == ']'))
|
||
break;
|
||
|
||
bDir = (*i == '[') ? 1 : -1;
|
||
bCount = 0;
|
||
|
||
while (1)
|
||
{
|
||
if (*i == '[')
|
||
bCount += bDir;
|
||
else if (*i == ']')
|
||
bCount -= bDir;
|
||
|
||
if (bCount == 0)
|
||
break;
|
||
|
||
i += bDir;
|
||
}
|
||
|
||
break;
|
||
|
||
default: break;
|
||
}
|
||
|
||
i++;
|
||
}
|
||
}
|
||
|
||
```
|
||
|
||
TODO: comun implementation
|
||
|
||
## Programs
|
||
|
||
Here are some simple programs in brainfuck.
|
||
|
||
Print `HI`:
|
||
|
||
```
|
||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ . + .
|
||
```
|
||
|
||
Read two 0-9 numbers (as ASCII digits) and add them:
|
||
|
||
```
|
||
,>,[<+>-]<------------------------------------------------.
|
||
```
|
||
|
||
TODO: more
|
||
|
||
## Variants
|
||
|
||
TODO
|
||
|
||
## See Also
|
||
|
||
- [False](false.md) (a very similar esolang)
|
||
- [comun](comun.md) |