-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathshunting-yard-algorithm.py
56 lines (53 loc) · 1.89 KB
/
shunting-yard-algorithm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# https://en.wikipedia.org/wiki/Shunting-yard_algorithm
PRECEDENCE = { 'func': 3, '^': 2, '/': 1, '*': 1, '+': 0, '-': 0 }
def parse(input_):
operator = []
output = []
tokens = list(input_)
while len(tokens) > 0:
char = tokens[0]
# number
if char.isnumeric(): output.append(char)
# function
if char.isalpha():
function = [char]
i = 1
while tokens[i].isalpha():
function.append(tokens[i])
i += 1
operator.append(('func', ''.join(function)))
# advance
tokens = tokens[i - 1:]
# operator
if char in ['+', '-', '*', '/', '^']:
# precedence
while len(operator) > 0:
op = operator.pop()
if op[0] == 'func':
output.append(op[1])
elif op not in ['(', '^'] and (op in PRECEDENCE and PRECEDENCE[op] >= PRECEDENCE[char]):
output.append(op)
else:
# break
operator.append(op)
break
operator.append(char)
# left parenthesis
if char == '(': operator.append(char)
# right parenthesis
if char == ')':
if '(' not in operator: print("Error: Mismatched parentheses")
while len(operator) > 0:
op = operator.pop()
if op[0] == 'func': output.append(op[1])
elif op != '(': output.append(op)
else: break
tokens = tokens[1:]
# pop operators
while len(operator) > 0:
op = operator.pop()
if op[0] == 'func': output.append(op[1])
else: output.append(op)
return ' '.join(output)
assert parse("3 + 4 * 2 / (1 - 5) ^2 ^3") == "3 4 2 * 1 5 - 2 3 ^ ^ / +"
assert parse("sin(max(2, 3) / 3 * pi)") == "2 3 max 3 / pi * sin"