Skip to content

Instantly share code, notes, and snippets.

@ggb
Created November 29, 2014 15:27
Show Gist options
  • Save ggb/d830418c739dac7ec983 to your computer and use it in GitHub Desktop.
Save ggb/d830418c739dac7ec983 to your computer and use it in GitHub Desktop.
Just another brainfuck interpreter...
defmodule Brainfuck do
@moduledoc """
Brainfuck, s. http://en.wikipedia.org/wiki/Brainfuck
"""
@register_size 100
# Function to find the next corresponding closing bracket
defp find_closing_bracket([ 91 | rest ], pos, closing) do
find_closing_bracket(rest, pos + 1, closing + 1)
end
defp find_closing_bracket([ 93 | _rest ], pos, closing) when closing == 0 do
pos + 1
end
defp find_closing_bracket([ 93 | rest ], pos, closing) do
find_closing_bracket(rest, pos + 1, closing - 1)
end
defp find_closing_bracket([ _ | rest ], pos, closing) do
find_closing_bracket(rest, pos + 1, closing)
end
# ''
def handle_command([ ], _reg, _current, _loop), do: :ok
# '<'
def handle_command([ 62 | rest ], register, current_pointer_pos, loop_memo) do
handle_command(rest, register, current_pointer_pos + 1, loop_memo)
end
# '<'
def handle_command([ 60 | rest ], register, current_pointer_pos, loop_memo) do
handle_command(rest, register, current_pointer_pos - 1, loop_memo)
end
# '+'
def handle_command([ 43 | rest ], register, current_pointer_pos, loop_memo) do
# IO.puts Dict.get(register, current_pointer_pos)
handle_command(rest, Dict.update!(register, current_pointer_pos, fn val -> val + 1 end), current_pointer_pos, loop_memo)
end
# '-'
def handle_command([ 45 | rest ], register, current_pointer_pos, loop_memo) do
# IO.puts Dict.get(register, current_pointer_pos)
handle_command(rest, Dict.update!(register, current_pointer_pos, fn val -> val - 1 end), current_pointer_pos, loop_memo)
end
# '.'
def handle_command([ 46 | rest ], register, current_pointer_pos, loop_memo) do
[ Dict.get(register, current_pointer_pos) | [] ] |> to_string |> IO.write
handle_command(rest, register, current_pointer_pos, loop_memo)
end
# ','
def handle_command([ 44 | rest ], register, current_pointer_pos, loop_memo) do
new_val = IO.read(:line) |> String.to_char_list |> Enum.take(1)
handle_command(rest, Dict.update!(register, current_pointer_pos, fn _val -> new_val end), current_pointer_pos, loop_memo)
end
# '['
def handle_command([ 91 | rest ], register, current_pointer_pos, loop_memo) do
closing_bracket_pos = find_closing_bracket(rest, 0, 0)
if(Dict.get(register, current_pointer_pos) == 0) do
handle_command(Enum.drop(rest, closing_bracket_pos), register, current_pointer_pos, Enum.drop(loop_memo, 1))
else
handle_command(rest, register, current_pointer_pos, [ [ 91 | Enum.take(rest, closing_bracket_pos) ] | loop_memo ])
end
end
# ']'
def handle_command([ 93 | rest ], register, current_pointer_pos, loop_memo = [ loop_head | _loop_rest]) do
handle_command( loop_head ++ rest , register, current_pointer_pos, loop_memo)
end
# ...any other character
def handle_command([ _ | rest ], register, current_pointer_pos, loop_memo) do
handle_command(rest, register, current_pointer_pos, loop_memo)
end
@doc """
Transforms the input binary to char_list and calls run, e. g.:
iex> File.read!("example.brainfuck") |> Brainfuck.run
"""
def run(programm) when is_binary(programm) do
programm |> String.to_char_list |> run
end
@doc """
Interprets a brainfuck program. Takes the program as char list as only input charakter.
iex> Brainfuck.run(',[.,]')
"""
def run(programm) do
register = Enum.map(1..@register_size, fn ele -> { ele, 0 } end) |> Enum.into(HashDict.new)
handle_command(programm, register, div(Enum.count(register), 2), [])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment