← SEARCHABLE ARCHIVE
Nand2Tetris · 2026-05-22

Nand2Tetris — 第 11 章

Jack 編譯器

INTERACTIVE READING MODE →

# Jack Compiler
# 輸入:.jack 文件
# 輸出:.vm 文件
# 範圍:符號表+VM程式碼生成
# 移動:
# 分別管理類別/靜態/字段符號和子程序/本地/參數符號,
# 將 let、do、return 和 expression 轉換為 VM 指令


class SymbolTable:
    def __init__(self):
        self.class_scope = {}
        self.subroutine_scope = {}
        self.counts = {"static": 0, "field": 0, "argument": 0, "var": 0}

    def start_subroutine(self):
        self.subroutine_scope = {}
        self.counts["argument"] = 0
        self.counts["var"] = 0

    def define(self, name, type_name, kind):
        index = self.counts[kind]
        self.counts[kind] += 1

        symbol = {
            "type": type_name,
            "kind": kind,
            "index": index,
        }

        if kind in ("static", "field"):
            self.class_scope[name] = symbol
        else:
            self.subroutine_scope[name] = symbol

    def var_count(self, kind):
        return self.counts[kind]

    def find(self, name):
        if name in self.subroutine_scope:
            return self.subroutine_scope[name]
        return self.class_scope.get(name)


class VMWriter:
    SEGMENT = {
        "static": "static",
        "field": "this",
        "argument": "argument",
        "var": "local",
    }

    def __init__(self):
        self.lines = []

    def write_push(self, segment, index):
        self.lines.append(f"push {segment} {index}")

    def write_pop(self, segment, index):
        self.lines.append(f"pop {segment} {index}")

    def write_arithmetic(self, command):
        self.lines.append(command)

    def write_label(self, label):
        self.lines.append(f"label {label}")

    def write_goto(self, label):
        self.lines.append(f"goto {label}")

    def write_if(self, label):
        self.lines.append(f"if-goto {label}")

    def write_call(self, name, arg_count):
        self.lines.append(f"call {name} {arg_count}")

    def write_function(self, name, local_count):
        self.lines.append(f"function {name} {local_count}")

    def write_return(self):
        self.lines.append("return")


class CompilerExample:
    def __init__(self):
        self.symbols = SymbolTable()
        self.vm = VMWriter()

    def write_variable_push(self, name):
        symbol = self.symbols.find(name)
        segment = VMWriter.SEGMENT[symbol["kind"]]
        self.vm.write_push(segment, symbol["index"])

    def write_variable_pop(self, name):
        symbol = self.symbols.find(name)
        segment = VMWriter.SEGMENT[symbol["kind"]]
        self.vm.write_pop(segment, symbol["index"])

    def compile_let_simple(self, name):
        # let name = expression;
        # 假設表達式結果位於棧頂,將其彈出到變數位置
        self.write_variable_pop(name)

    def compile_do_call(self, full_name, arg_count):
        # 進行函數呼叫; 不使用回傳值,因此temp被丟棄為0。
        self.vm.write_call(full_name, arg_count)
        self.vm.write_pop("temp", 0)

    def compile_return_void(self):
        self.vm.write_push("constant", 0)
        self.vm.write_return()
//傑克的代碼:令x = 10 + 20;
//VM 轉換範例
push constant 10
push constant 20
add
pop local 0
//Jack程式碼:do Output.printInt(x);
//VM 轉換範例
push local 0
call Output.printInt 1
pop temp 0