-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSyntax_Analyzer.py
137 lines (125 loc) · 4.58 KB
/
Syntax_Analyzer.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
from argparse import ArgumentError
from Lexical_Analyzer import Tokenizer
from os import path
import sys
class Syntax_Analyzer:
def __init__(self, tokens_list):
self.commands = tokens_list
self.variables = {}
@property
def commands(self):
return self.__commands
@commands.setter
def commands(self, value):
if isinstance(value, list):
temp_list = []
self.__commands = []
for token in value:
if token.type not in ["EOF", "NEW_LINE"]:
temp_list.append(token)
else:
if len(temp_list) != 0:
self.__commands.append(temp_list)
temp_list = []
else:
raise TypeError("Tokens_list must be list")
def run(self):
for command in self.commands:
self.tokens = iter(command)
token = next(self.tokens)
if token.type == "ID":
token_layer_1 = next(self.tokens)
if token_layer_1.type == "ASSIGN":
self.variables[token.value], op = self.cal_1(next(self.tokens))
else:
raise SyntaxError("assign is missing")
elif token.type == "PRINT":
total_number, op = self.cal_1(next(self.tokens))
print(total_number)
else:
raise SyntaxError("Invalid input")
def cal_1(self, base_token):
num_1, op = self.cal_2(base_token)
if op is not None:
while op.type in ["PLUS", "MINUS"]:
op_ex = op
num_2, op = self.cal_2(next(self.tokens))
if op_ex.type == "PLUS":
num_1 += num_2
else:
num_1 -= num_2
if op is None:
break
return num_1, op
def cal_2(self, base_token):
num_1, op = self.cal_3(base_token)
if op is not None:
while op.type in ["MUL", "DIV"]:
op_ex = op
num_2, op = self.cal_3(next(self.tokens))
if op_ex.type == "POW":
num_1 = pow(num_1, num_2)
elif op_ex.type == "DIV":
num_1 /= num_2
else:
num_1 *= num_2
if op is None:
break
return num_1, op
def cal_3(self, base_token):
num_1, op = self.cal_4(base_token)
if op is not None:
while op.type in ["POW"]:
op_ex = op
num_2, op = self.cal_4(next(self.tokens))
if op_ex.type == "POW":
num_1 = pow(num_1, num_2)
else:
num_1 *= num_2
if op is None:
break
return num_1, op
def cal_4(self, base_token):
try:
num_1 = 0
var = base_token
if var.type == "NUM":
num_1 = var.value
elif var.type == "MINUS":
next_var = next(self.tokens)
if next_var.type == "NUM":
num_1 = next_var.value * -1
elif next_var.type == "ID":
try:
num_1 = self.variables[next_var.value] * -1
except KeyError:
raise SyntaxError(
"{} is not declared in variables".format(next_var.value)
)
elif var.type == "ID":
try:
num_1 = self.variables[var.value]
except KeyError:
raise SyntaxError(
"{} is not declared in variables".format(var.value)
)
elif var.type == "OPEN_BRACKET":
num_1, op_next = self.cal_1(next(self.tokens))
if op_next and op_next.type != "CLOSE_BRACKET":
raise SyntaxError("close bracket is missing")
else:
raise SyntaxError("Invalid input")
next_token = next(self.tokens)
except StopIteration:
next_token = None
return num_1, next_token
if __name__ == "__main__":
if len(sys.argv) > 1:
file_path = sys.argv[1]
if path.isfile(file_path):
tokenizer = Tokenizer(file_path)
Syntax_Analyzer(tokenizer.get_tokens()).run()
else:
raise FileExistsError("File does not exist !")
else:
raise ArgumentError(None, "File path must set in first position of arguments !")