爲防閒逛至此的看官不知所云: From Nand to Tetris 是一個在線課程,目標是指導學生從 Nand 邏輯門開始從頭至尾完成一整套計算機系統。python
好像擼串同樣的爽快:------芯片--硬件---編譯原理---操做系統---應用程序------>segmentfault
這裏提供的是第八章的做業,以供半路摔進坑裏的同窗們扶一下。。。函數
人家老師確實是不但願擴散答案,不過我作的過程當中遇到不少坑,搞半天后發現全是些腦殘緣由,實在是浪費時間,但願卡殼的同窗們能以增進效率爲目的適當參考答案。畢竟學習這種東西,有沒有學到手只有本身知道。。。學習
註釋很少,由於代碼至關 self-explanatory ,就是書上那些,沒自由發揮什麼。網站
若是你是閒逛進來,並且對這塊內容有興趣的話,強烈建議點開上面的課程連接試試,我是真心很是喜歡這門課,請收下個人安利。。。this
另外還有第六章的做業答案:第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)