コンパイラ作成(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言語はそういうのなかったか。最近、いろんな言語を見て回ったりしたんでこんがらがってきたよ。うーん。