fixes #8673; Add operator's associativity check for stacks/infix_to_postfix_conversion.py

This commit is contained in:
Amirsoroush 2023-04-20 00:03:10 +03:00
parent 11582943a5
commit 55a8fae7b2

View File

@ -4,9 +4,26 @@ https://en.wikipedia.org/wiki/Reverse_Polish_notation
https://en.wikipedia.org/wiki/Shunting-yard_algorithm https://en.wikipedia.org/wiki/Shunting-yard_algorithm
""" """
from typing import Literal
from .balanced_parentheses import balanced_parentheses from .balanced_parentheses import balanced_parentheses
from .stack import Stack from .stack import Stack
PRECEDENCES: dict[str, int] = {
"+": 1,
"-": 1,
"*": 2,
"/": 2,
"^": 3,
}
ASSOCIATIVITIES: dict[str, Literal["LR", "RL"]] = {
"+": "LR",
"-": "LR",
"*": "LR",
"/": "LR",
"^": "RL",
}
def precedence(char: str) -> int: def precedence(char: str) -> int:
""" """
@ -14,7 +31,15 @@ def precedence(char: str) -> int:
order of operation. order of operation.
https://en.wikipedia.org/wiki/Order_of_operations https://en.wikipedia.org/wiki/Order_of_operations
""" """
return {"+": 1, "-": 1, "*": 2, "/": 2, "^": 3}.get(char, -1) return PRECEDENCES.get(char, -1)
def associativity(char: str) -> Literal["LR", "RL"]:
"""
Return the associativity of the operator `char`.
https://en.wikipedia.org/wiki/Operator_associativity
"""
return ASSOCIATIVITIES[char]
def infix_to_postfix(expression_str: str) -> str: def infix_to_postfix(expression_str: str) -> str:
@ -35,6 +60,8 @@ def infix_to_postfix(expression_str: str) -> str:
'a b c * + d e * f + g * +' 'a b c * + d e * f + g * +'
>>> infix_to_postfix("x^y/(5*z)+2") >>> infix_to_postfix("x^y/(5*z)+2")
'x y ^ 5 z * / 2 +' 'x y ^ 5 z * / 2 +'
>>> infix_to_postfix("2^3^2")
'2 3 2 ^ ^'
""" """
if not balanced_parentheses(expression_str): if not balanced_parentheses(expression_str):
raise ValueError("Mismatched parentheses") raise ValueError("Mismatched parentheses")
@ -50,9 +77,26 @@ def infix_to_postfix(expression_str: str) -> str:
postfix.append(stack.pop()) postfix.append(stack.pop())
stack.pop() stack.pop()
else: else:
while not stack.is_empty() and precedence(char) <= precedence(stack.peek()): while True:
postfix.append(stack.pop()) if stack.is_empty():
stack.push(char) stack.push(char)
break
char_precedence = precedence(char)
TOS_precedence = precedence(stack.peek())
if char_precedence > TOS_precedence:
stack.push(char)
break
elif char_precedence == TOS_precedence:
if associativity(char) == "RL":
stack.push(char)
break
else:
postfix.append(stack.pop())
else:
postfix.append(stack.pop())
while not stack.is_empty(): while not stack.is_empty():
postfix.append(stack.pop()) postfix.append(stack.pop())
return " ".join(postfix) return " ".join(postfix)