less_retarded_wiki/brainfuck.md
2024-02-17 10:47:29 +01:00

5.3 KiB
Raw Blame History

Brainfuck

Brainfuck is an extremely simple, minimalist untyped esoteric programming language; simple by its specification (consisting only of 8 commands) but very hard to program in (it is so called Turing tarpit). It works similarly to a pure Turing machine. In a way it is kind of beautiful by its simplicity, it is very easy to write your own brainfuck interpreter (or compiler) -- in fact the Brainfuck author's goal was to make a language for which the smallest compiler could be made.

There exist self-hosted Brainfuck interpreters and compilers (i.e. themselves written in Brainfuck) which is pretty fucked up. The smallest one is probably the one called dbfi 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 (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. 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 community as the lowest common denominator language: just as mathematicians use Turing machines in proofs, esolang programmers use brainfuck in similar ways -- many esolangs just compile to brainfuck or use brainfuck in proofs of Turing completeness 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 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 (Brainfuck with multithreading), Boolfuck (has only binary cells), Brainfuck++ (adds more features like networking), Pi (encodes Brainfuck program in error agains pi digits), Unary (encodes Brainfuck with a single symbol) etcetc.

In LRS programs brainfuck may be seriously used as a super simple scripting language.

Brainfuck can be trivially translated to comun 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 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