コンパイラ作成(42) for文
今回の目標
今回はfor文。
// for文 int main() { int i; puts("start"); for(i = 0; i < 5; i = i + 1) { printf("%d * %d = %d\n",i,i,i*i); } puts("end"); return 0; }
前回のwhile文から書き直しただけ。
statement
修正はここだけ。
elsif kind == TK::RESERVE && str == "for" then # while文の処理 @labelcnt += 1 cond_label = ".LBB_" + @funcname + "_" + @labelcnt.to_s @labelcnt += 1 cont_label = ".LBB_" + @funcname + "_" + @labelcnt.to_s @labelcnt += 1 body_label = ".LBB_" + @funcname + "_" + @labelcnt.to_s @labelcnt += 1 exit_label = ".LBB_" + @funcname + "_" + @labelcnt.to_s kind, str = @lex.gettoken if kind != TK::SYMBOL || str != "(" then perror end kind, str = @lex.gettoken if kind != TK::SYMBOL || str != ";" then kind, str = expr kind, str end if kind != TK::SYMBOL || str != ";" then perror end codegen cond_label + ":" kind, str = @lex.gettoken if kind != TK::SYMBOL || str != ";" then kind, str = expr kind, str codegen " jz " + exit_label end codegen " jmp " + body_label if kind != TK::SYMBOL || str != ";" then perror end codegen cont_label + ":" kind, str = @lex.gettoken if kind != TK::SYMBOL || str != ")" then kind, str = expr kind, str end if kind != TK::SYMBOL || str != ")" then perror end codegen " jmp " + cond_label codegen body_label + ":" kind, str = @lex.gettoken if kind == TK::SYMBOL && str == "{" then kind, str = @lex.gettoken loop do kind, str = statement kind, str if kind == TK::SYMBOL && str == "}" then kind, str = @lex.gettoken break end end else kind, str = statement kind, str end codegen " jmp " + cont_label codegen exit_label + ":" return kind, str
while文とだいたい同じだけど、for文は括弧の中の式が省略可能だから、それに対応してるよ。これでfor(;;)みたいなのもコンパイルできるはず。
動作テスト
動かしてみるよ。
~/myc$ myc n8.myc ~/myc$ ./n8 start 0 * 0 = 0 1 * 1 = 1 2 * 2 = 4 3 * 3 = 9 4 * 4 = 16 end ~/myc$
大丈夫だね。続けてもういっちょやってみる。
// for文 int main() { int i = 0, square; for(;;) { square = i * i; if(square >= 150) goto ex; printf("%2d * %2d = %3d\n",i,i,square); i = i + 1; } ex: return 0; }
無限ループの場合。
~/myc$ myc n9.myc ~/myc$ ./n9 0 * 0 = 0 1 * 1 = 1 2 * 2 = 4 3 * 3 = 9 4 * 4 = 16 5 * 5 = 25 6 * 6 = 36 7 * 7 = 49 8 * 8 = 64 9 * 9 = 81 10 * 10 = 100 11 * 11 = 121 12 * 12 = 144 ~/myc$
これも問題ないね。割とサクッとできたよ。でさ、n9.myc見てるとbreakしたくなる。でもbreakってちょっと難しいのかな。今、ループの中にいるのかどうかとか状態を持たないとダメか。多重ループとか考えると面倒だな。ループの中にいないときbreakしたらどうなるのかな。コンパイルエラーかな。こんなことしたことないから分からないなあ。そういやbreakで多重ループを一気に抜けられる言語もあるよね。Javaだったかな。色々調べてみるか。