{tape} ← {tape} ##.bf toks                  ⍝ Brainfuck.

The startling term "Brainfuck", henceforth "BF" in the interests of brevity (and
delicacy), denotes  both a theoretical machine and its order-code or programming
language.  The  machine  is  an exercise in minimalism in that it has only eight
instructions, none of which takes an explicit operand.

Despite its simplicity,  BF is "Turing-complete", which means that, given enough
time and memory,  it may be programmed  to solve any problem that a regular com-
puter can tackle. See: http://www.iwriteiam.nl/Ha_bf_Turing.html

For a full description of the language, together with some programming examples,
see: http://en.wikipedia.org/wiki/Brainfuck

Machine architecture
--------------------
The machine has just two "moving parts":

-   An instruction token stream, the character vector argument to the function.

        ┌───┬───┬───┬───┬───┬───┬───┬───┬──
        │ > │ [ │ - │ < │ + │ > │ ] │ < │    ∘∘∘
        └───┴───┴───┴───┴───┴───┴───┴───┴─

-   An infinite "tape" of cells, each of which holds a single number.

        ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬──
        │ 1 │ 3 │ 4 │ 48│ 49│ 0 │ 1 │ 2 │ 5 │ 0  ∘∘∘
        └───┴───┴───┴───┴───┴───┴───┴───┴───┴──

