/
exp_eval.py
139 lines (131 loc) · 4.83 KB
/
exp_eval.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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
from stack_array import Stack
# You do not need to change this class
class PostfixFormatException(Exception):
pass
def postfix_eval(input_str):
"""Evaluates a postfix expression"""
"""Input argument: a string containing a postfix expression where tokens
are space separated. Tokens are either operators + - * / ^ or numbers
Returns the result of the expression evaluation.
Raises an PostfixFormatException if the input is not well-formed"""
s = Stack(30)
tokens = input_str.split( )
operators = ['+', '-', '*', '/', '**', '<<', '>>']
if input_str == '':
return ''
for char in tokens:
if char in operators:
try:
n2 = s.pop()
n1 = s.pop()
except IndexError:
raise PostfixFormatException('Insufficient operands')
if char == '+':
result = n1 + n2
s.push(result)
if char == '-':
result = n1 - n2
s.push(result)
if char == '*':
result = n1 * n2
s.push(result)
if char == '/':
if n2 == 0:
raise ValueError('Cannot divide by 0!')
result = n1 / n2
s.push(result)
if char == '**':
result = n1 ** n2
s.push(result)
if char == '<<':
if type(n1) == float or type(n2) == float:
raise PostfixFormatException('Illegal bit shift operand')
result = n1 << n2
s.push(result)
if char == '>>':
if type(n1) == float or type(n2) == float:
raise PostfixFormatException('Illegal bit shift operand')
result = n1 >> n2
s.push(result)
elif char.lstrip('-').replace('.','',1).isdigit():
if '.' not in char:
s.push(int(char))
else:
s.push(float(char))
else:
raise PostfixFormatException('Invalid token')
final = s.pop()
if not s.is_empty():
raise PostfixFormatException('Too many operands')
return final
def infix_to_postfix(input_str):
"""Converts an infix expression to an equivalent postfix expression"""
"""Input argument: a string containing an infix expression where tokens are
space separated. Tokens are either operators + - * / ^ parentheses ( ) or numbers
Returns a String containing a postfix expression """
s = Stack(30)
post = ''
tokens = input_str.split( )
op_prec = {'+': 1, '-': 1, '*': 2, '/': 2, '**': 3, '<<': 4, '>>': 4}
operators = ['+','-','*','/','**','<<','>>']
if input_str == '':
return ''
for char in tokens:
if post == '' and char.lstrip('-').replace('.','',1).isdigit():
post += char
elif char.lstrip('-').replace('.','',1).isdigit():
post += ' ' + char
elif char == '(':
s.push(char)
elif char in operators:
if not s.is_empty():
o2 = s.peek()
while s.size() > 0:
o2 = s.peek()
if o2 == '(':
break
if char == '**':
if op_prec[char] < op_prec[o2]:
post += ' ' + s.pop()
else:
break
elif op_prec[char] <= op_prec[o2]:
post += ' ' + s.pop()
else:
break
s.push(char)
elif char == ')':
o2 = s.peek()
while o2 != '(':
post += ' ' + s.pop()
if not s.is_empty():
o2 = s.peek()
s.pop()
while not s.is_empty():
post += ' ' + s.pop()
return post
def prefix_to_postfix(input_str):
"""Converts a prefix expression to an equivalent postfix expression"""
"""Input argument: a string containing a prefix expression where tokens are
space separated. Tokens are either operators + - * / ^ parentheses ( ) or numbers
Returns a String containing a postfix expression(tokens are space separated)"""
s = Stack(30)
tokens = input_str.split( )
i = len(tokens) - 1
operators = ['+','-','*','/','<<','>>','**']
if input_str == '':
return ''
while i >= 0:
char = tokens[i]
if char.lstrip('-').replace('.','',1).isdigit():
s.push(char)
i -= 1
elif char in operators:
op1 = s.pop()
op2 = s.pop()
inf = op1 + ' ' + op2 + ' ' + char
s.push(inf)
i -= 1
else:
break
return s.pop()