Open czheo opened 7 years ago
import re
import operator
OPS = {
'+': 0,
'-': 0,
'*': 1,
'/': 1,
'%': 1,
'^': 2,
'u': 3, # unary -
}
OP_FUNCS = {
'+': operator.add,
'-': operator.sub,
'*': operator.mul,
'/': operator.truediv,
'%': operator.mod,
'^': operator.pow,
'u': operator.sub,
}
def tokenize(exp):
return re.sub(r'([+\-*/^()%])', r' \1 ', exp).split()
def infix_to_postfix(toks):
ret = []
stack = []
for i, tok in enumerate(toks):
if tok in '+-' and (i==0 or toks[i-1] in OPS or toks[i-1]=='('):
# HACK: unary +, -
if tok == '-':
ret.append('0')
stack.append('u')
elif tok in OPS:
# binary ops
if stack:
while stack and OPS.get(stack[-1], -1) > OPS.get(tok):
ret.append(stack.pop())
stack.append(tok)
elif tok == '(':
stack.append(tok)
elif tok == ')':
if not stack:
raise Exception('Unmatched )')
else:
t = stack.pop()
while t != '(':
ret.append(t)
t = stack.pop()
else:
ret.append(tok)
while stack:
ret.append(stack.pop())
return ret
def evaluate(toks):
stack = []
for tok in toks:
if tok in OP_FUNCS:
snd = stack.pop()
fst = stack.pop()
stack.append(OP_FUNCS.get(tok)(fst, snd))
else:
stack.append(float(tok))
return stack.pop()
def parse(exp):
toks = tokenize(exp)
print('infix:', toks)
toks = infix_to_postfix(toks)
print('postfix:', toks)
return evaluate(toks)
def repl():
exp = input('>> ')
while exp != 'exit':
print(parse(exp))
exp = input('>> ')
if __name__ == '__main__':
repl()
Given a math expression such as:
3 + 8 / (3 + 1)
, we'd like to obtain the result5
. https://en.wikipedia.org/wiki/Shunting-yard_algorithm