[From Nand to Tetris]第8章仮想マシンプロジェクトpython実装


[From Nand to Tetris]第8章仮想マシンプロジェクトpython実装
暇を防ぐためにここまでぶらぶらしている視聴者は、From Nand to Tetrisはオンライン課程で、学生がNand論理ゲートから最初から最後までコンピュータシステムを完成させることを指導することを目標としています.
チップ-ハードウェア-コンパイル原理-オペレーティングシステム-アプリケーション->
ここで提供したのは第8章の宿題で、途中で穴に落ちた学生たちに支えてもらいます.の
先生は确かに答えを拡散することを望んでいませんが、私がやっている过程で多くの穴に出会って、半日后にすべて脳障害の原因であることを発见して、本当に时間を浪費して、殻の学生达が効率を増進することを目的として适切に答えを参考にすることができることを望んでいます.结局このようなものを学んで、手があるかどうか自分で知っています..
注釈は多くありません.コードはself-explanatoryに相当するので、本の中のもので、自由に何も発揮できません.
もしあなたがぶらぶらして入ってきて、この内容に興味があれば、上のコースのリンクを強くお勧めします.私は本当にこの授業が大好きです.私の安利を受け取ってください.の
第6章の作業解答:第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)