-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
149 lines (128 loc) · 4.18 KB
/
main.py
File metadata and controls
149 lines (128 loc) · 4.18 KB
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
140
141
142
143
144
145
146
147
148
149
class CompilationError(Exception):
pass
class Token:
def __init__(self, type, value):
self.type = type
self.value = value
def __repr__(self):
return "Token({0}, {1!r})".format(self.type, self.value)
def new_token(char):
if char.isspace():
return None
elif char in "(":
return Token("BEGIN_BRACKET", char)
elif char in ")":
return Token("END_BRACKET", char)
elif char in "+-*/":
return Token("OP", char)
elif char.isdigit():
return Token("NUMBER", char)
else:
raise CompilationError("Unknown character: \"{0}\"".format(char))
def continue_token(current, char):
if current.type == "NUMBER":
if char.isdigit():
current.value += char
return True
else:
return False
elif current.type == "OP":
return False
elif current.type == "BRACKET":
return False
def parse(s):
tokens = []
current_token = None
for i in s:
if current_token is None:
current_token = new_token(i)
else:
if not continue_token(current_token, i):
tokens.append(current_token)
current_token = new_token(i)
if current_token is not None:
tokens.append(current_token)
for i in tokens:
if i.type == "NUMBER":
i.value = int(i.value)
return tokens
def create_groups_by_priority(group):
operations = ["*/", "+-"]
for op in operations:
i = 0
while i < len(group):
v = group[i]
if isinstance(v, Token) and v.type == "OP" and v.value in op:
if i == 0 or i == len(group) - 1:
raise CompilationError("No argument for operation")
group[i - 1:i + 2] = [[group[i - 1], group[i], group[i + 1]]]
i += 1
def build_tree(tokens):
group_stack = []
current_group = []
for i in tokens:
if i.type == "BEGIN_BRACKET":
group_stack.append(current_group)
current_group = []
elif i.type == "END_BRACKET":
if len(group_stack) == 0:
raise CompilationError("Wrong closing bracket")
else:
if len(current_group) == 1:
current_group = current_group[0]
else:
create_groups_by_priority(current_group)
group_stack[-1].append(current_group)
current_group = group_stack.pop()
else:
current_group.append(i)
if len(group_stack) > 0:
raise CompilationError("Not enough closing brackets")
create_groups_by_priority(current_group)
return current_group
def print_node(node, depth):
if isinstance(node, Token):
if node.type in {"OP", "NUMBER"}:
print(" " * (4 * depth) + str(node.value))
else:
print(" " * (4 * depth) + str(node))
else:
print_tree(node, depth)
def print_tree(tree, depth=0):
print(" " * (4 * depth) + "[")
for i in tree:
print_node(i, depth + 1)
print(" " * (4 * depth) + "]")
def execute(tree):
if isinstance(tree, Token):
if tree.type == "NUMBER":
return tree.value
else:
raise CompilationError("Unexpected token")
else:
if len(tree) == 1:
return execute(tree[0])
elif len(tree) != 3:
raise CompilationError("Not enough operations")
else:
tree[0] = execute(tree[0])
tree[2] = execute(tree[2])
if isinstance(tree[1], Token) and tree[1].type == "OP":
if tree[1].value == "+":
return tree[0] + tree[2]
elif tree[1].value == "-":
return tree[0] - tree[2]
elif tree[1].value == "*":
return tree[0] * tree[2]
elif tree[1].value == "/":
return tree[0] / tree[2]
else:
raise CompilationError("Unexpected token")
try:
expr = input("Expression: ")
tokens = parse(expr)
tree = build_tree(tokens)
print_tree(tree)
print("Result: ", execute(tree))
except CompilationError as e:
print("Compilation error: {0}".format(e))