コンパイラ作成(8) 複数の文
前回の続きで組み込み関数printのチェック。まずはコンパイル結果のアセンブリコードを見てみるよ。
.intel_syntax noprefix .global main main: mov rdi, 42 call print ret
うんうん、ちゃんと思った通りのコードが出力されてる。次はもうちょっと複雑なプログラムのコンパイル行ってみるよ。
main() { print(123); print(456); }
複雑って言ってもprintが二つあるだけだけどね。
~/myc$ ./myc.rb c2.myc ~/myc$ clang-5.0 c2.s print.o -o c2 ~/myc$ ./c2 123 ~/myc$
あれ、一個しか表示されないよ。
.intel_syntax noprefix .global main main: mov rdi, 123 call print ret
うーむ、一個分しか出力されてない。複数の文に対応したはずなのになあ。あ、statementメソッドでtrueを返すところで間違えてfalseを返してる。これが原因か。
def statement() kind, str = @lex.gettoken if kind == TK::SYMBOL && str == "}" then return false end if kind == TK::ID && str == "return" then # return文の処理 kind, str = @lex.gettoken if kind == TK::NUMBER then codegen " mov rax, "+str codegen " ret" end kind, str = @lex.gettoken if kind == TK::SYMBOL && str == ";" then return true end perror "expected ';' after return statement" return true; elsif kind == TK::ID && str == "print" then # 組み込み関数printの処理 kind, str = @lex.gettoken if kind != TK::SYMBOL || str != "(" then perror end kind, str = @lex.gettoken if kind == TK::NUMBER then codegen " mov rdi, "+str codegen " call print" end kind, str = @lex.gettoken if kind != TK::SYMBOL || str != ")" then perror end kind, str = @lex.gettoken if kind == TK::SYMBOL && str == ";" then return true end perror "expected ';' after builtin function" return true; end perror return true; end
二か所修正した。
~/myc$ ./myc.rb c2.myc ~/myc$ clang-5.0 c2.s print.o -o c2 ~/myc$ ./c2 123 456 ~/myc$
おお、print二個分ちゃんと表示された。
やっぱりちょっと機能拡張したら十分にテストをしないと駄目だね。どんどこ先へ進めたいんだけどさ。