当前位置

网站首页> 程序设计 > 开源项目 > 程序开发 > 浏览文章

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

作者:小梦 来源: 网络 时间: 2024-01-13 阅读:

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

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

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

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

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

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

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

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

# _*_ coding: utf-8 _*_import sysimport osimport globclass C_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 programif 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)

热点阅读

网友最爱