Skip to content

Commit

Permalink
Refactor reverse_polish_notation_evaluator.erl, utils.erl
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexanderSLoburev committed Jan 4, 2024
1 parent 3272560 commit 22cd3c5
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 45 deletions.
23 changes: 21 additions & 2 deletions common/utils.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-module(utils).
-export([try_parse_number/1, is_digit/1, re_escape/1]).
-export([try_parse_number/1, is_digit/1, re_escape/1, tokenize/1]).


try_parse_number(String) ->
Expand All @@ -13,4 +13,23 @@ is_digit(Char) -> lists:member(Char, lists:seq($0, $9)).

re_escape(String) ->
Escaped = re:replace(String, "[\\[\\]\\\\^$.|?*+()]", "\\\\&", [global]),
Escaped.
Escaped.


'_tokenize'(_Expression, [], _Position, Acc) -> lists:reverse(Acc);

'_tokenize'(Expression, Tokens, Position, Acc) ->
[FirstToken | RestTokens] = Tokens,
FirstPositionOfToken = string:str(Expression, FirstToken),
LengthOfToken = string:length(FirstToken),
SubstringStart = FirstPositionOfToken + LengthOfToken,
TrimmedExpression = string:slice(Expression, SubstringStart),
'_tokenize'(TrimmedExpression, RestTokens, Position + SubstringStart, [{FirstToken, Position + FirstPositionOfToken - 1} | Acc]).

tokenize(Expression) ->
Tokens = lists:filter(fun(X) -> (X =/= "") and not(lists:member(X, "\s\t\n")) end,
lists:map(fun(Token) -> binary_to_list(Token) end,
re:split(Expression, "\\s+")
)
),
'_tokenize'(Expression, Tokens, 1, []).
Original file line number Diff line number Diff line change
Expand Up @@ -3,82 +3,78 @@


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) ->
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),
Right = try
stack:peek(Stack)
catch
_ -> throw({error, lists:flatten(io_lib:format("Syntax error in position ~w: ~p is wrong token.~n", [Position, Token]))})
end,
io:fwrite("Poping ~p from stack~n", [Right]),
StackAfterFirstPop = stack:pop(Stack),
Left = try
stack:peek(StackAfterFirstPop)
catch
_ -> throw({error, lists:flatten(io_lib:format("Syntax error in position ~w: ~p is wrong token.~n", [Position, Token]))})
end,
io:fwrite("Poping ~p from stack~n", [Left]),
StackAfterSecondPop = stack:pop(StackAfterFirstPop),
case Token of
"+" ->
io:fwrite("Pushing ~p into stack~n", [Left + Right]),
stack:push(Left + Right, StackAfterSecondPop);
Result = Left + Right,
io:fwrite("~p + ~p = ~p, pushing ~p into stack~n", [Left, Right, Result, Result]),
stack:push(Result, StackAfterSecondPop);
"-" ->
io:fwrite("Pushing ~p into stack~n", [Left - Right]),
stack:push(Left - Right, StackAfterSecondPop);
Result = Left - Right,
io:fwrite("~p - ~p = ~p, pushing ~p into stack~n", [Left, Right, Result, Result]),
stack:push(Result, StackAfterSecondPop);
"*" ->
io:fwrite("Pushing ~p into stack~n", [Left * Right]),
stack:push(Left * Right, StackAfterSecondPop);
Result = Left * Right,
io:fwrite("~p * ~p = ~p, pushing ~p into stack~n", [Left, Right, Result, Result]),
stack:push(Result, StackAfterSecondPop);
"/" ->
io:fwrite("Pushing ~p into stack~n", [Left / Right]),
stack:push(Left / Right, StackAfterSecondPop);
Result = Left / Right,
io:fwrite("~p / ~p = ~p, pushing ~p into stack~n", [Left, Right, Result, Result]),
stack:push(Result, StackAfterSecondPop);
"//" ->
case is_integer(Left) and is_integer(Right) of
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])})
Result = Left div Right,
io:fwrite("~p // ~p = ~p, pushing ~p into stack~n", [Left, Right, Result, Result]),
stack:push(Result, StackAfterSecondPop);
false -> throw({error, lists:flatten(io_lib:format("Error at position ~w: both operands must be integers.", [Position]))})
end;
"%" ->
case is_integer(Left) and is_integer(Right) of
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])})
Result = Left rem Right,
io:fwrite("~p % ~p = ~p, pushing ~p into stack~n", [Left, Right, Result, Result]),
stack:push(Result, StackAfterSecondPop);
false -> throw({error, lists:flatten(io_lib:format("Error at position ~w: both operands must be integers.", [Position]))})
end;
"**" ->
io:fwrite("Pushing ~p into stack~n", [math:pow(Left, Right)]),
stack:push(math:pow(Left, Right), StackAfterSecondPop)
Result = math:pow(Left, Right),
io:fwrite("~p ** ~p = ~p, pushing ~p into stack~n", [Left, Right, Result, Result]),
stack:push(Result, StackAfterSecondPop)
end
end.


'_tokenize'(_Expression, [], _Position, Acc) -> lists:reverse(Acc);

'_tokenize'(Expression, Tokens, Position, Acc) ->
[FirstToken | RestTokens] = Tokens,
FirstPositionOfToken = string:str(Expression, FirstToken),
LengthOfToken = string:length(FirstToken),
SubstringStart = FirstPositionOfToken + LengthOfToken,
TrimmedExpression = string:slice(Expression, SubstringStart),
'_tokenize'(TrimmedExpression, RestTokens, Position + SubstringStart, [{FirstToken, Position + FirstPositionOfToken - 1} | Acc]).

tokenize(Expression) ->
Tokens = lists:filter(fun(X) -> (X =/= "") and not(lists:member(X, "\s\t\n")) end,
lists:map(fun(Token) -> binary_to_list(Token) end,
re:split(Expression, "\\s+")
)
),
'_tokenize'(Expression, Tokens, 1, []).


'_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), []).
evaluate_rpn(Expression) -> '_evaluate_rpn'(utils:tokenize(Expression), []).


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

0 comments on commit 22cd3c5

Please sign in to comment.