コンパイラ作成(41) while文
今回の目標
久々に機能追加。
// while文 int main() { int i = 0; puts("start"); while(i < 5) { printf("%d * %d = %d\n",i,i,i*i); i = i + 1; } puts("end"); return 0; }
while文だよ。if文とそんなに変わらないんで簡単にできると思うよ。
statement
今回の修正はここだけ。
elsif kind == TK::RESERVE && str == "while" then # while文の処理 @labelcnt += 1 cond_label = ".LBB_" + @funcname + "_" + @labelcnt.to_s @labelcnt += 1 exit_label = ".LBB_" + @funcname + "_" + @labelcnt.to_s codegen cond_label + ":" kind, str = @lex.gettoken if kind != TK::SYMBOL || str != "(" then perror end kind, str = @lex.gettoken kind, str = expr kind, str if kind != TK::SYMBOL || str != ")" then perror end codegen " jz " + exit_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 " + cond_label codegen exit_label + ":" return kind, str
やってることはif文とだいたい同じ。
動作テスト
どうかな。
~/myc$ myc n4.myc ~/myc$ ./n4 start 0 * 0 = 0 1 * 1 = 1 2 * 2 = 4 3 * 3 = 9 4 * 4 = 16 end ~/myc$
動いたよ。もうちょっと複雑なのもテストしてみる。whileを入子にして九九の表を出力してみるよ。
// while文 int main() { int i = 1, j; while(i <= 9) { j = 1; while(j <= 9) { printf("%2d ",i*j); j = j + 1; } printf("\n"); i = i + 1; } return 0; }
どうかな。
~/myc$ myc n7.myc ~/myc$ ./n7 1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81 ~/myc$
できた。これで大分C言語っぽくなってきたよ。ちなみに今myc.rbは840行だよ。次はfor文か。while文よりちょっと複雑だけどなんとかなるかな。
あ、そだ今回のコーディングだとif文と同じでwhile(1)みたいな場合上手くいかないよ。これも宿題だな。