Skip to content

Instantly share code, notes, and snippets.

@jokea
Created June 19, 2012 06:10
Show Gist options
  • Save jokea/2952550 to your computer and use it in GitHub Desktop.
Save jokea/2952550 to your computer and use it in GitHub Desktop.
Erlang programming ex3_8
%%% restrict: can only handle numbers from 0~9
-module(ec).
-export([parser/1, eval/1, print/1, compile/1, simulate/1, simplify/1]).
parser(List) -> do_parse(List, [], []).
do_parse([], _, [Output]) -> Output;
do_parse(List, Stack, Output) ->
Last = lists:last(List),
Len = length(List),
Sublist = lists:sublist(List, Len-1),
case [Last] of
")" -> do_parse(Sublist, lists:append(Stack, [Last]), Output);
"(" ->
{NewStack, NewOutput} = unwind_stack(Stack, Output),
do_parse(Sublist, NewStack, NewOutput);
"+" -> do_parse(Sublist, lists:append(Stack, [plus]), Output);
"-" -> do_parse(Sublist, lists:append(Stack, [minus]), Output);
"*" -> do_parse(Sublist, lists:append(Stack, [multi]), Output);
"/" -> do_parse(Sublist, lists:append(Stack, [divide]), Output);
"~" -> {negtive, lists:last(Output)};
_ -> do_parse(Sublist, Stack, lists:append(Output, [{num, Last-48}]))
end.
unwind_stack([], Output) -> {[], Output};
unwind_stack(Stack, Output) ->
Last = lists:last(Stack),
Len = length(Stack),
Sublist = lists:sublist(Stack, Len-1),
case [Last] of
")" -> {Sublist, Output};
_ ->
First = lists:last(Output),
Second = lists:nth(length(Output)-1, Output),
if
length(Output) == 2 -> NewOutput = [];
true -> NewOutput = lists:sublist(Output, length(Output)-2)
end,
unwind_stack(Sublist, lists:append(NewOutput, [{Last, First, Second}]))
end.
%%% evaluator
eval(Exp) -> do_eval(Exp, 0).
do_eval({}, Result) -> Result;
do_eval({num, K}, _) -> K;
do_eval({plus, A, B}, Result) -> Result + do_eval(A, 0) + do_eval(B, 0);
do_eval({minus, A, B}, Result) -> Result + do_eval(A, 0) - do_eval(B, 0);
do_eval({multi, A, B}, Result) -> Result + do_eval(A, 0) * do_eval(B, 0);
do_eval({divide, A, B}, Result) -> Result + do_eval(A, 0) / do_eval(B, 0);
do_eval({negtive, A}, Result) -> Result - do_eval(A, 0).
%%% pretty printer
print(Exp) -> do_print(Exp), io:format("~n", []).
do_print({num, K}) -> io:format("~p", [K]);
do_print({plus, A, B}) -> io:format("(", []), do_print(A), io:format("+", []), do_print(B), io:format(")", []);
do_print({minus, A, B}) -> io:format("(", []), do_print(A), io:format("-", []), do_print(B), io:format(")", []);
do_print({multi, A, B}) -> io:format("(", []), do_print(A), io:format("*", []), do_print(B), io:format(")", []);
do_print({divide, A, B}) -> io:format("(", []), do_print(A), io:format("/", []), do_print(B), io:format(")", []);
do_print({negtive, A}) -> io:format("~~", []), do_print(A).
%%% compiler
compile(Exp) -> do_compile(Exp, []).
do_compile({}, [Result]) -> Result;
do_compile({num, K}, _) -> [K];
% convert negtive to multiply of (-1*K)
do_compile({negtive, K}, R) -> do_compile({multi, {num, -1}, K}, R);
do_compile({Op, A, B}, Result) ->
Ra = do_compile(A, []),
Rb = do_compile(B, []),
R1 = lists:append(Result, [Op]),
R2 = lists:append(R1, Ra),
lists:append(R2, Rb).
%%% simulator
simulate(Exp) -> do_sim(lists:reverse(Exp)).
do_sim([]) -> 0;
do_sim([Result]) -> Result;
do_sim([K, negtive]) -> -1*K;
do_sim(List) ->
Len = length(List),
Head = lists:sublist(List, 3),
Next = lists:sublist(List, 4, Len-3),
XX = lists:nth(3, Head),
if
is_integer(XX) ->
First = lists:nth(1, Head),
NewHead = lists:sublist(List, 2, 3),
Rest = lists:sublist(List, 5, Len-4),
V = calc(NewHead),
do_sim(lists:append([First, V], Rest));
is_atom(XX) ->
V = calc(Head),
do_sim([V | Next])
end.
calc([Second, First, plus]) -> First + Second;
calc([Second, First, minus]) -> First - Second;
calc([Second, First, multi]) -> First * Second;
calc([Second, First, divide]) -> First / Second.
%%% simplifier
simplify({}) -> {};
simplify({num, K}) -> {num, K};
simplify({plus, {num, 0}, {num, K}}) -> {num, K};
simplify({plus, {num, K}, {num, 0}}) -> {num, K};
simplify({minus, {num, K}, {num, 0}}) -> {num, K};
simplify({minus, {num, 0}, {num, K}}) -> {num, -1*K};
simplify({multi, {num, 0}, _}) -> {num, 0};
simplify({multi, _, {num, 0}}) -> {num, 0};
simplify({multi, {num, 1}, K}) -> K;
simplify({multi, K, {num, 1}}) -> K;
simplify({divide, {num, 0}, _}) -> {num, 0};
simplify({divide, K, {num, 1}}) -> K;
simplify({Op, {num, A}, {num, B}}) -> {Op, {num, A}, {num, B}};
simplify({Op, {num, A}, B}) -> {Op, {num, A}, simplify(B)};
simplify({Op, A, {num, B}}) -> {Op, simplify(A), {num, B}};
simplify({Op, A, B}) -> simplify({Op, simplify(A), simplify(B)}).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment