Created
June 19, 2012 06:10
-
-
Save jokea/2952550 to your computer and use it in GitHub Desktop.
Erlang programming ex3_8
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
| %%% 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