资讯专栏INFORMATION COLUMN

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

alphahans / 1808人阅读

摘要:第章虚拟机项目实现为防闲逛至此的看官不知所云是一个在线课程,目标是指导学生从逻辑门开始从头到尾完成一整套计算机系统。好像撸串一样的爽快芯片硬件编译原理操作系统应用程序这里提供的是第八章的作业,以供半路摔进坑里的同学们扶一下。。。

[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 == "
" 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
M=M-1
A=M
D=M
@SP
M=M-1
A=M
M=M+D
@SP
M=M+1
")
        elif command == "sub":
            self.foutput.write("@SP
M=M-1
A=M
D=M
@SP
M=M-1
A=M
M=M-D
@SP
M=M+1
")
        elif command == "neg":
            self.foutput.write("@SP
M=M-1
A=M
M=-M
@SP
M=M+1
")
        elif command == "eq":
            self.foutput.write("@SP
M=M-1
A=M
D=M
@SP
M=M-1
A=M
D=M-D
@RET_TRUE"+str(self.uniqueFlag)+"
"
                               "D;JEQ
D=0
@END"+str(self.uniqueFlag)+"
0;JMP
(RET_TRUE"+str(self.uniqueFlag)+")
"
                               "D=-1
(END"+str(self.uniqueFlag)+")
@SP
A=M
M=D
@SP
M=M+1
")
            self.uniqueFlag += 1
        elif command == "gt":
            self.foutput.write("@SP
M=M-1
A=M
D=M
@SP
M=M-1
A=M
D=M-D
@RET_TRUE"+str(self.uniqueFlag)+"
"
                               "D;JGT
D=0
@END"+str(self.uniqueFlag)+"
0;JMP
(RET_TRUE"+str(self.uniqueFlag)+")
"
                               "D=-1
(END"+str(self.uniqueFlag)+")
@SP
A=M
M=D
@SP
M=M+1
")
            self.uniqueFlag += 1
        elif command == "lt":
            self.foutput.write("@SP
M=M-1
A=M
D=M
@SP
M=M-1
A=M
D=M-D
@RET_TRUE"+str(self.uniqueFlag)+"
"
                               "D;JLT
D=0
@END"+str(self.uniqueFlag)+"
0;JMP
(RET_TRUE"+str(self.uniqueFlag)+")
"
                               "D=-1
(END"+str(self.uniqueFlag)+")
@SP
A=M
M=D
@SP
M=M+1
")
            self.uniqueFlag += 1
        elif command == "and":
            self.foutput.write("@SP
M=M-1
A=M
D=M
@SP
M=M-1
A=M
M=M&D
@SP
M=M+1
")
        elif command == "or":
            self.foutput.write("@SP
M=M-1
A=M
D=M
@SP
M=M-1
A=M
M=M|D
@SP
M=M+1
")
        elif command == "not":
            self.foutput.write("@SP
M=M-1
A=M
M=!M
@SP
M=M+1
")

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

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

    def write_init(self):
        self.foutput.write("@256
D=A
@SP
M=D
")
        self.write_call("Sys.init", 0)

    def write_goto(self, label):
        self.foutput.write("@"+self.currentFunc+"$"+label+"
0;JMP
")

    def write_if(self, label):
        self.foutput.write("@SP
M=M-1
A=M
D=M
@"+self.currentFunc+"$"+label+"
D;JNE
")

    def write_call(self, function_name, num_args):
        self.foutput.write("@RETURN_ADDRESS"+str(self.uniqueFlag)+"
D=A
@SP
A=M
M=D
@SP
M=M+1
"
                           "@LCL
D=M
@SP
A=M
M=D
@SP
M=M+1
"
                           "@ARG
D=M
@SP
A=M
M=D
@SP
M=M+1
"
                           "@THIS
D=M
@SP
A=M
M=D
@SP
M=M+1
"
                           "@THAT
D=M
@SP
A=M
M=D
@SP
M=M+1
"
                           "@SP
D=M
@"+str(int(num_args)+5)+"
D=D-A
@ARG
M=D
"
                           "@SP
D=M
@LCL
M=D
"
                           "@"+function_name+"
0;JMP
"
                           "(RETURN_ADDRESS"+str(self.uniqueFlag)+")
")
        self.uniqueFlag += 1

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

    def write_function(self, function_name, num_locals):
        self.currentFunc = function_name
        commandsInitLocals = ""
        for i in range(int(num_locals)):
            commandsInitLocals += "@LCL
D=M
@"+str(i)+"
A=A+D
M=0
"
        self.foutput.write("("+function_name+")
"+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)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/45396.html

相关文章

  • [Coursera][From Nand to Tetris / Part I] 六周 汇编器项目

    摘要:今天折腾一上午,终于完成了上这个课程的最后一个汇编器项目。这套课程真是没白跟,收获良多,现在已经等不及想看下一期的软件部分了,哈哈。 今天折腾一上午,终于 完成了 Coursera 上 From Nand to Tetris / Part I 这个课程的最后一个汇编器项目。这套课程真是没白跟,收获良多,现在已经等不及想看下一期的软件部分了,哈哈。 下面是我的 python 实现,存个...

    Taste 评论0 收藏0
  • 基于ARM处理器的U-BOOT详细移植总结

    摘要:作用是将标准输入中的所有大写字母转换为响应的小写字母。的移植过的源代码是在源代码目录下编译的,所以源代码目录等于目标文件目录,所以条件不满足,将执行分支的代码。         一个嵌入式产品的开发阶段,需要不断地把bootloader下载到存储器中,如果存储器使用nand flash,但是...

    zengdongbao 评论0 收藏0
  • 流畅的python读书笔记-11-接口:从协议到抽象基类

    摘要:自己定义的抽象基类要继承。抽象基类可以包含具体方法。这里想表达的观点是我们可以偷懒,直接从抽象基类中继承不是那么理想的具体方法。 抽象基类 抽象基类的常见用途: 实现接口时作为超类使用。 然后,说明抽象基类如何检查具体子类是否符合接口定义,以及如何使用注册机制声明一个类实现了某个接口,而不进行子类化操作。 如何让抽象基类自动识别任何符合接口的类——不进行子类化或注册。 接口在动态类...

    Kyxy 评论0 收藏0
  • 《深入理解Java虚拟》(二)Java虚拟运行时数据区

    摘要:虚拟机运行时数据区分为以下几个部分。程序计数器也是在虚拟机规范中唯一没有规定任何异常情况的区域。在方法运行期间不会改变局部变量表的大小。长度在位和位的虚拟机中,分别为官方称它为。 Java虚拟机运行时数据区 详解 2.1 概述 本文参考的是周志明的 《深入理解Java虚拟机》第二章 ,为了整理思路,简单记录一下,方便后期查阅。 2.2 运行时数据区域 Java虚拟机在Java程序运行时...

    draveness 评论0 收藏0
  • ApacheCN 人工智能知识树 v1.0

    摘要:贡献者飞龙版本最近总是有人问我,把这些资料看完一遍要用多长时间,如果你一本书一本书看的话,的确要用很长时间。为了方便大家,我就把每本书的章节拆开,再按照知识点合并,手动整理了这个知识树。 Special Sponsors showImg(https://segmentfault.com/img/remote/1460000018907426?w=1760&h=200); 贡献者:飞龙版...

    刘厚水 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<