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