2008-07-03 [長年日記]
λ. A brainf*ck interpreter in Erlang
HelloWorld を書いたので、次は brainf*ck のインタプリタでも。
-module(brainfuck). -export([brainfuck/1]). brainfuck(Src) -> Prog=parse(Src), seq(Prog, {[], [0]}). parse(X) -> {Y,_} = parse(X, []), Y. parse([], Acc) -> {lists:reverse(Acc), []}; parse([H|T], Acc) -> case H of $] -> {lists:reverse(Acc), T}; $> -> parse(T, ['>'|Acc]); $< -> parse(T, ['<'|Acc]); $+ -> parse(T, ['+'|Acc]); $- -> parse(T, ['-'|Acc]); $. -> parse(T, ['.'|Acc]); $, -> parse(T, [','|Acc]); $[ -> {Prog,X}=parse(T, []), parse(X,[{Prog}|Acc]); _ -> parse(T, Acc) end. seq(Prog, T) -> lists:foldl(fun (P,T1) -> step(P,T1) end, T, Prog). step('>', {L,[X|R]}) -> {[X|L], case R of [_|_] -> R; _ -> [0] end}; step('<', {[X|L],R}) -> {L, [X|R]}; step('+', {L,[X|R]}) -> {L, [ case X of 255 -> 0; _ -> X+1 end | R ]}; step('-', {L,[X|R]}) -> {L, [ case X of 0 -> 255; _ -> X-1 end | R ]}; step('.', {L,[X|R]}) -> io:put_chars([X]), {L, [X|R]}; step(',', {L,[_|R]}) -> [X] = io:get_chars("", 1), {L, [X|R]}; step({W}, T) -> while(W, T). while(_, {_,[0|_]}=T1) -> T1; while(W, T) -> while(W, seq(W, T)).
といっても、前にPrologで書いたもの を適当に翻訳しただけ。
Erlang shell から実行してみる。
% erl Eshell V5.6.3 (abort with ^G) 1> c(brainfuck). {ok,brainfuck} 2> brainfuck:brainfuck(" >+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++ ++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]> ++++++++[<++++>-]<+.[-]++++++++++."). Hello World! {[],[10,0]}