The tape and token stream are manipulated using the eight machine instructions:

    >    Move tape pointer one cell position to right.
    <    Move tape pointer one cell position to left.

    +    Increment value in current tape cell.
    -    Decrement value in current tape cell.

    .    Output character corresponding to value in current tape cell.
    ,    Set value in current tape cell to ⎕UCS value of an input char.

    [    If current cell value = 0, jump to right of matching ] in token stream.
    ]    If current cell value ≠ 0, jump to right of matching [ in token stream.

The final two instructions, [ and ], provide a "while loop".

Any characters other than the above eight "<>+-.,[]" are ignored and may be used
as program commentary (see example below).

Programming
-----------
The  following  vector  (with  embedded newlines) is an example of a BF program,
which outputs the string 'Hello World':

          display hello
    ┌→───────────────────────────────────────────────┐
    │addr:val shows current cell address and value   │
    │                                                │
    │+++++ +++++ [           0:10 × loop:            │
    │    > +++++ ++          1:10×7 for H W          │
    │    > ++                2:10×2 for e l l o r l d│
    │    << -                0: decr loop counter    │
    │]                       0:0                     │
    │>++ .                   1:72 → H                │
    │>+.                     2:21 → e                │
    │+++++ ++ ..             2:28 → l l              │
    │+++ .                   2:31 → o                │
    │<<++++ .                0:4  →  sp              │
    │>+++++ +++++ +++++ .    1:87 → W                │
    │> .                     2:31 → o                │
    │+++ .                   2:34 → r                │
    │--- --- .               2:28 → l                │
    │--- --- --.             2:20 → d                │
    │<<-.                    0:3  →  nl              │
    └────────────────────────────────────────────────┘

Take care,  when commenting such programs, to avoid using any of the instruction
characters: "<>+-.,[]".

Using the tape
--------------
The  final state of the tape is returned as a shy result of the function and may
be  re-loaded  as  optional left argument to a subsequent BF session. This means
that  we can use the state of the tape for simple calculations without having to
convert  between  characters  '1' '2' '3' ... and numbers 1 2 3 .. for input and
output.

        ⎕←123 45 bf '[->+<]'    ⍝ 123 + 45 → 168
    0 168

Tracing
-------
We  can  watch  the progress of the machine by removing the leading '⍝' from the
first line of inner fuction "machine":

    machine←{                       ⍝ machine definition: ⍺:tape ⍵:toks.
        t←get ⍵                     ⍝ next token.
    ⍝   ⎕←t,↑' ()',.,⍕∘∊¨⍺          ⍝ uncomment to trace.
    │   ...       └─┴───────────────  "mesh" (Nicolas Delcros).
    └───────────────────────────────  remove '⍝' to watch trace.

With  tracing  enabled, the next token and memory tape (⍺) are displayed at each
step with the current tape cell in parentheses:

    +bf'>++[<+++>-]<'               ⍝ 2 × 3
> 0(0)0
+ 0 0(0)0
+ 0 0(1)0
[ 0 0(2)0
< 0 0(2)0
+ 0(0)2 0
+ 0(1)2 0
+ 0(2)2 0
> 0(3)2 0
- 0 3(2)0
] 0 3(1)0
< 0 3(1)0
+ 0(3)1 0
+ 0(4)1 0
+ 0(5)1 0
> 0(6)1 0
- 0 6(1)0
] 0 6(0)0
< 0 6(0)0
∘ 0(6)0 0
6 0

Turing's Tape
-------------
BF's memory is a tape of cells,  which extends to infinity in the ">" direction.
At any time,  exactly one cell is  under the machine's read-head.  Order codes <
and > shift the tape to make current the next cell to the left or right.

                                ┌──────────────┐
                        ┌───────│              │───────┐
                  ┌─────│ next  │  "current"   │ next  │─────┐
              ┌───│ nxt │ cell  │    cell      │ cell  │ nxt │───┐
 -○○ ···∘∘∘⎕⎕⎕│ < │ lft │ left  │  referenced  │ right │ rgt │ > │⎕⎕⎕∘∘∘··· +○○
              └───│  <  │   <   │  by <>[]+-., │  >    │  >  │───┘
                  └─────│       │ instructions │       │─────┘
                        └───────│              │───────┘
                                └──────────────┘

This infinite tape mechanism is borrowed from Alan Turing's theoretical machine.
See: http://en.wikipedia.org/wiki/Turing_machine

Technical notes:

Both  tape  and token stream are pleasingly implemented in Dyalog as a recursive
data structure,  which is a pair of "snoc" and "cons" →list←s,  separated by the
current cell. The tape is accessed using structure assignment:

    get←{_ m _←⍵ ⋄ m}                   ⍝ current item.
    put←{l _ r←⍵ ⋄ l ⍺ r}               ⍝ ⍺ replaces current item.

    lft←{(ll l)m r←⍵ ⋄ ll l(m r)}       ⍝ tape pointer left.
    rgt←{l m(r rr)←⍵ ⋄ (l m)r rr}       ⍝ tape pointer right.

Note how Dyalog's "scalar extension" mechanism automatically extends the tape in
either direction, as required:

    tape←0 99 0                         ⍝ initial 3-cell tape.

    tape ← lft lft tape ⋄ disp tape     ⍝ move two cells left, extending tape.
┌─┬─┬────────┐
│0│0│┌─┬────┐│
│ │ ││0│99 0││
│ │ │└─┴────┘│
└─┴─┴────────┘

    tape ← rgt rgt tape ⋄ disp tape     ⍝ move two cells right again.
┌───────┬──┬─┐
│┌───┬─┐│99│0│
││0 0│0││  │ │
│└───┴─┘│  │ │
└───────┴──┴─┘

    tape ← rgt rgt tape ⋄ disp tape     ⍝ move two cells right, extending tape.
┌────────────────┬─┬─┐
│┌────────────┬─┐│0│0│
││┌───────┬──┐│0││ │ │
│││┌───┬─┐│99││ ││ │ │
││││0 0│0││  ││ ││ │ │
│││└───┴─┘│  ││ ││ │ │
││└───────┴──┘│ ││ │ │
│└────────────┴─┘│ │ │
└────────────────┴─┴─┘

    tape←lft lft tape ⋄ disp tape       ⍝ move two cells left again to home.
┌───────┬──┬───────┐
│┌───┬─┐│99│┌─┬───┐│
││0 0│0││  ││0│0 0││
│└───┴─┘│  │└─┴───┘│
└───────┴──┴───────┘

Further,  to increment (decrement) the current cell, we need only add (subtract)
the triple 0 1 0.

    inc←+∘0 1 0                         ⍝ + increment current tape cell.
    dec←-∘0 1 0                         ⍝ - decrement current tape cell.

However, this operation takes significantly more time as the memory tape becomes
extended.  This  is  because the interpreter must add 0 to both (nested) ends of
the memory tape. It could be argued that the interpreter should special-case 0+⍵
as a no-op  but it would probably still need to traverse a nested array so that,
for example, 0+((((5)4)3)2)1(2(3(4(5'?'))))  would continue to generate a DOMAIN
ERROR.

A less elegant but O(1) increment would be:

    inc←{l m r←⍵ ⋄ l(m+1)r}             ⍝ increment of current tape cell.

The only challenging part of the code is in inner operator [skip], which search-
es the token stream, left or right,  to find a matching bracket for [ or ].  The
code is complicated by having to navigate nested pairs of brackets,  which means
that  inner matching [...] pairs must be skipped over during the search.  [skip]
achieves this with a signature double recursion, characteristic of bracket proc-
essing in list implementations.  See the line with the exdented comment:

    skip←{                                  ⍝ search ⍺⍺-wise for [] match in ⍵.
        fm to←{⍵,'[]'~⍵}get ⍵               ⍝ current and target brackets.
        ⍺⍺{                                 ⍝ ⍺⍺ is lft or rgt.
            tok←get ⍵                       ⍝ current token.
            tok≡to:⍵                        ⍝ found match: done.
            tok≡fm:∇ ⍺⍺ ∇ ⍺⍺ ⍵          ⍝ inner loop: skip over it.
            tok≡'∘':⍵                       ⍝ run off end: quit.
            ∇ ⍺⍺ ⍵                          ⍝ skip lft or rgt to next token.
        }⍺⍺ ⍵                               ⍝ skipping over starting bracket.
    }

(muse:

    In this code,  [skip],  bound to its operand function [rgt] or [lft], is al-
    ways applied by the conditional application operator if←{(⍺⍺⍣⍵)⍺}.

        ... ⍵ rgt skip if 0=get
        ... ⍵ lft skip if 0≠get

    If Dyalog were to implement →hyperators←,  then (skip if)  could be bound at
    definition time:

        skip_if←{                       ⍝ search ⍺⍺-wise for [] match in ⍵.
            fm to←{⍵,'[]'~⍵}get ⍵       ⍝ current and target brackets.
            ⍺⍺{                         ⍝ ⍺⍺ is lft or rgt.
                tok←get ⍵               ⍝ current token.
                tok≡to:⍵                ⍝ found match: done.
                tok≡fm:∇ ⍺⍺ ∇ ⍺⍺ ⍵      ⍝ inner loop: skip over it.
                tok≡'∘':⍵               ⍝ run off end: quit.
                ∇ ⍺⍺ ⍵                  ⍝ skip lft or rgt to next token.
            }⍺⍺ ⍵                       ⍝ skipping over starting bracket.
        }{(⍺⍺ ⍺⍺⍺⍣⍵)⍺}                  ⍝ conditional →hyperator←.
)

Refs:
[1] http://en.wikipedia.org/wiki/Brainfuck        Brainfuck full description.
[2] http://en.wikipedia.org/wiki/Turing_machine   Turing machine.
[3] http://esolangs.org/wiki/Brainfuck            More on brainfuck.
[4] http://www.iwriteiam.nl/Ha_bf_Turing.html     Bf is turing-complete.
[5] http://esolangs.org                           More esoteric languages.
[6] min.dws max.dws                               Home-brewed minimal languages.

Note,  when searching the Internet that, owing to its second  syllable's being a
taboo word in English,  "brainfuck"  is  often  written as brainf***, brainf*ck,
brainfsck, BF or even b****fuck!

The language was designed to be extremely simple to implement.  For  example, it
may be expressed in only:

- 21 lines of the minuscule functional language: max.dws/lib.bf
- 18 reduction rules in term-rewriting system: eval.dws/bfck

Thanks to Nicolas Delcros and Jason Rivers for sowing the seed.

Examples:

    bf'++++++++++[>+++++++>++<<-]>++.>+.+++++++..+++.<<++++.>+++++++++++++++.>.+++.------.--------.<<-.'
Hello World

⍝ The following program inputs two single-digit numbers and ouputs their sum:

    display add         ⍝ sum of two single digit numbers.
┌→────────────────────────────────────────────────┐
│ output sum of two ASCII digits                  │
│ "⍺" plus "⍵" → "⍺" ┼ "⍵" ─ "0" where "0" = 48   │
│                                                 │
│ ,                   0: 1st digit '0' plus ⍺     │
│ > +++++ + [         1:6 × loop:                 │
│     < ----- ---     0: sub 6×8: '0' plus ⍺ → ⍺  │
│     >-              1: decr loop counter        │
│ ]                   1:0                         │
│ ,                   1: 2nd digit '0' plus ⍵     │
│ <[                  0:⍺ × loop                  │
│     >+              1: incr ⍵                   │
│     <-              0: decr ⍺                   │
│ ]                   0:0                         │
│ >.                  0: output ⍺ plus '0' plus ⍵ │
└─────────────────────────────────────────────────┘

    bf add                  ⍝ input 3, 4; output 7.
3
4
7
    +5 8 bf '[>+<-]'        ⍝ simple in-memory adder  5 + 8 → 13.
0 13

    1e6 bf time '[-]'       ⍝ 1 million loops takes just over 2 minutes.
02:07.28

⍝ Code snippets may be concatenated into larger programs:

    din ← ',>++++++++[<------>-]<'      ⍝ single-digit input.
    dot ← '>++++++++[<++++++>-]<.'      ⍝ single-digit output.
    clr ← '[-]'                         ⍝ cell clear: m → 0
    ff  ← '[>]'                         ⍝ fast-forward over non-zero cells.
    adr ← '[->+<]'                      ⍝ add right: m n → 0 (m+n)
    adl ← '>[-<+>]<'                    ⍝ add left:  m n → (m+n) 0
    dup ← '[->+>+<<]'                   ⍝ replicate: m → 0 m m

    sum ← din,'>',din,'<',adr,'>',dot   ⍝ output sum of two input digits.

    bf sum                              ⍝ using "sum" from above.
4
5
9
    bf din,dup,'>',adr,'>',dot          ⍝ double of input digit.
4
8

⍝ This program, transliterated from Böhm's P" language, a precursor to BF,
⍝ returns the predecessor of a number represented in 2→adic← number system:
⍝ ⍬ 1 2 11 12 21 22 111 112 121 ...

    +1 1 2 bf'>[>]<[-[<[<]]-<]>+'   ⍝ (-∘1) 8 → 7
0 0 1 1 1 0

⍝ For a more substantial example, see: →bfack←

See also: mac bfack balm
See also: baby list time adic lisp joy
See also: min.dws max.dws eval.dws
See also: max.dws/lib.bf eval.dws/bfck

Back to: contents

Back to: Workspaces