Created
November 12, 2014 07:47
-
-
Save padde/e133e8ee6d0f314b0fd3 to your computer and use it in GitHub Desktop.
Brainfuck interpreter in Elixir
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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