コンパイラ作成(7) 組み込み関数print
return文一個のプログラムのコンパイルはできるようになったんで、もうちょっと複雑なのに挑戦するよ。さて何にするかな。式の評価?よくあるコンパイラの解説とかだと大体式の評価をやってるけど、式の構文解析とか難しそうだから違うことにしよ。
main()
{
print(42);
}
ちょっと考えて今回はこれをコンパイルすることにしたよ。本当はprintfを呼べばいいんだけどハードル高いんで諦めた。
main() { printf("%d\n",42); }
これだと文字列リテラルとか出てきちゃうし、いきなり引数2個だし、そもそもprintfは不定個の引数受け付ける関数だもん。これを一気にやるのは厳しいよね。ってことで謎の組み込み関数printの登場。
#include <stdio.h> void print(int n) { printf("%d\n",n); }
組み込み関数の実態はcで作った。で、前回つくったParserクラスのstatementメソッドに組み込み関数の処理を追加。
# 文の構文解析 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 false 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 false end perror "expected ';' after builtin function" return true; end perror return true; end
さてどうだ?
~/myc$ cat c.myc main() { print(42); } ~/myc$ ./myc.rb c.myc ~/myc$ clang-5.0 c.s print.o -o c ~/myc$ ./c 42 ~/myc$
お、うまくできた。