コンパイラ作成(95) return文での型のチェック

今回の目標

前回の続きでreturn文。

// 関数の呼び出し
int *sub(void)
{
    return 2.5;
}

int main()
{
    printf("%d\n",sub());
}

型をチェックするよ。

expr
  # 式の構文解析
  def expr2(fkind,fstr,skind,sstr)
    el, kind, str = read_modify_el fkind, fstr, skind, sstr
    return kind, str, codegen_el(el)
  end

型の情報を返すようインターフェースを修正。

statement

return文の処理。

    if kind == TK::RESERVE && str == "return" then
      # return文の処理
      f = @functions[@funcname]
      kind, str = @lex.gettoken
      if kind != TK::SYMBOL && str != ";" then
        kind, str, type = expr kind, str
        if f[0] != type then
          if f[0] == "void" then
            perror "return a value at void function"
          else
            perror "return with incompatible result type"
          end
        end
        if f[0] == "double" then
          codegen "  movsd  xmm0, xmm8"
        end
      else
        if f[0] != "void" then
          perror "return no value at non-void function"
        end
      end
      codegen "  jmp  .RET_" + @funcname
      if kind != TK::SYMBOL || str != ";" then
        perror "expected ';' after return statement"
      end

exprからの型情報と関数情報テーブルの返値の型を見比べてエラーを出してるんだけど、色んな場合があって面倒だよ。

動作テスト
~/myc$ myc err45.myc
err45.myc:4:15 error: return with incompatible result type
~/myc$ 

ちゃんとエラーになってるね。さらに別のパターンを二つチェックするよ。

// 関数の呼び出し
void sub(void)
{
    return 42;
}

int main()
{
    printf("%d\n",sub());
}

void関数で値を返してる場合。

// 関数の呼び出し
int sub(void)
{
    return;
}

int main()
{
    printf("%d\n",sub());
}

逆にvoid関数じゃないのに値を返してない場合。

~/myc$ myc err46.myc
err46.myc:4:14 error: return a value at void function
~/myc$ myc err47.myc
err47.myc:4:11 error: return no value at non-void function
~/myc$

大丈夫だね。一応これで全部のパターンチェックしたつもり。次回はreturn文でのint型→double型の変換をやるつもりだよ。