Skip to content

Commit

Permalink
reverse_polish_notation_evaluator complete
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexanderSLoburev committed Jan 3, 2024
1 parent e0a7941 commit 4d7a881
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 19 deletions.
4 changes: 2 additions & 2 deletions common/stack.erl
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ new() -> [].
push(Item, Stack) -> [Item | Stack].


pop([]) -> throw({error, empty});
pop([]) -> throw({error, "Attempting to pop an element from an empty stack."});

pop([_Head | Tail]) -> Tail.


peek([]) -> throw({error, empty});
peek([]) -> throw({error, "Attempting to peek an element from an empty stack."});

peek([Head | _Tail]) -> Head.

Expand Down
6 changes: 3 additions & 3 deletions common/utils.erl
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
-module(utils).
-export([try_parse_number/1, is_digit/1, re_escape/1]).


try_parse_number(String) ->
case io_lib:fread("~d", String) of
{ok, Value} -> Value;
error -> String
{ok, [Value], _} -> Value;
{error, _} -> String
end.


is_digit(Char) -> lists:member(Char, lists:seq($0, $9)).

re_escape(String) ->
io:fwrite("Token:~p, is binary: ~p~n", [String, is_binary(String)]),
Escaped = re:replace(String, "[\\[\\]\\\\^$.|?*+()]", "\\\\&", [global]),
Escaped.
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,76 @@
-export([start/0]).


handle_token(Token, Stack, Position) ->
handle_token({Token, Position}, Stack) ->
io:fwrite("Token ~p in position ~w~n", [Token, Position]),
io:fwrite("Stack: ~p~n", [Stack]),
case utils:try_parse_number(Token) of
Value when is_number(Value) -> stack:push(Value, Stack);
Value when is_number(Value) ->
io:fwrite("Pushing ~p into stack~n", [Value]),
stack:push(Value, Stack);
_ ->
Right = stack:peek(Stack),
io:fwrite("Poping ~p from stack~n", [Right]),
StackAfterFirstPop = stack:pop(Stack),
Left = stack:peek(StackAfterFirstPop),
io:fwrite("Poping ~p from stack~n", [Left]),
StackAfterSecondPop = stack:pop(StackAfterFirstPop),
case Token of
"+" -> stack:push(Left + Right, StackAfterSecondPop);
"-" -> stack:push(Left - Right, StackAfterSecondPop);
"*" -> stack:push(Left * Right, StackAfterSecondPop);
"/" -> stack:push(Left / Right, StackAfterSecondPop);
"//" ->
"+" ->
io:fwrite("Pushing ~p into stack~n", [Left + Right]),
stack:push(Left + Right, StackAfterSecondPop);
"-" ->
io:fwrite("Pushing ~p into stack~n", [Left - Right]),
stack:push(Left - Right, StackAfterSecondPop);
"*" ->
io:fwrite("Pushing ~p into stack~n", [Left * Right]),
stack:push(Left * Right, StackAfterSecondPop);
"/" ->
io:fwrite("Pushing ~p into stack~n", [Left / Right]),
stack:push(Left / Right, StackAfterSecondPop);
"//" ->
case is_integer(Left) and is_integer(Right) of
true -> stack:push(Left div Right, StackAfterSecondPop);
true ->
io:fwrite("Pushing ~p into stack~n", [Left div Right]),
stack:push(Left div Right, StackAfterSecondPop);
false -> throw({error, io_lib:format("Error at position ~w: both operands must be integers.", [Position])})
end;
"%" ->
case is_integer(Left) and is_integer(Right) of
true -> stack:push(Left rem Right, StackAfterSecondPop);
true ->
io:fwrite("Pushing ~p into stack~n", [Left rem Right]),
stack:push(Left rem Right, StackAfterSecondPop);
false -> throw({error, io_lib:format("Error at position ~w: both operands must be integers.", [Position])})
end;
"**" -> stack:push(math:pow(Left, Right), StackAfterSecondPop)
"**" ->
io:fwrite("Pushing ~p into stack~n", [math:pow(Left, Right)]),
stack:push(math:pow(Left, Right), StackAfterSecondPop)
end
end.


tokenize(Expression) ->
Tokens = re:split(Expression, "\\s+"),
FilteredTokens = lists:filter(fun(X) -> (X =/= "") and not(lists:member(X, "\s\t\n")) end, Tokens),
StringTokens = lists:map(fun(Token) -> binary_to_list(Token) end, Tokens),
FilteredTokens = lists:filter(fun(X) -> (X =/= "") and not(lists:member(X, "\s\t\n")) end, StringTokens),
Positions = lists:flatmap(fun(Token) ->
case re:run(Expression, utils:re_escape(Token), [global]) of
nomatch -> [];
{match, Captured} -> lists:map(fun({Index, _Length}) -> {Token, Index + 1} end, lists:flatten(Captured))
end
end, FilteredTokens),
Positions.



%evaluate_rpn(Expression) ->
'_evaluate_rpn'([], Stack) -> stack:peek(Stack);

'_evaluate_rpn'(Tokens, Stack) ->
[FirstToken | RestTokens] = Tokens,
'_evaluate_rpn'(RestTokens, handle_token(FirstToken, Stack)).


evaluate_rpn(Expression) -> '_evaluate_rpn'(tokenize(Expression), []).


start() ->
io:fwrite("~p~n", [tokenize("-11.4 2 3 / + * // ** % + 4 -")]).
io:fwrite("~p~n", [evaluate_rpn("1 2 3 * + 4 -")]).

0 comments on commit 4d7a881

Please sign in to comment.