44https://en.wikipedia.org/wiki/Shunting-yard_algorithm
55"""
66
7+ from typing import Literal
8+
79from .balanced_parentheses import balanced_parentheses
810from .stack import Stack
911
12+ PRECEDENCES : dict [str , int ] = {
13+ "+" : 1 ,
14+ "-" : 1 ,
15+ "*" : 2 ,
16+ "/" : 2 ,
17+ "^" : 3 ,
18+ }
19+ ASSOCIATIVITIES : dict [str , Literal ["LR" , "RL" ]] = {
20+ "+" : "LR" ,
21+ "-" : "LR" ,
22+ "*" : "LR" ,
23+ "/" : "LR" ,
24+ "^" : "RL" ,
25+ }
26+
1027
1128def precedence (char : str ) -> int :
1229 """
1330 Return integer value representing an operator's precedence, or
1431 order of operation.
1532 https://en.wikipedia.org/wiki/Order_of_operations
1633 """
17- return {"+" : 1 , "-" : 1 , "*" : 2 , "/" : 2 , "^" : 3 }.get (char , - 1 )
34+ return PRECEDENCES .get (char , - 1 )
35+
36+
37+ def associativity (char : str ) -> Literal ["LR" , "RL" ]:
38+ """
39+ Return the associativity of the operator `char`.
40+ https://en.wikipedia.org/wiki/Operator_associativity
41+ """
42+ return ASSOCIATIVITIES [char ]
1843
1944
2045def infix_to_postfix (expression_str : str ) -> str :
@@ -35,6 +60,8 @@ def infix_to_postfix(expression_str: str) -> str:
3560 'a b c * + d e * f + g * +'
3661 >>> infix_to_postfix("x^y/(5*z)+2")
3762 'x y ^ 5 z * / 2 +'
63+ >>> infix_to_postfix("2^3^2")
64+ '2 3 2 ^ ^'
3865 """
3966 if not balanced_parentheses (expression_str ):
4067 raise ValueError ("Mismatched parentheses" )
@@ -50,9 +77,26 @@ def infix_to_postfix(expression_str: str) -> str:
5077 postfix .append (stack .pop ())
5178 stack .pop ()
5279 else :
53- while not stack .is_empty () and precedence (char ) <= precedence (stack .peek ()):
80+ while True :
81+ if stack .is_empty ():
82+ stack .push (char )
83+ break
84+
85+ char_precedence = precedence (char )
86+ tos_precedence = precedence (stack .peek ())
87+
88+ if char_precedence > tos_precedence :
89+ stack .push (char )
90+ break
91+ if char_precedence < tos_precedence :
92+ postfix .append (stack .pop ())
93+ continue
94+ # Precedences are equal
95+ if associativity (char ) == "RL" :
96+ stack .push (char )
97+ break
5498 postfix .append (stack .pop ())
55- stack . push ( char )
99+
56100 while not stack .is_empty ():
57101 postfix .append (stack .pop ())
58102 return " " .join (postfix )
0 commit comments