コンパイラ作成(39) バグ修正
バグ修正2件
最近バグ修正多いけどまた2件見つかっちゃったんで修正するよ。
// 関数 int main() { sub(); sub() + 10; 10 + sub(); } int sub() { puts("sub"); return 42; }
1件目は式中の関数呼出。この中のsub() + 10;がコンパイルできずに異常終了しちゃってたよ。
// 変数 int main() { int a = 10, a1 = 20, a_1 = 30, _a = 40, _ = 50; printf("%d %d %d %d %d\n",a,a1,a_1,_a,_); int b1 = 10, b12 = 20, b123 = 30; printf("%d %d %d\n",b1,b12,b123); }
2件目は数字を含んだ識別子。Lexerがちゃんと扱えてなかったよ。
codegen_elf
1件目はコード生成部がおかしかった。
# 式のコード生成(二項演算の左側被演算子) def codegen_elf(operand) if operand.kind_of?(Array) then if !operand[0].kind_of?(Array) && operand[0].kind == TK::ID && operand[1].str == "()" then codegen " call " + operand[0].str else codegen_el operand end elsif operand.kind == TK::NUMBER then codegen " mov eax, " + operand.str elsif operand.kind == TK::ID then v = @lvars[operand.str] if v == nil then perror "undeclared variable \"" + operand.str + "\"" end codegen " mov eax, dword ptr [rbp - " + v[1].to_s + "]" end end
関数呼出か判断するところの処理が意味不明のコーディングになってたよ。
Lexerクラス
2件目はここ。
# identifireの切り出し if m = @line[@idx,@line.length].match(/^[\p{alpha}|_][\p{alnum}|_]*/) then str = m.to_s @idx += str.length if @reservedword.include?(str) then return TK::RESERVE, str else return TK::ID, str end
また正規表現が間違ってたよ。alphaだけ見ててalnumが入ってなかった。この前アンダーバー入りの識別子をサポートしたときのバグだな。
動作テスト
2件続けていくよ。
~/myc$ myc m24.myc ~/myc$ ./m24 sub sub sub ~/myc$ myc m25.myc ~/myc$ ./m25 10 20 30 40 50 10 20 30 ~/myc$
修正できたよ。結構いろんなパターンでチェックしてるつもりなんだけど、それでも抜けが出てくるよ。これからも地道にやってかないと駄目だな。頑張ろう。ところでアンダーバーだけの識別子ってC言語でリーガルなんだっけ? clangでコンパイルエラーにならなかったから良いのかな。_が特殊な意味をもつ言語もあるけど、C言語はそういうのなかったか。最近、いろんな言語を見て回ったりしたんでこんがらがってきたよ。うーん。