-
Notifications
You must be signed in to change notification settings - Fork 0
/
interpreter.py
117 lines (90 loc) · 3.5 KB
/
interpreter.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
from lark import Lark
from lark.indenter import Indenter
from lark.lexer import Token
from lark.tree import Tree
class PythonIndenter(Indenter):
NL_type = '_NEWLINE'
OPEN_PAREN_types = ['LPAR', 'LSQB', 'LBRACE']
CLOSE_PAREN_types = ['RPAR', 'RSQB', 'RBRACE']
INDENT_type = '_INDENT'
DEDENT_type = '_DEDENT'
tab_len = 8
kwargs = dict(rel_to=__file__, postlex=PythonIndenter(), start='file_input')
python_parser3 = Lark.open('python3.lark', parser='lalr', **kwargs)
class StackFrame(object):
"""Stack frame class."""
def __init__(self):
self.frame_locals = {}
def dump(self):
"""Dump the stack."""
print("========= Stack Locals ==========")
print(self.frame_locals)
class Var(object):
"""Variable class."""
def __init__(self, value):
self.value = value
def __repr__(self):
return str(self.value)
# TODO - Make builtin types, including int, float, and object.
# TOOD - Implement base object functions to perform arithmetic: https://docs.python.org/3.7/reference/datamodel.html#emulating-numeric-types
# Global stack frame
global_frame = StackFrame()
def run_instruction(t):
if t.data == 'expr_stmt':
var_name = t.children[0].children[0].value
result = run_instruction(t.children[1])
global_frame.frame_locals[var_name] = Var(result)
elif t.data == 'arith_expr' or t.data == 'term':
result = None
next_operand = None
for child in t.children:
if isinstance(child, Tree):
if child.data == "term":
x = run_instruction(child)
if result is None:
result = x
elif result is not None:
if next_operand.type == "PLUS":
result = result + x
elif next_operand.type == "MINUS":
result = result - x
elif next_operand.type == "STAR":
result = result * x
elif next_operand.type == "SLASH":
result = result / x
if child.data == "number":
x = int(child.children[0].value)
if result is None:
result = x
elif result is not None:
if next_operand.type == "PLUS":
result = result + x
elif next_operand.type == "MINUS":
result = result - x
elif next_operand.type == "STAR":
result = result * x
elif next_operand.type == "SLASH":
result = result / x
elif isinstance(child, Token):
next_operand = child
return result
else:
raise SyntaxError('Unknown instruction: %s' % t.data)
def main():
ENABLE_TIMING = True
from timeit import default_timer as timer
if ENABLE_TIMING:
parse_start = timer()
parse_tree = python_parser3.parse(open('test.py', 'r').read())
if ENABLE_TIMING:
parse_end = timer()
exec_start = timer()
# Main loop
for inst in parse_tree.children:
run_instruction(inst)
if ENABLE_TIMING:
exec_end = timer()
print("Parsing time (seconds): %s" % (parse_end - parse_start,))
print("Execution time (seconds): %s" % (exec_end - exec_start,))
global_frame.dump()
main()