-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathproject_11.py
128 lines (92 loc) · 4.46 KB
/
project_11.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
# Compiler II: Code Generation
#
# See https://www.nand2tetris.org/project11
from nand.jack_ast import *
# SOLVERS: remove this import to get started
from nand.solutions import solved_11
class SymbolTable:
def __init__(self, class_name):
# SOLVERS: delete this line and add your implementation here
self.solved = solved_11.SymbolTable(class_name)
def start_subroutine(self, name, kind):
"""Start a new subroutine scope (i.e. remove all "argument" and "local" definitions.),
and track the name and the kind of subroutine being defined ("function", "method", or
"constructor"), for reporting the context when something goes wrong.
"""
# SOLVERS: delete this line and add your implementation here
self.solved.start_subroutine(name, kind)
def define(self, name, type_, kind):
"""Record the definition of a new identifier, and assign it a running index.
If `kind` is "static" or "this", record it in class scope, if "argument" or "local",
record it in subroutine scope."""
# SOLVERS: delete this line and add your implementation here
self.solved.define(name, type_, kind)
def count(self, kind):
"""Number of identifiers of the given kind already defined in the current scope
(class or subroutine, depending on the kind.)
"""
# SOLVERS: delete this line and add your implementation here
return self.solved.count(kind)
def kind_of(self, name):
"""Look up the kind of an identifier. Return "static", "field", "argument", or "var"; if
the identifier has not been defined in the current scope, return None."""
# SOLVERS: delete this line and add your implementation here
return self.solved.kind_of(name)
def type_of(self, name):
"""Look up the type of an identifier. If the identifier has not been defined in the
current scope, throw.
"""
# SOLVERS: delete this line and add your implementation here
return self.solved.type_of(name)
def index_of(self, name):
"""Look up the index of an identifier. Return an integer which is unique to the given
identifier in the current scope, counting from 0; if the identifier has not been defined
in the current scope, return None."""
# SOLVERS: delete this line and add your implementation here
return self.solved.index_of(name)
def context(self):
"""Brief description of the part of the program being analyzed, e.g. "Main.run".
Note: this is useful for debugging, but not actually required for the tests or for actually
using the compiler.
"""
# SOLVERS: delete this line and add your implementation here
return self.solved.context()
def __str__(self):
"""A human-readable summary of all definitions in scope.
Note: this is useful for debugging, but not actually required for the tests or for actually
using the compiler.
"""
# SOLVERS: delete this line and add your implementation here
return str(self.solved)
def find_symbols(node):
"""Identify all references needing to be mapped to locations in memory, and build the mapping
in the form of a symbol table.
TODO: how do symbol tables for different scopes get composed?
"""
symbol_table = solved_11.find_symbols(node)
return symbol_table
def compile_expression(ast, symbol_table, asm):
"""Given a node representing a Jack expression (e.g. "x + 1"), and a symbol table mapping
identifiers to locations, generate VM instructions to compute the result and leave it on the
stack.
>>> from nand.translate import AssemblySource
>>> asm = AssemblySource()
>>> compile_expression(IntegerConstant(1), SymbolTable("Test"), asm)
>>> asm.lines
[' push constant 1']
"""
# if isinstance(ast, IntegerConstant):
# asm.instr(f"push constant {ast.value}")
# elif ...
# SOLVERS: replace this with your own implementation
solved_11.compile_expression(ast, symbol_table, asm)
def compile_class(ast, asm):
"""Given a jack_ast.Class node, generate VM source for all subroutines.
VM opcodes are written to the provided AssemblySource, which can also take
care of generating unique labels.
"""
# symbol_table = SymbolTable(ast.name)
# for sd in ast.subroutineDecs:
# ...
# SOLVERS: replace this with your own implementation
solved_11.compile_class(ast, asm)