Skip to content

Instantly share code, notes, and snippets.

@p7g
Created June 28, 2020 20:38
Show Gist options
  • Save p7g/dd9f9b19082a884f5cbb180fc35d2202 to your computer and use it in GitHub Desktop.
Save p7g/dd9f9b19082a884f5cbb180fc35d2202 to your computer and use it in GitHub Desktop.
Simple implementation of the shunting yard algorithm (https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm) in Python
operators = ['sentinel', '=', ')', '(', '+', '*', '.']
precedence = dict((b, a) for a, b in enumerate(operators))
assoc_right = {'='}
def has_higher_prec(a, b):
prec = precedence[a]
if a in assoc_right:
prec += 1
return prec > precedence[b]
def operate(op, a, b):
if op in {'=', '+', '.', '*'}:
return f'({a}{op}{b})'
if op == '(':
return f'{a}({b})'
raise ValueError(op)
def parse(s):
i = 0
def next():
nonlocal i
c = s[i]
i += 1
return c
def peek():
return s[i]
operand_stack = []
operator_stack = ['sentinel']
def print_state():
print(
s[i:],
'|',
' '.join(reversed(operand_stack)),
'|',
' '.join(reversed(operator_stack)),
)
def consume_operator():
op = operator_stack.pop()
if op == ')': # right paren has no effect
return True
b, a = operand_stack.pop(), operand_stack.pop()
operand_stack.append(operate(op, a, b))
while i < len(s):
print_state()
c = peek()
if c in operators:
if has_higher_prec(c, operator_stack[-1]):
operator_stack.append(next())
elif consume_operator():
continue
else:
operand_stack.append(next())
while len(operator_stack) > 1:
print_state()
consume_operator()
assert len(operand_stack) == 1
return operand_stack.pop()
print(parse('a=S.f(a+b)*3'))
print(parse('a=b=3'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment