コンパイラ作成(29) printfのバグ修正

今回の目標

前回のバグの修正をするよ。

int main()
{
    printf("Hello, World!\n");
    printf("%s\n","Hello, World!");
    printf("%d %d %d\n",1,2,3);
    printf("%d %d %d %d %d\n",1,2,3,4,5);
    printf("%d %d %d %d %d\n",1,2,3,4,2*5);
}

最期のprintfがバグってちゃんと表示されなかったやつね。

codegen_els

コード生成を修正するよ。

  # 式のコード生成(二項演算の右側被演算子)
  def codegen_els(op, operand)
    if op.str == "+" then
      ostr = "add "
    elsif op.str == "-" then
      ostr = "sub "
    elsif op.str == "*" then
      ostr = "mul "
    elsif op.str == "/" then
      ostr = "div "
    elsif op.str == "==" then
      ostr = "cmp "
    else
      perror "unknown operator \"" + op.str + "\""
    end
    if operand.kind_of?(Array) then
      if operand[0].size == 2 && operand[0].kind == TK::ID && operand[1].str == "()" then
        codegen "  push rax"
        codegen "  call " + operand[0].str
        codegen "  mov  ebx, eax"
        codegen "  pop  rax"
      else
        codegen "  push rax"
        codegen_el operand
        codegen "  mov  ebx, eax"
        codegen "  pop  rax"
      end
      if op.str == "==" then
        codegen "  " + ostr + " eax, ebx"
        codegen "  sete al"
        codegen "  and  eax, 1"
      elsif op.str == "*" || op.str == "/" then
        codegen " mov  r11, rdx"
        if op.str == "/" then
          codegen "  xor  edx, edx"
        end
        codegen "  " + ostr + " ebx"
        codegen "  mov  rdx, r11"
      else
        codegen "  " + ostr + " eax, ebx"
      end
    elsif operand.kind == TK::NUMBER then
      if op.str == "==" then
        codegen "  " + ostr + " eax, " + operand.str
        codegen "  sete al"
        codegen "  and  eax, 1"
      elsif op.str == "*" || op.str == "/" then
        codegen "  mov  ebx, " + operand.str
        codegen "  mov  r11, rdx"
        if op.str == "/" then
          codegen "  xor  edx, edx"
        end
        codegen "  " + ostr + " ebx"
        codegen "  mov  rdx, r11"
      else
        codegen "  " + ostr + " eax, " + operand.str
      end
    end
  end

乗算除算のところでrdxをr11に退避するようにしたよ。本当はrdxの使用状況に合わせて必要な場合のみ退避すれば良いんだけど、面倒何で無条件に退避するようにしたよ。rdxに値を入れるのは関数呼出の時だけだから、引数をrdxに入れたときにフラグをセットして、printfのコールの後にフラグをリセットすれば良いのかな。やればできるかな。うーん、とりあえずはこのままで良いか。

動作テスト

どうかな。

~/myc$ myc m3.myc
~/myc$ ./m3
Hello, World!
Hello, World!
1 2 3
1 2 3 4 5
1 2 3 4 10
~/myc$

ちゃんと表示されたよ。これで一応printfが使えるようになったよ。まだ引数の数とか制限はあるけどね。これでもう組み込み関数printは必要なくなったのかな。でも動作確認用のソースがprint使いまくってるなあ。あれを全部書き換えるの面倒だから、当面残しておくか。動作確認のためには処理が単純なprintの方が良いような気もするしなあ。
さて次回は何やろうかな。そろそろ変数に手を出してみるかな。ちょっと考えてみたけど難しそうだな。どうするかもうちょっと悩むか。