Nand2Tetris — Capítulo 8
Traductor de VM II: flujo del programa y llamadas a funciones
# VM Translator 2
# Entrada: archivo o directorio .vm
# Salida: archivo .asm
# Alcance: flujo del programa, llamada de función/retorno
# movimiento:
# Llame a Sys.init después de configurar SP=256 en bootstrap
# la llamada guarda la dirección del remitente y LCL/ARG/ESTO/ESO y se mueve a un nuevo marco
# return restaura FRAME=LCL, RET=*(FRAME-5) y luego salta a la ubicación de la persona que llama.
class VMWriter:
def __init__(self):
self.call_id = 0
self.current_function = ""
def scoped(self, label):
if self.current_function:
return f"{self.current_function}${label}"
return label
def bootstrap(self):
return [
"@256",
"D=A",
"@SP",
"M=D",
] + self.write_call("Sys.init", 0)
def write_label(self, label):
return [f"({self.scoped(label)})"]
def write_goto(self, label):
return [
f"@{self.scoped(label)}",
"0;JMP",
]
def write_if(self, label):
return [
"@SP",
"AM=M-1",
"D=M",
f"@{self.scoped(label)}",
"D;JNE",
]
def write_function(self, name, local_count):
self.current_function = name
code = [f"({name})"]
for _ in range(int(local_count)):
code += [
"@SP",
"A=M",
"M=0",
"@SP",
"M=M+1",
]
return code
def push_register(self, register):
return [
f"@{register}",
"D=M",
"@SP",
"A=M",
"M=D",
"@SP",
"M=M+1",
]
def write_call(self, name, arg_count):
return_label = f"{name}$ret.{self.call_id}"
self.call_id += 1
code = [
f"@{return_label}",
"D=A",
"@SP",
"A=M",
"M=D",
"@SP",
"M=M+1",
]
for register in ["LCL", "ARG", "THIS", "THAT"]:
code += self.push_register(register)
code += [
"@SP",
"D=M",
f"@{int(arg_count) + 5}",
"D=D-A",
"@ARG",
"M=D",
"@SP",
"D=M",
"@LCL",
"M=D",
f"@{name}",
"0;JMP",
f"({return_label})",
]
return code
def write_return(self):
return [
"@LCL",
"D=M",
"@R13",
"M=D",
"@5",
"A=D-A",
"D=M",
"@R14",
"M=D",
"@SP",
"AM=M-1",
"D=M",
"@ARG",
"A=M",
"M=D",
"@ARG",
"D=M+1",
"@SP",
"M=D",
"@R13",
"AM=M-1",
"D=M",
"@THAT",
"M=D",
"@R13",
"AM=M-1",
"D=M",
"@THIS",
"M=D",
"@R13",
"AM=M-1",
"D=M",
"@ARG",
"M=D",
"@R13",
"AM=M-1",
"D=M",
"@LCL",
"M=D",
"@R14",
"A=M",
"0;JMP",
]