優先順位は使わず規則だけで演算子の優先順位を

やってみた

class Parser

options no_result_var

rule

  expr  : addsub

  addsub: addsub '+' muldiv { val[0] + val[2] }
        | addsub '-' muldiv { val[0] - val[2] }
        | muldiv
  
  muldiv: muldiv '*' primary { val[0] * val[2] }
        | muldiv '/' primary { val[0] / val[2] }
        | primary
  
  primary: NUM
         | '(' expr ')' { val[1] }
end

---- inner

def parse
  yyparse( self, :scan )
end

def scan
  require 'strscan'
  s = StringScanner.new( gets )
  until s.eos?
    next if s.skip( /\s+/ )
    case
    when s.scan( /\d+/ )
      yield :NUM, s.matched.to_i
    else
      yield s.getch, nil
    end
  end
  yield false, '$'
end

---- footer

p Parser.new.parse

右から左に結合する演算子

結合規則が右から左な演算子

  pow   : primary POW_OP pow { val[0] ** val[2] } # 右から左の結合規則

のようにすればいい。

  pow   : pow POW_OP primary { val[0] ** val[2] } # これだと左から右になる

ではないことに注目。

結合しない演算子

結合しないような演算子だったら

eq    : addsub EQ_OP addsub { val[0] == val[2] }

みたいに。

単項演算子

uminus: '-' uminus { - val[1] }

条件演算子

cond  : eq '?' expr ':' cond { val[0] ? val[2] : val[4] }

今回のようにアクション中で直接計算してしまうタイプだと条件演算子とは名ばかりに全ての項を評価してしまうけどそれは本筋ではないから気にしない。