Created
February 15, 2014 18:45
-
-
Save ferd/9023419 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| -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