Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
defmodule Brainfuck do
# opcodes
@op_vinc "+" # increment value at memory address
@op_vdec "-" # decrement value at memory address
@op_pinc ">" # increment memory address
@op_pdec "<" # decrement memory address
@op_putc "." # output byte at memory address
@op_getc "," # input byte into memory address
@op_lbeg "[" # loop begin
@op_lend "]" # loop end
@empty ""
def run(program), do: run(program, 0, [0], @empty)
# final condition
defp run(@empty, addr, mem, output), do: {addr, mem, output}
# commands
defp run(@op_vinc <> rest, addr, mem, output) do
run(rest, addr, mem |> inc_at(addr), output)
end
defp run(@op_vdec <> rest, addr, mem, output) do
run(rest, addr, mem |> dec_at(addr), output)
end
defp run(@op_pinc <> rest, addr, mem, output) do
run(rest, addr+1, mem, output)
end
defp run(@op_pdec <> rest, addr, mem, output) do
run(rest, addr-1, mem, output)
end
defp run(@op_putc <> rest, addr, mem, output) do
run(rest, addr, mem, output <> (mem |> char_at addr))
end
defp run(@op_getc <> rest, addr, mem, output) do
val = case IO.getn("Input\n", 1) do
:eof -> 0
c -> c
end
run(rest, addr, mem |> put_at(addr, val), output)
end
# drop every other character
defp run(<<_>> <> rest, addr, mem, output), do: run(rest, addr, mem, output)
# helpers
defp inc_at(list, addr), do: List.update_at(list, addr, &(&1+1 |> rem 255))
defp dec_at(list, addr), do: List.update_at(list, addr, &(&1-1 |> rem 255))
defp put_at(list, addr, val), do: List.replace_at(list, addr, val)
defp byte_at(list, addr), do: list |> Enum.at addr
defp char_at(list, addr), do: [list |> byte_at addr] |> to_string
end
@mtwtkman

This comment has been minimized.

Copy link

commented Oct 17, 2014

Hi, I read your very cool post!

So, I guess when pointer increment operator given and address is end of list, mem should be added new element.
(For example, line 28 would be like below?)

defp run(@op_pinc <> rest, addr, mem, output) do
    if length(mem) == addr+1 do
        mem = mem ++ [0]
    end
    run(rest, addr+1, mem, output)
end

Very sorry for you, If I get wrong...
And sorry for my very poor English... ;-)

What is anyway, I'm looking forward to post your cool Elixir Brainfuck part2.

@wstucco

This comment has been minimized.

Copy link
Owner Author

commented Nov 5, 2014

First of all, thanks!
I was going to explain the auto expanding memory in the second part, but you guessed right.
I have only one advice: you're still thinking imperative, you don't need the if in Elixir, you can take advantage of guard clauses and basically add this two functions, this way you are modular and add the features you need, without modifying code that already works (I'll talk about testing Elixir code and the command line tools in part 3)

# we are moving past the end of the memory tape
defp run(@op_pinc <> rest, addr, mem, output) when addr + 1 == mem |> length do
  # append a new cell, initialize its value to zero, return the next address as new address
  run(rest, addr+1, mem ++ [0], output)
end

# we are moving to the left of the first cell of the memory tape
defp run(@op_pdec <> rest, addr, mem, output) when addr == 0 do
    # prepend a new empty cell, initialize its value to zero, return zero as new address
  run(rest, 0, [0] ++ mem, output)
end

I'm very glad you liked the first part, the second will be even more fun! :)

@mtwtkman

This comment has been minimized.

Copy link

commented Nov 11, 2014

Thanks for your reply!
And i'm glad to read next part this topic :)

I can feel that pattern matching and guard clauses are really elegant, beautiful.

@wstucco

This comment has been minimized.

Copy link
Owner Author

commented Nov 11, 2014

Thanks to you!
the second part is out, you can read it at http://dev.mikamai.com/post/102283561929/elixir-as-a-parsing-tool-writing-a-brainfuck

@ylluminate

This comment has been minimized.

Copy link

commented Jan 26, 2016

@wstucco you might consider adding elixir benchmarks to: https://github.com/kostya/benchmarks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.