aboutsummaryrefslogblamecommitdiffstats
path: root/calc/calc.erl
blob: 48691049fe1873e4771ef3024f547c6e8f037b56 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
              
                  
 


                                                   
 



                                                                     

                      





                                        

                                                       













                                       
 























                                                
 

                                    


                                    

































































































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