← SEARCHABLE ARCHIVE
Nand2Tetris · 2026-05-20

Nand2Tetris — Capítulo 7

Traductor de VM I: operaciones de pila y segmentos de memoria

INTERACTIVE READING MODE →

# VM Translator 1
# Entrada: archivo .vm
# Salida: archivo .asm
# Alcance: comandos push/pop/aritméticos
# movimiento:
# El puntero de la pila está apuntado por SP,
# push es *SP=valor y luego SP++,
# pop almacena el valor después de SP-- en el segmento correspondiente.

import sys


SEGMENT_BASE = {
    "local": "LCL",
    "argument": "ARG",
    "this": "THIS",
    "that": "THAT",
}


class VMTranslator:
    def __init__(self):
        self.label_id = 0

    def push_d(self):
        return [
            "@SP",
            "A=M",
            "M=D",
            "@SP",
            "M=M+1",
        ]

    def pop_to_d(self):
        return [
            "@SP",
            "AM=M-1",
            "D=M",
        ]

    def write_arithmetic(self, command):
        if command == "add":
            return ["@SP", "AM=M-1", "D=M", "A=A-1", "M=M+D"]
        if command == "sub":
            return ["@SP", "AM=M-1", "D=M", "A=A-1", "M=M-D"]
        if command == "and":
            return ["@SP", "AM=M-1", "D=M", "A=A-1", "M=M&D"]
        if command == "or":
            return ["@SP", "AM=M-1", "D=M", "A=A-1", "M=M|D"]
        if command == "neg":
            return ["@SP", "A=M-1", "M=-M"]
        if command == "not":
            return ["@SP", "A=M-1", "M=!M"]

        # eq, gt, lt guarda el resultado de la comparación como verdadero (-1) o falso (0) en la parte superior de la pila.
        jump = {"eq": "JEQ", "gt": "JGT", "lt": "JLT"}[command]
        true_label = f"TRUE_{self.label_id}"
        end_label = f"END_{self.label_id}"
        self.label_id += 1

        return [
            "@SP",
            "AM=M-1",
            "D=M",
            "A=A-1",
            "D=M-D",
            f"@{true_label}",
            f"D;{jump}",
            "@SP",
            "A=M-1",
            "M=0",
            f"@{end_label}",
            "0;JMP",
            f"({true_label})",
            "@SP",
            "A=M-1",
            "M=-1",
            f"({end_label})",
        ]

    def write_push(self, segment, index, file_name):
        if segment == "constant":
            return [f"@{index}", "D=A"] + self.push_d()

        if segment in SEGMENT_BASE:
            return [
                f"@{SEGMENT_BASE[segment]}",
                "D=M",
                f"@{index}",
                "A=D+A",
                "D=M",
            ] + self.push_d()

        if segment == "temp":
            return [f"@{5 + int(index)}", "D=M"] + self.push_d()

        if segment == "pointer":
            return [f"@{'THIS' if index == '0' else 'THAT'}", "D=M"] + self.push_d()

        if segment == "static":
            return [f"@{file_name}.{index}", "D=M"] + self.push_d()

        raise ValueError(segment)

    def write_pop(self, segment, index, file_name):
        if segment in SEGMENT_BASE:
            return [
                f"@{SEGMENT_BASE[segment]}",
                "D=M",
                f"@{index}",
                "D=D+A",
                "@R13",
                "M=D",
            ] + self.pop_to_d() + [
                "@R13",
                "A=M",
                "M=D",
            ]

        if segment == "temp":
            return self.pop_to_d() + [f"@{5 + int(index)}", "M=D"]

        if segment == "pointer":
            return self.pop_to_d() + [f"@{'THIS' if index == '0' else 'THAT'}", "M=D"]

        if segment == "static":
            return self.pop_to_d() + [f"@{file_name}.{index}", "M=D"]

        raise ValueError(segment)