-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterpreterv1.py
151 lines (134 loc) · 5.26 KB
/
interpreterv1.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
140
141
142
143
144
145
146
147
148
149
150
151
from intbase import InterpreterBase, ErrorType
from brewparse import parse_program
class Interpreter(InterpreterBase):
def __init__(self, console_output=True, inp=None, trace_output=False):
# call InterpreterBase's constructor
super().__init__(console_output, inp)
def run(self, program):
ast = parse_program(program)
self.variables = {} # variable name : value
main_func_node = ast.dict["functions"][0]
if main_func_node.dict["name"] != "main":
super().error(
ErrorType.NAME_ERROR,
"No main() function was found",
)
self.run_function(main_func_node)
def run_function(self, func_node):
for statement_node in func_node.dict["statements"]:
self.run_statement(statement_node)
def run_statement(self, statement_node):
# variable definition
if statement_node.elem_type == "vardef":
name = statement_node.dict["name"]
if name in self.variables:
super().error(
ErrorType.NAME_ERROR,
f"Variable {name} defined more than once",
)
self.variables[name] = 0
elif statement_node.elem_type == "=":
# maps to either an expression node, variable node, or value node
name = statement_node.dict["name"]
node = statement_node.dict["expression"]
if name not in self.variables:
super().error(
ErrorType.NAME_ERROR,
f"Undefined variable {name}",
)
self.variables[name] = self.evaluate_expression(node)
# function call
elif statement_node.elem_type == "fcall":
self.run_function_call(statement_node)
def evaluate_expression(self, expression_node):
# value node
if expression_node.elem_type == "int" or expression_node.elem_type == "string":
return expression_node.dict["val"]
# variable node
elif expression_node.elem_type == "var":
var_name = expression_node.dict["name"]
if var_name not in self.variables:
super().error(
ErrorType.NAME_ERROR,
f"Variable {var_name} has not been defined",
)
return self.variables[var_name]
# binary operation
elif expression_node.elem_type == "+":
op1, op2 = self.check_operation(expression_node)
return self.evaluate_expression(op1) + self.evaluate_expression(op2)
elif expression_node.elem_type == "-":
op1, op2 = self.check_operation(expression_node)
return self.evaluate_expression(op1) - self.evaluate_expression(op2)
# function call
elif expression_node.elem_type == "fcall":
return self.run_function_call(expression_node)
def evaluate_value(self, expression_node):
# value node
if expression_node.elem_type == "int" or expression_node.elem_type == "string":
return expression_node.dict["val"]
# variable node
elif expression_node.elem_type == "var":
var_name = expression_node.dict["name"]
if var_name not in self.variables:
super().error(
ErrorType.NAME_ERROR,
f"Variable {var_name} has not been defined",
)
return self.variables[var_name]
def run_function_call(self, function_call):
func_name = function_call.dict["name"]
if func_name == "print":
res = ""
for arg in function_call.dict["args"]:
res += str(self.evaluate_expression(arg))
super().output(res)
elif func_name == "inputi":
if len(function_call.dict["args"]) > 1:
super().error(
ErrorType.NAME_ERROR,
"No inputi() function found that takes > 1 parameter",
)
elif len(function_call.dict["args"]) == 1:
super().output(function_call.dict["args"][0].dict["val"])
return int(super().get_input())
else:
super().error(
ErrorType.NAME_ERROR,
f"Function {func_name} has not been defined",
)
def check_operation(self, expression_node):
op1 = expression_node.dict["op1"]
op2 = expression_node.dict["op2"]
if (
isinstance(self.evaluate_value(op1), int)
and isinstance(self.evaluate_value(op2), str)
) or (
isinstance(self.evaluate_value(op1), str)
and isinstance(self.evaluate_value(op2), int)
):
super().error(
ErrorType.TYPE_ERROR,
"Incompatible types for arithmetic operation",
)
return op1, op2
if __name__ == "__main__":
# program = """func main() {
# var x;
# x = 4 + inputi("enter a number: ");
# print(x);
# }
# """
program = """func main() {
var x;
x = 3 - (3 + (2 + inputi()));
print(x);
}
"""
# program = """func main() {
# var x;
# x = inputi("enter a number: ");
# print(x);
# }"""
interpreter = Interpreter()
interpreter.run(program)