コンパイラ作成(62) 引数のチェック
今回の目標
関数コール時の引数の型・個数をチェックするよ。
// 誤った関数コール extern int add(int a, int b); int main() { int a = 5, b = 12, c; c = add(a,"must be int"); printf("%d + %d = %d\n",a,b,c); }
// 誤った関数コール extern int add(int a, int b); int main() { int a = 5, b = 12, c; c = add(a); printf("%d + %d = %d\n",a,b,c); }
前々回、関数テーブルにちゃんと引数の型の情報を入れるようにしたんで、それを使ってチェックするよ。
codegen_func
# 関数コールのコード生成 def codegen_func operand rettype = "int" f = @functions[operand[0].str] if @numuseregs != 0 then if @numuseregs % 2 == 1 then codegen " sub rsp, 8" end (0...@numuseregs).each do |i| codegen " push #{@regs64[i]}" end end if f != nil then if operand.size - 2 != f[1].size then perror "wrong number of parameters" end end (0...operand.size-2).each do |i| save = @numuseregs @numuseregs = i type = codegen_el operand[i+2] @numuseregs = save if f != nil then if type != f[1][i] then perror "incompatible type parameter" end end if type == "int" codegen " mov #{@regs32[i]}, eax" elsif type == "char*" codegen " mov #{@regs64[i]}, rax" else perror end end codegen " call " + operand[0].str if f != nil then rettype = f[0] end if @numuseregs != 0 then (0...@numuseregs).reverse_each do |i| codegen " pop #{@regs64[i]}" end if @numuseregs % 2 == 1 then codegen " add rsp, 8" end end return rettype end
関数宣言がされてるときだけチェックしてる。されてないときにワーニングを出すべきかな。
動作テスト
2つ続けてテスト。
~/myc$ myc err31.myc err31.myc:7:28 error: incompatible type parameter ~/myc$ myc err32.myc err32.myc:7:14 error: wrong number of parameters ~/myc$
できたよ。このところ関数まわりとchar*まわりを頑張ってきたけど飽きたなあ。次回は別の事しよう。