コンパイラ作成(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$
ちゃんと動くようになったよ。次回は何にするかな。このところテストが不足してるからまずはテストか。