前提・実現したいこと
コンピュータシステムの理論と実装を学習中です。現在8章でVM変換器をPythonで実装しようとしています。以下コードの一部です。
python
1## f_parser.py 2import re 3 4class Parser(): 5 def __init__(self, i_stream): 6 self.stream = i_stream 7 self.line_now = '\n' 8 self.commands = None 9 self.match_obj = None 10 self.command_type = None 11 self.comment = None 12 self.command_reg = re.compile('([a-zA-Z]+)?\s?([a-zA-Z0-9]+)?\s?([a-zA-Z0-9]+)?\s?(^(//){1}.*)?\s?') 13 14 self.command_dict = {'add': 'C_ARITHMETRIC', 15 'sub': 'C_ARITHMETRIC', 16 'neg': 'C_ARITHMETRIC', 17 'eq': 'C_ARITHMETRIC', 18 'gt': 'C_ARITHMETRIC', 19 'lt': 'C_ARITHMETRIC', 20 'and': 'C_ARITHMETRIC', 21 'or': 'C_ARITHMETRIC', 22 'not': 'C_ARITHMETRIC', 23 'push': 'C_PUSH', 24 'pop': 'C_POP', 25 'label': 'C_LABEL', 26 'goto': 'C_GOTO', 27 'if-goto' : 'C_IF', 28 'function' : 'C_FUNCTION', 29 'return': 'C_RETURN', 30 'call': 'C_CALL'} 31 32 33 def __del__(self): 34 self.stream.close() 35 36 37 def hasMoreCommands(self): 38 return self.line_now != '' 39 40 def advance(self): 41 self.line_now = self.stream.readline() 42 43 def commandType(self): 44 self.match_obj = self.command_reg.match(self.line_now) 45 self.commands = [self.match_obj.group(1), 46 self.match_obj.group(2), 47 self.match_obj.group(3), 48 self.match_obj.group(4)] 49 50 self.command_type = self.command_dict.get(self.commands[0]) 51 return self.command_type 52 53 54 def get_arg1(self): 55 if self.command_type == 'C_ARITHMETRIC': 56 return self.commands[0] 57 else: 58 return self.commands[1] 59 60 61 def get_arg2(self): 62 if self.command_type in ['C_PUSH', 'C_POP', 'C_FUNCTION', 'C_CALL']: 63 return self.commands[2] 64 else: 65 return None 66 67
実現したいことは、push constant 2 のようなVMコードをパースして以下のような関数に投げて処理がしたいです。
python
1 2## code_writer.py 3 4def writePush(self, arg1, arg2): 5 if arg1 == 'static': 6 address = ['@' + self.filename + '.' + arg2] 7 process = ['D=M'] 8 9 elif arg1 == 'constant': 10 address = ['@' + str(self.mapping.get(arg1) + int(arg2))] 11 process = ['D=A'] 12 13 elif arg1 in ['pointer', 'temp']: 14 address = ['@' + str(self.mapping.get(arg1))] 15 process = ['A=M' ,'A=A+{0}'.format(arg2), 'D=M'] 16 17 elif arg1 in ['local', 'argument', 'this', 'that']: 18 address = ['@' + self.mapping.get(arg1)] 19 process = ['A=M', 'A=A+{0}'.format(arg2), 'D=M'] 20 21 22 command = '\n'.join(address + process) 23 self.o_stream.write(command)
get_arg1,get_arg2はf_parser.pyに記述されています。やりたい処理は同じディレクトリ内のcode_writer.pyに書いてあります。実際にはWritePush()は、vm_translator.pyというファイル(これも同じディレクトリ内)でVM_Translatorクラスのメソッド内の処理として呼び出されています。
python
1# vm_translator.py 2 3import f_parser 4import code_writer 5 6 7class VM_Translator(): 8 def __init__(self, dir, filename): 9 self.dir = dir 10 self.filename = filename 11 self.i_stream = open(dir+'/'+filename + '.vm', 'r') 12 self.parser = f_parser.Parser(self.i_stream) 13 self.codeWriter = code_writer.codeWriter(self.dir, self.filename, self.parser) 14 15 def Translate(self): 16 while self.parser.hasMoreCommands(): 17 self.parser.advance() 18 19 line_now = self.parser.line_now 20 command_type = self.parser.commandType() 21 22 if command_type == None: 23 continue 24 25 if command_type == 'C_PUSH': 26 arg1 = self.parser.get_arg1 27 arg2 = self.parser.get_arg2 28 self.codeWriter.writePush(arg1, arg2) 29 30 if command_type == 'C_POP': 31 arg1 = self.parser.get_arg1 32 arg2 = self.parser.get_arg2 33 self.codeWriter.writePop(arg1, arg2) 34 35 if command_type == 'C_ARITHMETRIC': 36 command = self.parser.get_arg1() 37 self.codeWriter.writeArithmetric(command) 38 39 else: 40 print('Finish VM translation.') 41 42
起きていること
始めに示したクラスのget_arg1,get_arg2メソッドでarg1とarg2を取得して処理しようとしましたが、以下のエラーが返ってきました。
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "~~~~\vm_translator.py", line 26, in Translate self.codeWriter.writePush(arg1, arg2) File "~~~~\code_writer.py", line 53, in writePush command = '\n'.join(address + process) UnboundLocalError: local variable 'address' referenced before assignment
さらに、arg1とarg2の中身を確認すると
<bound method Parser.get_arg1 of <f_parser.Parser object at 0x0000023461595CD0>>
となっており、型としてstringを期待しているのにParserクラスのオブジェクトとして表示されています。エラー自体はget_argの戻り値がどのif文にも引っかからなかったことが原因です(さらにそのような場合のケアもしていない)。get_argメソッドの戻り値をarg1 == 'static'のような条件分岐に引っ掛けるにはどうすればよいでしょうか?クラス定義と継承あたりの基本事項と思われますが、どうぞ宜しくお願いします。
回答1件
あなたの回答
tips
プレビュー