diff options
Diffstat (limited to 'calc')
-rw-r--r-- | calc/calc.erl | 164 | ||||
-rw-r--r-- | calc/remote.erl | 22 |
2 files changed, 186 insertions, 0 deletions
diff --git a/calc/calc.erl b/calc/calc.erl new file mode 100644 index 0000000..4869104 --- /dev/null +++ b/calc/calc.erl @@ -0,0 +1,164 @@ +-module(calc). +-export([eval/1]). + +%% num := [-] 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 +num(Input) -> + num(Input, []). + +num([Current|Input], Num) when ($0 =< Current) and ($9 >= Current) -> + num(Input, Num ++ [Current]); +num([Head|_], "-") -> + {error, {unexpected, list_to_atom([Head])}}; +num(Input, []) -> + {ok, {Input, []}}; +num(Input, Num) -> + {ok, {Input, list_to_integer(Num)}}. + +%% bracket := [-] ( '(' sum '}' | num ) +bracket([$-|Input]) -> + case bracket(Input) of + {ok, {Tail, []}} -> + {error, {expected_number, {before, Tail}}}; + {ok, {Tail, Result}} -> + {ok, {Tail, -1 * Result}}; + {error, Why} -> + {error, Why} + end; +bracket([$(|Input]) -> + case sum(Input) of + {ok, {Tail, Result}} -> + bracketCheck(Tail, Result); + {error, Why} -> + {error, Why} + end; +bracket(Input) -> + num(Input). + +bracketCheck([$)|Tail], Result) -> + {ok, {Tail, Result}}; +bracketCheck(_, _) -> + {error, missing_bracket}. + +%% factor := num [ ^ factor ] +factor(Input) -> + case bracket(Input) of + {ok, {Tail, Number2}} -> + factorExtended(Tail, Number2); + {error, Why} -> + {error, Why} + end. + +factor([Head|Input], Number1) -> + case bracket([Head|Input]) of + {ok, {Tail, Number2}} -> + Result = math:pow(Number1, Number2), + factorExtended(Tail, Result); + {error, Why} -> + {error, Why} + end; +factor([], _) -> + {error, unexpected_end_of_input}. + +factorExtended([$ |Tail], Result) -> + factorExtended(Tail, Result); +factorExtended([$^|Tail], Result) -> + factor(Tail, Result); +factorExtended(Tail, Result) -> + {ok, {Tail, Result}}. + +%% term := factor [ ( * | / ) term ] +term(Input) -> + case factor(Input) of + {ok, {Tail, Result}} -> + termExtended(Tail, Result); + {error, Why} -> + {error, Why} + end. + +term([Head|Input], Number1, Operator) -> + case factor([Head|Input]) of + {ok, {Tail, Number2}} -> + case calc(Number1, Operator, Number2) of + {ok, Result} -> + termExtended(Tail, Result); + {error, Why} -> + {error, Why} + end; + + {error, Why} -> + {error, Why} + end; +term([], _, _) -> + {error, unexpected_end_of_input}. + +termExtended([$ |Tail], Result) -> + termExtended(Tail, Result); +termExtended([$*|Tail], Result) -> + term(Tail, Result, $*); +termExtended([$/|Tail], Result) -> + term(Tail, Result, $/); +termExtended(Tail, Result) -> + {ok, {Tail, Result}}. + +%% sum := term [ ( + | - ) sum ] +sum([$+|Input]) -> + sum(Input); +sum(Input) -> + case term(Input) of + {ok, {Tail, Result}} -> + sumExtended(Tail, Result); + {error, Why} -> + {error, Why} + end. + +sum([Head|Input], Number1, Operator) -> + case term([Head|Input]) of + {ok, {Tail, Number2}} -> + case calc(Number1, Operator, Number2) of + {ok, Result} -> + sumExtended(Tail, Result); + {error, Why} -> + {error, Why} + end; + + {error, Why} -> + {error, Why} + end; +sum([], _, _) -> + {error, unexpected_end_of_input}. + +sumExtended([$ |Tail], Result) -> + sumExtended(Tail, Result); +sumExtended([$+|Tail], Result) -> + sum(Tail, Result, $+); +sumExtended([$-|Tail], Result) -> + sum(Tail, Result, $-); +sumExtended(Tail, Result) -> + {ok, {Tail, Result}}. + +%% helper function to do the calculations +calc(Number1, $+, Number2) -> + {ok, Number1 + Number2}; +calc(Number1, $-, Number2) -> + {ok, Number1 - Number2}; +calc(Number1, $*, Number2) -> + {ok, Number1 * Number2}; +calc(Number1, $/, Number2) when (Number2 /= 0) -> + {ok, Number1 / Number2}; +calc(_, $/, _) -> + {error, division_zero}; +calc(_,_,_) -> + {error, invalid_operator}. + +eval(Formular) -> + case sum([X || X <- Formular, X /= $ ]) of + {ok, {Tail, Result}} -> + evalCheck(Tail, Result); + {error, Why} -> + {error, Why} + end. + +evalCheck([], Result) -> + {ok, Result}; +evalCheck(Tail, _) -> + {error, {unexpected_garbage_at_end_of_input, Tail}}. diff --git a/calc/remote.erl b/calc/remote.erl new file mode 100644 index 0000000..793c27c --- /dev/null +++ b/calc/remote.erl @@ -0,0 +1,22 @@ +-module(remote). +-export([start/0, calculate/1]). + +rpc(C) -> + rechner ! {self(), C}, + receive + {rechner, Reply} -> + Reply + end. + +loop() -> + receive + {From, {calculate, String}} -> + From ! {rechner, calc:eval(String)}, + loop() + end. + +start() -> + register(rechner, spawn(fun() -> loop() end)). + +calculate(String) -> + rpc({calculate, String}). |