コンパイラ作成(88) 式のエラーチェック

今回の目標

double型関連にちょっと疲れたんで別の事やるよ。壊れてる式をチェックしてエラーに。

// 壊れてる式
int main()
{
    1 + ;
}
// 壊れてる式
int main()
{
     + ;
}
// 壊れてる式
int main()
{
     / ;
}
// 壊れてる式
int main()
{
    int i;
    i++;
}

ちょっとづつ違う4パターン。最後のはC言語としては正しいんだけど、mycはまだインクリメント演算子をサポートしてないんでエラー。

modify_el_unaryop
  # elの変形(単行演算子の処理)
  #   [-, 2, +, 3]
  #   =>[[-, 2], + 3]
  #   [-, 2, +, -, 3]
  #   =>[[-, 2], + [-, 3]]
  def modify_el_unaryop(el, opl)
    mel = []
    prev = nil
    loop do
      if el.size == 0 then break end
      x = el.shift
      if ((prev == nil) || (!prev.kind_of?(Array) && (prev.kind == TK::SYMBOL))) \
         && !x.kind_of?(Array) && x.kind == TK::SYMBOL
      then
        if opl.include? x.str then
          tel = []
          tel << x
          if el == [] then
            perror "broken expression"
          end
          x = el.shift
          if x.kind_of?(Array) then
            x = modify_el_unaryop x, opl
          elsif opl.include? x.str then
            sel = []
            loop do
              sel << x
              if !opl.include? x.str then break end
              if el.size == 0 then break end
              x = el.shift
            end
            x = modify_el_unaryop sel, opl
            if x.size == 1 && x[0].kind_of?(Array) then
              x = x[0]
            end
          end
          tel << x
          mel << tel
          prev = tel
        else
          perror "broken expression"
        end
      else
        if x.kind_of?(Array) then x = modify_el_unaryop x, opl end
        mel << x
        prev = x
      end
    end
    return mel
  end

単項演算子の後に適切なオペランドが無かったらエラー。

codegen_el
  # 式のコード生成
  def codegen_el(el)
    type = "int"
    if !el[0].kind_of?(Array) && el[0].kind == TK::SYMBOL
      type = codegen_unaryop el[0], [el[1]]
    elsif (el.size > 1) && el[1].str == "=" then
      type = codegen_assign el
    else
      type = codegen_elf el.shift
      loop do
        if el == [] then break end
        op = el.shift
        operand = el.shift
        if operand == nil then
          perror "broken expression"
        end
        type = codegen_els op, operand, type
      end
    end
    return type
  end

二項演算子の場合もオペランドが無かったらエラー。

動作テスト

4つ纏めて行くよ。

~/myc$ myc err38.myc
err38.myc:4:8 error: broken expression
~/myc$ myc err39.myc
err39.myc:4:7 error: broken expression
~/myc$ myc err40.myc
err40.myc:4:7 error: broken expression
~/myc$ myc err41.myc
err41.myc:5:8 error: broken expression
~/myc$

みんなエラーになったよ。今回はこの4件をチェックしたけど、まだまだ漏れてるのあるだろうなあ。代入演算子、アドレス演算子、参照演算子がらみのチェックは不十分だよなあ。次回もエラーチェックかな。