Raccのメモ

CパーサをRaccで書いてる途中に、よく無道編*1を字引く箇所をメモる。

記法やイディオム

アクションの書き方
funcall : IDENTIFIER '(' arguments ')'
	{
		#result : 左辺記号の値
		#val    : 右辺記号の値の配列
		result = FuncallNode.new(val[0], val[2])
	}
各パートの挿入

parse.y

class SomeModule::SomeParser

prechigh
  ...
preclow

rule
  ...
end

---- header
  ...

---- inner
  ...

---- footer
  ...

parse.tab.rb

#{header}

module SomeModule
  class SomeParser
    #{inner}
    ...
  end
end

#{footer}
レクサのイディオム

行指向の例。

def lex(line, queue)
  buffer = line.strip
  until buffer.empty?
    case
    #空白
    when /\A\s+/
      ;
    #コメント
    when /\A\#.*/
      ;
    #識別子
    when /\A[a-zA-Z_]\w*/
      queue << [:IDENT, $&.intern]
    #整数リテラル
    when /\A\d+/
      queue << [:INTEGER, $&.to_i]
    #文字列リテラル
    when /\A"(?:[^"\\]+|\\.)*"/
      queue << [:STRING, eval($&)]
    #その他の一文字
    when /\A./
      queue << [$&, $&]
    else
      raise Exception, 'must not happen'
    end
    buffer = $'
  end
  queue << [:EOL, nil]  #行終端記号
end

トークン詰めの終わり。

queue << [false, nil]  #[false, 何か]を詰める
演算子の優先順位のイディオム
prechigh
  nonassoc UNIMINUS
  left '*' '/'
  left '+' '-'
preclow

rule
  uni_expr : '-' expr =UNIMINUS
end
result省略オプション

逆にresult=...とは書けなくなる。

class SomeParser

options no_result_var

rule
  funcall : IDENTIFIER '(' arguments ')'
    {
      FuncallNode.new(val[0], val[2])
    }
end

デバック

デバック用パーサの生成
---- inner
  def initialize
    @yydebug = true  #do_parse()の前にtrueに
  end

と、@yydebugをtrueにして、

$ racc -g parse.y

でreadやshift、reduceの様子がstderr出力される。

.outputファイルの出力

中身は状態リストなど。

$ racc -v parse.y   #=> parse.output
conflictの情報

.outputの最初に書いてある。

state 15 contains 1 shift/reduce conflicts

で、state 15を見る。

state 15

   7) funcall : IDENT args _
   9) args : args _ "," primary
  
  ","       shift, and go to state 20
  ","       [reduce using rule 7 (funcall)]
  $default  reduce using rule 7 (funcall)

下部分は、"先読みトークン 動作"である。
先読みトークンはLALR(1)の1。
$defaultはその他のトークンを示す。

","が先読みできた場合、shiftとreduceがダブっている。
yaccに習ってデフォではshiftを優先するので、reduceは
[...]で囲われて示されている(パーサに捨てられた方)。

*1:Rubyを256倍使うための本無道編」青木峰郎、ASCII