-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}}.