Brainfuck is an esoteric language that consists of only eight simple commands:
>
increment the data pointer (to point to the next cell to the right).<
decrement the data pointer (to point to the next cell to the left).+
increment (increase by one) the byte at the data pointer.-
decrement (decrease by one) the byte at the data pointer..
output the byte at the data pointer.,
accept one byte of input, storing its value in the byte at the data pointer.[
if the byte at the data pointer is zero, then instead of moving the instruction pointer forward to the next command, jump it forward to the command after the matching ] command.]
if the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward to the next command, jump it back to the command after the matching [ commandBrainfuck is a simple language, but that does not mean that programming Brainfuck is easy!
In [ ]:
import wasmfun as wf
In [ ]:
def _commands2instructions(commands):
""" Compile brainfuck commands to WASM instructions (as tuples).
"""
instructions = []
while commands:
c = commands.pop(0)
if c == '>':
instructions += [('get_local', 0), ('i32.const', 1), ('i32.add'), ('set_local', 0)]
elif c == '<':
instructions += [('get_local', 0), ('i32.const', 1), ('i32.sub'), ('set_local', 0)]
elif c == '+':
instructions += [('get_local', 0), ('get_local', 0), # once for the read, once for the write
('i32.load8_u', 0, 0),
('i32.const', 1), ('i32.add'), ('i32.store8', 0, 0)]
elif c == '-':
instructions += [('get_local', 0), ('get_local', 0), # once for the read, once for the write
('i32.load8_u', 0, 0),
('i32.const', 1), ('i32.sub'), ('i32.store8', 0, 0)]
elif c == '.':
instructions += [('get_local', 0), ('i32.load8_u', 0, 0), ('call', 0)]
elif c == ',':
# We don't support input, just set to zero
instructions += [('get_local', 0), ('i32.const', 0), ('i32.store8', 0, 0)]
elif c == '[':
instructions += [('block', 'emptyblock'),
# if current data point == 0 goto end of block
('get_local', 0), ('i32.load8_u', 0, 0), ('i32.const', 0), ('i32.eq'), ('br_if', 0),
('loop', 'emptyblock'),
] + _commands2instructions(commands ) + [
# if current data point > 0 goto start of block
('get_local', 0), ('i32.load8_u', 0, 0), ('i32.const', 0), ('i32.ne'), ('br_if', 0),
('end'),
('end')]
elif c == ']':
break
else:
raise ValueError('Unknown Brainfuck command: %r' % c)
return instructions
In [ ]:
EXAMPLE1 = """
[This program prints "Hello World!" and a newline to the screen]
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.
>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
"""
In [ ]:
instructions = _commands2instructions([c for c in EXAMPLE1 if c in '><+-.,[]'])
In [ ]:
m = wf.Module(
wf.ImportedFuncion('print_charcode', ['i32'], [], 'js', 'print_charcode'),
wf.Function('$main', [], [], ['i32'], instructions),
wf.MemorySection((1, 1)),
wf.DataSection(),
)
In [ ]:
len(m.to_bytes())
In [ ]:
wf.run_wasm_in_notebook(m)
In [ ]:
EXAMPLE2 = """
[Generate the fibonacci number sequence, (for numbers under 100). Taken from
http://esoteric.sange.fi/brainfuck/bf-source/prog/fibonacci.txt
]
+++++++++++>+>>>>++++++++++++++++++++++++++++++++++++++++++++>
++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>+<<<<<<<-]>>>>>>>
[<<<<<<<+>>>>>>>-]<[>++++++++++[-<-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]
<[-]]>[<<[>>>+<<<-]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>
[<<+>>[-]]<<<<<<<]>>>>>[++++++++++++++++++++++++++++++++++++++++++++++++.
[-]]++++++++++<[->-<]>++++++++++++++++++++++++++++++++++++++++++++++++.[-]
<<<<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<[-]]<<[>>+>+<<<-]>>>
[<<<+>>>-]<<[<+>-]>[<+>-]<<<-]
"""
In [ ]:
instructions = _commands2instructions([c for c in EXAMPLE2 if c in '><+-.,[]'])
In [ ]:
m = wf.Module(
wf.ImportedFuncion('print_charcode', ['i32'], [], 'js', 'print_charcode'),
wf.Function('$main', [], [], ['i32'], instructions),
wf.MemorySection((1, 1)),
wf.DataSection(),
)
In [ ]:
wf.run_wasm_in_notebook(m)
In [ ]:
wf.run_wasm_in_node(m)
In [ ]: