[From Nand to Tetris] 第8章 虚拟机项目 python 实现
admin
2023-07-31 01:53:03
0

[From Nand to Tetris] 第8章 虚拟机项目 python 实现

为防闲逛至此的看官不知所云: From Nand to Tetris 是一个在线课程,目标是指导学生从 Nand 逻辑门开始从头到尾完成一整套计算机系统

好像撸串一样的爽快:——芯片–硬件—编译原理—操作系统—应用程序——>

这里提供的是第八章的作业,以供半路摔进坑里的同学们扶一下。。。

人家老师确实是不希望扩散答案,不过我做的过程中遇到很多坑,搞半天后发现全是些脑残原因,实在是浪费时间,希望卡壳的同学们能以增进效率为目的适当参考答案。毕竟学习这种东西,有没有学到手只有自己知道。。。

注释不多,因为代码相当 self-explanatory ,就是书上那些,没自由发挥什么。

如果你是闲逛进来,而且对这块内容有兴趣的话,强烈建议点开上面的课程链接试试,我是真心非常喜欢这门课,请收下我的安利。。。

另外还有第六章的作业答案:第6章 汇编器项目 python 实现

# _*_ coding: utf-8 _*_

import sys
import os
import glob


class C_TYPE:
    \'\'\'Command Type\'\'\'
    C_ARITHMETIC, C_PUSH, C_POP, C_LABEL, C_GOTO, C_IF, C_FUNCTION, C_RETURN, C_CALL = range(9)


class Parser:

    def __init__(self, fname):
        self.finput = open(fname, \'rU\')
        self.current = None
        self.commandPart = []
        self.cType = -1

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.finput.close()

    def has_more_commands(self):

        self.current = self.finput.readline()

        while self.current == \'\\n\' or self.current[:2] == \'//\':
            self.current = self.finput.readline()

        return self.current != \'\'

    def advance(self):
        self.commandPart = self.current.strip().split(\' \')[:3]

        if self.commandPart[0] == \'add\' or\\
                self.commandPart[0] == \'sub\' or\\
                self.commandPart[0] == \'neg\' or\\
                self.commandPart[0] == \'eq\' or\\
                self.commandPart[0] == \'gt\' or\\
                self.commandPart[0] == \'lt\' or\\
                self.commandPart[0] == \'and\' or\\
                self.commandPart[0] == \'or\' or\\
                self.commandPart[0] == \'not\':
            self.cType = C_TYPE.C_ARITHMETIC
        elif self.commandPart[0] == \'push\':
            self.cType = C_TYPE.C_PUSH
        elif self.commandPart[0] == \'pop\':
            self.cType = C_TYPE.C_POP
        elif self.commandPart[0] == \'label\':
            self.cType = C_TYPE.C_LABEL
        elif self.commandPart[0] == \'goto\':
            self.cType = C_TYPE.C_GOTO
        elif self.commandPart[0] == \'if-goto\':
            self.cType = C_TYPE.C_IF
        elif self.commandPart[0] == \'function\':
            self.cType = C_TYPE.C_FUNCTION
        elif self.commandPart[0] == \'call\':
            self.cType = C_TYPE.C_CALL
        elif self.commandPart[0] == \'return\':
            self.cType = C_TYPE.C_RETURN

    def command_type(self):
        return self.cType

    def arg1(self):
        if self.command_type() == C_TYPE.C_ARITHMETIC:
            return self.commandPart[0]
        return self.commandPart[1]

    def arg2(self):
        return self.commandPart[2]


class CodeWriter:

    def __init__(self, fname):
        self.foutput = open(fname, \'w\')
        self.uniqueFlag = 0  # 用于构造唯一的标签,每次使用后加1
        self.currentFile = \'\' # 当前处理的文件的名字
        self.currentFunc = \'\' # 当前处理的函数的名字

    def set_file_name(self, fname):
        self.currentFile = fname

    def write_arithmetic(self, command):
        if command == \'add\':
            self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nD=M\\n@SP\\nM=M-1\\nA=M\\nM=M+D\\n@SP\\nM=M+1\\n\')
        elif command == \'sub\':
            self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nD=M\\n@SP\\nM=M-1\\nA=M\\nM=M-D\\n@SP\\nM=M+1\\n\')
        elif command == \'neg\':
            self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nM=-M\\n@SP\\nM=M+1\\n\')
        elif command == \'eq\':
            self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nD=M\\n@SP\\nM=M-1\\nA=M\\nD=M-D\\n@RET_TRUE\'+str(self.uniqueFlag)+\'\\n\'
                               \'D;JEQ\\nD=0\\n@END\'+str(self.uniqueFlag)+\'\\n0;JMP\\n(RET_TRUE\'+str(self.uniqueFlag)+\')\\n\'
                               \'D=-1\\n(END\'+str(self.uniqueFlag)+\')\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\')
            self.uniqueFlag += 1
        elif command == \'gt\':
            self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nD=M\\n@SP\\nM=M-1\\nA=M\\nD=M-D\\n@RET_TRUE\'+str(self.uniqueFlag)+\'\\n\'
                               \'D;JGT\\nD=0\\n@END\'+str(self.uniqueFlag)+\'\\n0;JMP\\n(RET_TRUE\'+str(self.uniqueFlag)+\')\\n\'
                               \'D=-1\\n(END\'+str(self.uniqueFlag)+\')\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\')
            self.uniqueFlag += 1
        elif command == \'lt\':
            self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nD=M\\n@SP\\nM=M-1\\nA=M\\nD=M-D\\n@RET_TRUE\'+str(self.uniqueFlag)+\'\\n\'
                               \'D;JLT\\nD=0\\n@END\'+str(self.uniqueFlag)+\'\\n0;JMP\\n(RET_TRUE\'+str(self.uniqueFlag)+\')\\n\'
                               \'D=-1\\n(END\'+str(self.uniqueFlag)+\')\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\')
            self.uniqueFlag += 1
        elif command == \'and\':
            self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nD=M\\n@SP\\nM=M-1\\nA=M\\nM=M&D\\n@SP\\nM=M+1\\n\')
        elif command == \'or\':
            self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nD=M\\n@SP\\nM=M-1\\nA=M\\nM=M|D\\n@SP\\nM=M+1\\n\')
        elif command == \'not\':
            self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nM=!M\\n@SP\\nM=M+1\\n\')

    def write_push_pop(self, command, segment, index):
        if command == C_TYPE.C_PUSH:
            if segment == \'constant\':
                self.foutput.write(\'@\'+index+\'\\nD=A\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\')
            elif segment == \'local\':
                self.foutput.write(\'@LCL\\nD=M\\n@\'+index+\'\\nA=A+D\\nD=M\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\')
            elif segment == \'argument\':
                self.foutput.write(\'@ARG\\nD=M\\n@\'+index+\'\\nA=A+D\\nD=M\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\')
            elif segment == \'this\':
                self.foutput.write(\'@THIS\\nD=M\\n@\'+index+\'\\nA=A+D\\nD=M\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\')
            elif segment == \'that\':
                self.foutput.write(\'@THAT\\nD=M\\n@\'+index+\'\\nA=A+D\\nD=M\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\')
            elif segment == \'pointer\':
                self.foutput.write(\'@\'+str(int(index)+3)+\'\\nD=M\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\')
            elif segment == \'temp\':
                self.foutput.write(\'@\'+str(int(index)+5)+\'\\nD=M\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\')
            elif segment == \'static\':
                self.foutput.write(\'@\'+self.currentFile+\'.\'+index+\'\\nD=M\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\')
        elif command == C_TYPE.C_POP:
            if segment == \'local\':
                self.foutput.write(\'@LCL\\nD=M\\n@\'+index+\'\\nD=A+D\\n@R13\\nM=D\\n@SP\\nM=M-1\\nA=M\\nD=M\\n@R13\\nA=M\\nM=D\\n\')
            elif segment == \'argument\':
                self.foutput.write(\'@ARG\\nD=M\\n@\'+index+\'\\nD=A+D\\n@R13\\nM=D\\n@SP\\nM=M-1\\nA=M\\nD=M\\n@R13\\nA=M\\nM=D\\n\')
            elif segment == \'this\':
                self.foutput.write(\'@THIS\\nD=M\\n@\'+index+\'\\nD=A+D\\n@R13\\nM=D\\n@SP\\nM=M-1\\nA=M\\nD=M\\n@R13\\nA=M\\nM=D\\n\')
            elif segment == \'that\':
                self.foutput.write(\'@THAT\\nD=M\\n@\'+index+\'\\nD=A+D\\n@R13\\nM=D\\n@SP\\nM=M-1\\nA=M\\nD=M\\n@R13\\nA=M\\nM=D\\n\')
            elif segment == \'pointer\':
                self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nD=M\\n@\'+str(int(index)+3)+\'\\nM=D\\n\')
            elif segment == \'temp\':
                self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nD=M\\n@\'+str(int(index)+5)+\'\\nM=D\\n\')
            elif segment == \'static\':
                self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nD=M\\n@\'+self.currentFile+\'.\'+index+\'\\nM=D\\n\')

    def write_label(self, label):
        self.foutput.write(\'(\'+self.currentFunc+\'$\'+label+\')\\n\') # 构造 (funcName$label) 格式的标记,网站上没提,但书里有

    def write_init(self):
        self.foutput.write(\'@256\\nD=A\\n@SP\\nM=D\\n\')
        self.write_call(\'Sys.init\', 0)

    def write_goto(self, label):
        self.foutput.write(\'@\'+self.currentFunc+\'$\'+label+\'\\n0;JMP\\n\')

    def write_if(self, label):
        self.foutput.write(\'@SP\\nM=M-1\\nA=M\\nD=M\\n@\'+self.currentFunc+\'$\'+label+\'\\nD;JNE\\n\')

    def write_call(self, function_name, num_args):
        self.foutput.write(\'@RETURN_ADDRESS\'+str(self.uniqueFlag)+\'\\nD=A\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\'
                           \'@LCL\\nD=M\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\'
                           \'@ARG\\nD=M\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\'
                           \'@THIS\\nD=M\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\'
                           \'@THAT\\nD=M\\n@SP\\nA=M\\nM=D\\n@SP\\nM=M+1\\n\'
                           \'@SP\\nD=M\\n@\'+str(int(num_args)+5)+\'\\nD=D-A\\n@ARG\\nM=D\\n\'
                           \'@SP\\nD=M\\n@LCL\\nM=D\\n\'
                           \'@\'+function_name+\'\\n0;JMP\\n\'
                           \'(RETURN_ADDRESS\'+str(self.uniqueFlag)+\')\\n\')
        self.uniqueFlag += 1

    def write_return(self):
        self.foutput.write(\'@LCL\\nD=M\\n@R13\\nM=D\\n\'
                           \'@5\\nA=D-A\\nD=M\\n@R14\\nM=D\\n\'
                           \'@SP\\nM=M-1\\nA=M\\nD=M\\n@ARG\\nA=M\\nM=D\\n\'
                           \'@ARG\\nD=M+1\\n@SP\\nM=D\\n\'
                           \'@R13\\nA=M-1\\nD=M\\n@THAT\\nM=D\\n\'
                           \'@R13\\nA=M-1\\nA=A-1\\nD=M\\n@THIS\\nM=D\\n\'  # 蠢萌蠢萌的减n次1,比下一句还省一条指令。。。
                           \'@R13\\nD=M\\n@3\\nA=D-A\\nD=M\\n@ARG\\nM=D\\n\'
                           \'@R13\\nD=M\\n@4\\nA=D-A\\nD=M\\n@LCL\\nM=D\\n\'
                           \'@R14\\nA=M\\n0;JMP\\n\')

    def write_function(self, function_name, num_locals):
        self.currentFunc = function_name
        commandsInitLocals = \'\'
        for i in range(int(num_locals)):
            commandsInitLocals += \'@LCL\\nD=M\\n@\'+str(i)+\'\\nA=A+D\\nM=0\\n\'
        self.foutput.write(\'(\'+function_name+\')\\n\'+commandsInitLocals)

    def close(self):
        self.foutput.close()


def process_vm_file(fpath):
    \'\'\'
    处理一个 .vm 文件

    fpath: 待处理 .vm 文件的绝对路径
    \'\'\'
    parser = Parser(fpath)
    writer.set_file_name(os.path.basename(fpath.strip(\'.vm\')))
    while parser.has_more_commands():
        parser.advance()
        if parser.command_type() == C_TYPE.C_PUSH or parser.command_type() == C_TYPE.C_POP:
            writer.write_push_pop(parser.command_type(), parser.arg1(), parser.arg2())
        elif parser.command_type() == C_TYPE.C_ARITHMETIC:
            writer.write_arithmetic(parser.arg1())
        elif parser.command_type() == C_TYPE.C_LABEL:
            writer.write_label(parser.arg1())
        elif parser.command_type() == C_TYPE.C_GOTO:
            writer.write_goto(parser.arg1())
        elif parser.command_type() == C_TYPE.C_IF:
            writer.write_if(parser.arg1())
        elif parser.command_type() == C_TYPE.C_CALL:
            writer.write_call(parser.arg1(), parser.arg2())
        elif parser.command_type() == C_TYPE.C_FUNCTION:
            writer.write_function(parser.arg1(), parser.arg2())
        elif parser.command_type() == C_TYPE.C_RETURN:
            writer.write_return()

# main program
if os.path.isfile(sys.argv[1]) and sys.argv[1].endswith(\'.vm\'):  # 参数为 .vm 文件,只翻译一个文件
    writer = CodeWriter(os.path.splitext(sys.argv[1])[0]+\'.asm\')
    writer.write_init()
    process_vm_file(sys.argv[1])
elif os.path.isdir(sys.argv[1]): # 参数为文件夹,将文件夹中所有文件翻译为 hack 汇编
    writer = CodeWriter(sys.argv[1]+\'/\'+os.path.basename(sys.argv[1])+\'.asm\')
    writer.write_init()
    for f in glob.glob(sys.argv[1] + \'/*.vm\'):
        process_vm_file(f)

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
项目管理和工程管理的区别 项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...