コンパイラ作成(102) int型以外の配列の参照

今回の目標

色々試してたらバグが見つかったよ。

// 配列
int main()
{
    double a[10];
    a[0] = 42;
    a[1] = 55;
    printf("a[0] = %f\n", a[0]);
}

配列の参照だけどint型以外の場合上手く行ってなかった。バグっていうか未サポートってところかな。

codegen_lval_to_rval

新しいメソッドを追加。

  # 左辺値を右辺値に変換するコード生成
  def codegen_lval_to_rval(type)
    if is_pointer_type? type then
      codegen "  mov    rax, [rax]"
    elsif type == "int" then
      codegen "  mov    eax, [rax]"
    elsif type == "char" then
      codegen "  mov    al, [rax]"
    elsif type == "double" then
      codegen "  movsd  xmm8, [rax]"
    else
      perror
    end
  end
codegen_els

配列の処理のところを修正。

      if is_pointer_type?(type_l) && type_r == "int" then
        # ポインタ型+int型の処理
        codegen_pointer_int type_l, op, ostr, str
      elsif type_l == "int" && is_pointer_type?(type_r) then
        # int型+ポインタ型の処理
        codegen_int_pointer type_r, op, ostr, str
        type_l = type_r
      elsif is_array_type?(type_l) && type_r == "int" then
        # 配列+int型の処理
        type_l = array_to_pointer type_l
        codegen_pointer_int type_l, op, ostr, str
        type_l = type_l[0,type_l.length-1]
        codegen_lval_to_rval type_l
      elsif type_l == "int" && is_array_type?(type_r) then
        # int型+配列の処理
        type_r = array_to_pointer type_r
        codegen_int_pointer type_r, op, ostr, str
        type_l = type_r[0,type_r.length-1]
        codegen_lval_to_rval type_l
      else
        codegen "  " + ostr + " #{reg}, " + str
      end

追加したメソッドを呼ぶようにしたよ。

codegen_pointer_int

ここも修正。

  # ポインタ型+int型のコード生成
  def codegen_pointer_int(type_l,op,ostr,str)
    size = sizeof type_l[0,type_l.length-1]
    if str == op.str then
      codegen "  " + ostr + " rax, " + (str.to_i*size).to_s
    elsif str == "r10d" then
      codegen "  movsx r10, r10d"
      if size == 4 then
        codegen "  shl  r10, 2"
        codegen "  " + ostr + " rax, r10"
      elsif size == 8 then
        codegen "  shl  r10, 3"
        codegen "  " + ostr + " rax, r10"
      else
        (0...size).each do
          codegen "  " + ostr + " rax, r10"
        end
      end
    else
      codegen "  mov  r10d, " + str
      codegen "  movsx r10, r10d"
      if size == 4 then
        codegen "  shl  r10, 2"
        codegen "  " + ostr + " rax, r10"
      elsif size == 8 then
        codegen "  shl  r10, 3"
        codegen "  " + ostr + " rax, r10"
      else
        (0...size).each do
          codegen "  " + ostr + " rax, r10"
        end
      end
    end
  end

ここは本当にバグってたよ。size==8のとき2bitしかシフトしてなかった。

動作テスト
~/myc$ myc q9.myc
~/myc$ ./q9
a[0] = 42.000000
~/myc$

ちゃんと動くようになったよ。次回は何にするかな。このところテストが不足してるからまずはテストか。