コンパイラ作成(59) char*型変数の代入・参照を修正
今回の目標
引き続きchar*型。
// char*型の変数 int main() { char *p = "Hello, World!"; puts(p); }
これ前々回のテストプログラム。コンパイルできてちゃんと動いたんだけどさ、アセンブリコード見てて変なことに気が付いたよ。
.intel_syntax noprefix .global main main: push rbp mov rbp, rsp sub rsp, 16 lea rax, .L.str mov dword ptr [rbp - 8], eax mov eax, dword ptr [rbp - 8] mov edi, eax call puts .RET_main: add rsp, 16 pop rbp ret .L.str: .asciz "Hello, World!"
movが32bitになってる。ポインタだから64bitじゃないと拙いよね。で良く考えたら前々回は変数宣言部の修正しかしてないから当たり前だよ。raxに値が残ってて偶然動いてるだけだった。はは、参ったね。
codegen_assign
ここも型を意識してコード生成するようにしたよ。
# 代入のコード生成 def codegen_assign(el) if el.size != 3 then perror end type_r = codegen_el [el[2]] if el[0].kind_of?(Array) then perror end if el[0].kind != TK::ID then perror end v = @lvars[el[0].str] if v == nil then perror "undeclared variable \"" + el[0].str + "\"" end type_l = v[0] if type_l != type_r then perror end if type_l == "char*" then codegen " mov qword ptr [rbp - " + v[1].to_s + "], rax" else codegen " mov dword ptr [rbp - " + v[1].to_s + "], eax" end return type_l end
変数のHashテーブルから型を参照するようにした。
codegen_elf
ここも同じように修正。
# 式のコード生成(二項演算の左側被演算子) def codegen_elf(operand) type = "int" if operand.kind_of?(Array) then if !operand[0].kind_of?(Array) && operand[0].kind == TK::ID && operand[1].str == "()" then type = codegen_func operand else type = 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 type = v[0] if type == "char*" codegen " mov rax, qword ptr [rbp - " + v[1].to_s + "]" else codegen " mov eax, dword ptr [rbp - " + v[1].to_s + "]" end elsif operand.kind == TK::STRING then type = "char*" label = addliteral operand.str codegen " lea rax, "+label else perror end return type end
動作テスト
~/myc$ myc o13.myc ~/myc$ ./o13 Hello, World! ~/myc$
ここまではこの前と同じ。コンパイル結果を見てみるよ。
.intel_syntax noprefix .global main main: push rbp mov rbp, rsp sub rsp, 16 lea rax, .L.str mov qword ptr [rbp - 8], rax mov rax, qword ptr [rbp - 8] mov rdi, rax call puts .RET_main: add rsp, 16 pop rbp ret .L.str: .asciz "Hello, World!"
ちゃんと64bitになってる。動作確認だけじゃなくアセンブリコードもしっかり確かめないと駄目だね。これから気を付けよう。(多分明日になったら忘れてる)