-
Notifications
You must be signed in to change notification settings - Fork 4
/
project_07.py
197 lines (142 loc) · 5.23 KB
/
project_07.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# VM I: Stack Arithmetic
#
# See https://www.nand2tetris.org/project07
from nand.translate import AssemblySource
# SOLVERS: remove this import to get started
from nand.solutions import solved_07
class Translator:
"""Translates all the arithmetic and memory access opcodes of the VM to assembly instructions.
"""
def __init__(self):
# AssemblySource deals with keeping track of emitted instructions, and provides a nice
# log of execution which makes debugging a lot easier. In any case, the tests assume you use
# it, so you might as well not fight it.
self.asm = AssemblySource()
# SOLVERS: remove this when all the method bodies are filled in
self.solved = solved_07.Translator(self.asm)
#
# Simple Add:
#
def push_constant(self, value):
# SOLVERS: write some code here to emit Hack assembly instructions to push `value` onto the stack
#
# self.asm.start("push constant") # insert a comment which is shown when debugging
# self.asm.instr(f"@{value}")
# self.asm.instr("D=A")
# ...
return self.solved.push_constant(value)
def add(self):
# SOLVERS: implement the add opcode
return self.solved.add()
#
# Stack Ops:
#
def sub(self):
# SOLVERS: implement the sub opcode
return self.solved.sub()
def neg(self):
# SOLVERS: implement the sub opcode
return self.solved.neg()
def and_op(self):
# SOLVERS: implement the and opcode
return self.solved.and_op()
def or_op(self):
# SOLVERS: implement the or opcode
return self.solved.or_op()
def not_op(self):
# SOLVERS: implement the not opcode
return self.solved.not_op()
def eq(self):
# SOLVERS: implement the eq opcode
return self.solved.eq()
def lt(self):
# SOLVERS: implement the lt opcode
return self.solved.lt()
def gt(self):
# SOLVERS: implement the gt opcode
return self.solved.gt()
#
# Memory Access - Basic:
#
def pop_local(self, index):
# SOLVERS: implement
return self.solved.pop_local(index)
def pop_argument(self, index):
# SOLVERS: implement
return self.solved.pop_argument(index)
def pop_this(self, index):
# SOLVERS: implement
return self.solved.pop_this(index)
def pop_that(self, index):
# SOLVERS: implement
return self.solved.pop_that(index)
def pop_temp(self, index):
# SOLVERS: implement
return self.solved.pop_temp(index)
def push_local(self, index):
# SOLVERS: implement
return self.solved.push_local(index)
def push_argument(self, index):
# SOLVERS: implement
return self.solved.push_argument(index)
def push_this(self, index):
# SOLVERS: implement
return self.solved.push_this(index)
def push_that(self, index):
# SOLVERS: implement
return self.solved.push_that(index)
def push_temp(self, index):
# SOLVERS: implement
return self.solved.push_temp(index)
#
# Memory Access - Pointer:
#
def pop_pointer(self, index):
# SOLVERS: implement
return self.solved.pop_pointer(index)
def push_pointer(self, index):
# SOLVERS: implement
return self.solved.push_pointer(index)
#
# Memory Access - Static:
#
def pop_static(self, index):
# SOLVERS: implement
return self.solved.pop_static(index)
def push_static(self, index):
# SOLVERS: implement
return self.solved.push_static(index)
#
# (Optional) Cleanup:
#
def finish(self):
"""Called after all opcodes are processed, in case the translator needs to say any last words."""
pass
#
# (Optional) Optimization:
#
def rewrite_ops(self, ops):
# SOLVERS: ignore for now. This is a hook to allow the Translator to inspect and modify the
# opcode sequence before it is translated, in case a "better" equivalent sequence is possible.
return ops
def check_references(self):
"""Check for obvious "linkage" errors: e.g. functions that are referenced but never defined.
Raises AssertionFailure if there are any obvious problems.
"""
# SOLVERS: this is a big help for debugging programs later on, but you can just return None
# and nothing will break (except possibly your sanity.)
return self.solved.check_references()
#
# Wiring:
#
def handle(self, op):
"""Dispatch to the handler for an opcode, in the form of a tuple (op_name, [args])."""
# SOLVERS: this is just plumbing to call one of the methods definied below. Feel
# free to leave it here and don't worry about it how it works too much.
op_name, args = op
self.__getattribute__(op_name)(*args)
def parse_line(line):
# SOLVERS: parse one line of VM source. The result should be a tuple which contains the name of
# the method of Translator which handles the opcode, and a sequence with any arguments.
# E.g. ("push_constant", [1]), ("add", []), ("function", ["Main", "main", 2])
return solved_07.parse_line(line)