コンパイラ作成(15) 簡単な式
Clang先輩
まずはClangのアセンブリコードでお勉強。
.text .intel_syntax noprefix .file "i4.myc" .globl main # -- Begin function main .p2align 4, 0x90 .type main,@function main: # @main # BB#0: push rbp mov rbp, rsp sub rsp, 16 mov edi, 79 mov al, 0 call print mov edi, 1504 mov dword ptr [rbp - 4], eax # 4-byte Spill mov al, 0 call print xor edi, edi mov dword ptr [rbp - 8], eax # 4-byte Spill mov eax, edi add rsp, 16 pop rbp ret .Lfunc_end0: .size main, .Lfunc_end0-main # -- End function .ident "clang version 5.0.1-4 (tags/RELEASE_501/final)" .section ".note.GNU-stack","",@progbits
ありゃ、最適化されっちゃってる。これじゃ参考にならないなあ。しょうがないんで自力で頑張るよ。
Lexerクラス
まずLexerクラスのTK::SYMBOLのところに”*”を追加。前回の”:”の追加とおんなじ感じ。
組込関数print
以前作ったprintの処理を修正して式を書けるようにするよ。
elsif kind == TK::ID && str == "print" then # 組み込み関数printの処理 kind, str = @lex.gettoken if kind != TK::SYMBOL || str != "(" then perror end kind, str = @lex.gettoken expr kind, str codegen " mov edi, eax" codegen " call print" kind, str = @lex.gettoken if kind == TK::SYMBOL && str == ";" then return true end perror "expected ';' after builtin function" return true;
exprってのが式の処理をしてくれるメソッド。eaxに計算結果を入れるようコード生成してる。
expr
exprの中身はこんな感じ。
# 式の構文解析 def expr(fkind,fstr) kind, str = @lex.gettoken if kind == TK::SYMBOL && str == ";" then expr2 fkind,fstr,kind,str return true elsif kind == TK::SYMBOL && str == "+" then expr2 fkind,fstr,kind,str return true elsif kind == TK::SYMBOL && str == "*" then expr2 fkind,fstr,kind,str return true end end # 式の構文解析 def expr2(fkind,fstr,skind,sstr) if fkind == TK::NUMBER then codegen " mov eax, " + fstr if skind == TK::SYMBOL && sstr == ";" then return elsif skind == TK::SYMBOL && sstr == "+" then kind, str = @lex.gettoken if kind == TK::NUMBER then codegen " add eax, " + str end kind, str = @lex.gettoken if kind == TK::SYMBOL && str == ";" then return end if kind == TK::SYMBOL && str == ")" then return end perror "expected ';' after expr" elsif skind == TK::SYMBOL && sstr == "*" then kind, str = @lex.gettoken if kind == TK::NUMBER then codegen " mov ebx, " + str codegen " mul ebx" end kind, str = @lex.gettoken if kind == TK::SYMBOL && str == ";" then return end if kind == TK::SYMBOL && str == ")" then return end perror "expected ';' after expr" end end end
動作チェック
コーディングできたんで早速テストしてみる。
~/myc$ ./myc.rb i5.myc ~/myc$ clang-5.0 i5.s print.o -o i5 ~/myc$ ./i5 79 1504 ~/myc$
お、動いた。
問題点
これで一番単純な式の処理はできるようになったよ。でも今回のコーディングはイマイチかな。
- 複雑な式への拡張ができるか
- エラー処理が不十分
- レジスタの使い方に問題はないか
この記事書きながらプログラム見てたらやっぱり色々拙いような気がしてきた。式の処理だけはしっかりやらないと駄目だよなあ。もう一回考え直そう。