Skip to content

Instantly share code, notes, and snippets.

@ferd
Created February 15, 2014 18:45
Show Gist options
  • Select an option

  • Save ferd/9023419 to your computer and use it in GitHub Desktop.

Select an option

Save ferd/9023419 to your computer and use it in GitHub Desktop.
-module(brainfuck).
-export([main/1,run/1]).
-define(Tape, <<0:30000/unit:8>>).
-define(DATA_POINTER, 0).
%% >: data ptr +1
%% <: data ptr -1
%% +: byte+1 at data ptr
%% -: byte-1 at data ptr
%% .: output byte at data ptr
%% ,: store 1 byte of input at data ptr
%% [: if byte at data ptr = 0, jump to command after ]
%% ]: if byte at data ptr != 0, jump back to command after [
%% running from the command-line
main([Program]) -> run(Program), halt().
%% running from the erlang shell
run(Instructions) when is_list(Instructions) ->
run(list_to_binary(Instructions));
run(Instructions) when is_binary(Instructions) ->
run(Instructions, ?DATA_POINTER, ?Tape),
io:format("~n").
%% Ins = instructions,
%% DataPtr = Previous index,
%% Tape = Data
run(<< $>, Ins/binary>>, DataPtr, Tape) ->
run(Ins, DataPtr+1, Tape);
run(<< $<, Ins/binary>>, DataPtr, Tape) ->
run(Ins, DataPtr-1, Tape);
run(<< $+, Ins/binary>>, DataPtr, Tape) ->
<<Prev:(DataPtr)/binary, X/integer, Next/binary>> = Tape,
run(Ins, DataPtr, <<Prev/binary, (X+1)/integer, Next/binary>>);
run(<< $-, Ins/binary>>, DataPtr, Tape) ->
<<Prev:(DataPtr)/binary, X/integer, Next/binary>> = Tape,
run(Ins, DataPtr, <<Prev/binary, (X-1)/integer, Next/binary>>);
run(<< $., Ins/binary>>, DataPtr, Tape) ->
<<_:(DataPtr)/binary, X/integer, _/binary>> = Tape,
io:put_chars([X]),
run(Ins, DataPtr, Tape);
run(<< $,, Ins/binary>>, DataPtr, Tape) ->
<<Prev:(DataPtr)/binary, _/integer, Next/binary>> = Tape,
[X] = io:get_chars("",1),
run(Ins, DataPtr, <<Prev/binary, X/integer, Next/binary>>);
run(<< $[, Ins/binary>>, DataPtr, Tape) ->
End = find_end(Ins),
<<Loop:End/binary, PostLoop/binary>> = Ins,
<<_:(DataPtr)/binary, X/integer, _/binary>> = Tape,
if X =:= 0 ->
run(PostLoop, DataPtr, Tape);
X =/= 0 ->
{NewPtr, NewTape} = run(Loop, DataPtr, Tape),
run(<<$[,Loop/binary,$],PostLoop/binary>>, NewPtr, NewTape)
end;
run(<<_, Ins/binary>>, DataPtr, Tape) ->
run(Ins, DataPtr, Tape);
run(<<>>, DataPtr, Tape) -> {DataPtr, Tape}.
%% finds the point where a loop ends.
find_end(Ins) ->
find_end(Ins, 0, 0).
find_end(<< $], _/binary>>, 0, Pos) ->
Pos+1;
find_end(<< $], Ins/binary>>, N, Pos) ->
find_end(Ins, N-1, Pos+1);
find_end(<< $[, Ins/binary>>, N, Pos) ->
find_end(Ins, N+1, Pos+1);
find_end(<<_, Ins/binary>>, N, Pos) ->
find_end(Ins, N, Pos+1).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment