Rainbow Brainfuck Cheatsheet


jump to live interpreter

Command
R, O, Y, G, B, V, P, C, W, or K Change character color (FG) to red, orange, yellow, green, blue, violet, pink, cyan, brown or black, unless preceded by @ or * (see below)
r, o, y, g, b, v, p, c, w, or k Change background color (BG) to red, orange, yellow, green, blue, violet, pink, cyan, brown or black, unless preceded by @ or * (see below)
+ load value at FG cell, increment by one, and store at BG cell
- load value at FG cell, decrement by one, and store at BG cell
< load pointer position of FG, set BG pointer position one cell to its left
> load pointer position of FG, set BG pointer position one cell to its right
[ if value at FG cell is zero, jump forward to command after ] with matching BG color
] if value at FG cell is not zero, jump to back to command after [ with maching BG color
@ followed by a letter in the Latin alphabet, e.g. @a Define or call a function. See notes below for explanations of how functions behave in rainbow brainfuck.
# Mark the end of a function definition. If encountered outside of a function definition it is ignored.
* followed by a lowercase letter, e.g. *a Store function with name equal to lowercase letter in BG. If the function was not defined yet, define it. See below for detailed explanation
@* Call a function previously stored in FG. Noop if no function was stored.
a Add FG to BG with carry. Store result in BG, set carry flag if integer overflow, otherwise unset it
s Sub FG from BG with carry. Store result in BG, set carry flag if integer underflow, otherwise unset it
m Multiply FG by BG. Store high product in FG, low product in BG. Reset carry flag
d Divide FG by BG. Store modulus in FG, division in BG. Reset carry flag
! invert the bits of FG, store the result in BG
| OR the bits of FG and BG, store the result in BG. Reset carry flag
& AND the bits of FG and BG, store the result in BG. Reset carry flag
^ XOR the bits of FG and BG, store the result in BG. Reset carry flag
{ Shift all bits in FG one to the left, inserting carry to LSB, and the value of the MSB that was shifted out to carry. Store result in BG
} Shift all bits in FG one to the right, inserting carry to MSB, and the value of the LSB that was shifted out to carry. Store result in BG

Functions

Functions are lexically scoped and defined in-line by @ followed by any lowercase letter. Function definitions encountered at run-time are run as if their code body was part of their enclosing function - e.g. +++[-]++ and ++@a+[#-]++ behave identically, except that the letter also defines a function a with code body +[ which is never called.

Because we only have the Latin alphabet available, there can only be 26 top-level functions. To mitigate this, functions define their own function definition scope. For example:

[-]@a@b+++#@b@b@b@b#@a@a@a@a@b.#

Here, we have two top-level functions: a and b. a has a function b defined inside of it, different from the top-level b. Displayed as a tree the function scopes would look like this

▒─┬─a──b
  └─b

Note that any path down this tree is guaranteed to produce a unique string of letters! Let's use that string as a shorthand from now on. So here, the two b functions will be distinguished as b for the top-level, and ab for the one defined inside a.

Let's walk through the code example. [-] is the standard set-cell-to-zero trick. @a defines a. In its code body we first see @b, which defines ab, which has code body +++. Then a calls ab four more times.Therefore a increments by a total of 15. After being defined, a is called four more times, for a total increment of 75. Then we see another @b, which defines the top-level b. It has code body ., which prints the current cell value to output. When encountered, the cell value is 75. This is the letter "K" in ASCII and unicode, so this code prints the letter "K".

It is possible to call a function in a higher or a different scope in two ways.

Calling a function in a higher scope

The first way to call function in a different scope is using @ followed by an uppercase letter. In that case, we call the first function encountered in an enclosing scope with the same lowercase letter:

[-][@b+++#]@a#@B@B@B@B@B#@a@a@a@a.

This example, like the previous one, prints the letter K, except in an even more convoluted way. First it sets the current cell to zero, then it jumps over b, although the latter is still defined since function definitions are lexically scoped. Then a is defined and run. It calls b five times using @B, for a total increment of 15. Then it is called four more times, incrementing the cell to 75, and finally we print "K" again.

Note that functions can call themselves recursively, although care has to be taken to avoid infinite loops:

@a-[@A]#

As long as the current cell is non-zero, the above function a calls itself, meaning it is equivalent to [-], except with added call overhead (unless the implementation supports some kind of tail-call optimizations).

To demonstrate this, we can make the print-"K" example even more convoluted:

[-][
 @b+++#
 @a[>@B<-@A]#
 @c[>@D@A<-@C]#
]
@d+++++# @c .

Storing functions, and calling stored functions

The second option is to store a function in a color slot, and later call it. To store a function, write * followed by a lowercase letter, e.g. *a. This stores the function that is named in BG. To call a stored function, write @*, which will run whichever function is stored in FG. If no function has been stored yet, @* does nothing.

If a function is not defined yet when attempting to store it, * also defines it as if it was an @ symbol. Like with @ this function definition is lexically scoped), if a was previusly undefined, a top-level @a+++# or *a+++# would be almost equivalent, except that the latter also would store a in BG.

Try it yourself!

Note: functions are not yet implemented, and there may be other bugs.