An optimizing compiler / interpreter for Brainfuck, written in Elixir.
I love compilers and Elixir, but I didn’t want to write a huge parser or tokenizer and die from boredom. Brainfuck is small, simple, and lets me focus entirely on optimizations.
brainstorm is fully capable of interpreting Brainfuck code, as well as producing optimized C programs.
cat bf_snippets/hello.bf
# >+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.>>>++++++++[<++++>-]<.>>>++++++++++[<+++++++++>-]<---.<<<<.+++.------.--------.>>+.>++++++++++../bs bf_snippets/hello.bf
# Output: Hello World!./bs bf_snippets/hello.bf --mode cNow we have hello.c:
#include <stdio.h>
int main(void) {
fputs("Hello World!\n", stdout);
return 0;
}You can then compile and run the generated C code:
gcc -o hello hello.c
./hello
# Output: Hello World!brainstorm supports a wide range of common Brainfuck optimizations, including nearly all of the techniques described in the notable article brainfuck optimization strategies.
-
Combine sequential increments/decrements
+++--becomes+. -
Combine sequential shifts
>>>><<becomes>>. -
Remove dead loops at the start of the program
[+->><.>]++becomes++. -
Remove redundant sequential loops
[>][<]becomes[>]. -
Remove dead code at the end
+++++.>>><-becomes+++++.
Current limitation: dead loops are not automatically removed. -
Combine increments and shifts into single instructions
Optimizes patterns like+>+>into fewer operations. -
Detect and replace "multiplication loops"
Loops that copy or scale values are replaced with direct arithmetic:>+++++++++[<++++++++>-].
becomes
arr[i + 1] = 9; i += 1; arr[i - 1] += arr[i] * 8; arr[i] = 0;
-
Compile-time execution
brainstormtries to execute code at compile-time as much as possible. To prevent an infinite time of compilation due to an unexpected infinite loop,brainstormsupports specifying steps limit - how many commands are allowed to be executed at compile-time. It defaults to8192and can be changed via--max-stepsCLI argument. If you are risky enough, you can specify--max-steps infinityand wait as long as you want.
You can control which optimizations are applied using the opt_level argument:
0- No optimizations (original commands are returned as-is)1- Basic peephole optimizations2- Full optimizations (:o1plus removing trivial loops at start/end, fusing instructions, and unwrapping multiplication loops)
# Compile-time "Hello World!"
./bs ./bf_snippets/hello.bf --mode c
# Compile-time calculating squares or numbers from 1 to 1000
./bs ./bf_snippets/squares.bf --mode c --max-steps 1000000
# Run-time "Just another brainfuck hacker,"
./bs ./bf_snippets/jabh.bf
# A ghost game
./bs ./bf_snippets/ghost.bf --mode cgit clone https://github.com/samedit66/brainstorm.git
cd brainstorm
mix escript.build
./bs./bs <file.bf> [--opt-level 0|1|2] [--outdir <dir>] [--mode i|c] [--max-steps <number>|infinity]Options:
--opt-level(-O,-o) - Set optimization level (0,1, or2, default2)--outdir- Directory to write the generated C file (default: current directory)--mode- Execution mode (i- interpretation orc- compilation, defaulti)--max-steps- Maximum execution steps (any positive number orinfinity, default8192)