Skip to content

Instantly share code, notes, and snippets.

@padde

padde/brainfuck.ex

Created Nov 12, 2014
Embed
What would you like to do?
Brainfuck interpreter in Elixir
# Inspired by these blog posts:
# http://dev.mikamai.com/post/100075543414/elixir-as-a-parsing-tool-writing-a-brainfuck
# http://dev.mikamai.com/post/102283561929/elixir-as-a-parsing-tool-writing-a-brainfuck
defmodule Brainfuck do
@op_decv "-"
@op_incv "+"
@op_decp "<"
@op_incp ">"
@op_putc "."
@op_getc ","
@op_begl "["
@op_endl "]"
def run(source) do
run(source, [0], 0)
end
defp run(@op_decv <> rest, mem, addr) do
new_mem = List.update_at(mem, addr, &(&1-1))
run(rest, new_mem, addr)
end
defp run(@op_incv <> rest, mem, addr) do
new_mem = List.update_at(mem, addr, &(&1+1))
run(rest, new_mem, addr)
end
defp run(@op_decp <> rest, mem, 0) do
run(rest, [0 | mem], 0)
end
defp run(@op_decp <> rest, mem, addr) do
run(rest, mem, addr-1)
end
defp run(@op_incp <> rest, mem, addr) when addr == length(mem)-1 do
run(rest, mem ++ [0], addr+1)
end
defp run(@op_incp <> rest, mem, addr) do
run(rest, mem, addr+1)
end
defp run(@op_putc <> rest, mem, addr) do
IO.puts [Enum.at(mem, addr)]
run(rest, mem, addr)
end
defp run(@op_getc <> rest, mem, addr) do
val = case IO.getn("", 1) do
:eof -> 0
c -> hd(String.to_char_list(c))
end
new_mem = List.replace_at mem, addr, val
run(rest, new_mem, addr)
end
defp run(source = @op_begl <> _, mem, addr) do
{loop, rest} = extract_loop(source)
case Enum.at(mem, addr) do
0 ->
run(rest, mem, addr)
_ ->
{mem, addr} = run(loop, mem, addr)
run(source, mem, addr)
end
end
defp run(@op_endl <> _, _mem, _addr) do
raise "unmatched right bracket"
end
defp run(<<_>> <> rest, mem, addr) do
run(rest, mem, addr)
end
defp run("", mem, addr) do
{mem, addr}
end
defp extract_loop(source) do
extract_loop(source, 0, "")
end
defp extract_loop(@op_begl <> rest, 0, acc) do
extract_loop(rest, 1, acc)
end
defp extract_loop(@op_begl <> rest, depth, acc) do
extract_loop(rest, depth+1, acc <> @op_begl)
end
defp extract_loop(@op_endl <> rest, 1, acc) do
{acc, rest}
end
defp extract_loop(@op_endl <> rest, depth, acc) do
extract_loop(rest, depth-1, acc <> @op_endl)
end
defp extract_loop(<<char>> <> rest, depth, acc) do
extract_loop(rest, depth, acc <> <<char>>)
end
defp extract_loop(_source, _depth, _acc) do
raise "unmatched left bracket"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment