LoginSignup
0
0

More than 5 years have passed since last update.

オフラインリアルタイムどう書く E29 の実装例( racc )

Last updated at Posted at 2018-12-08

問題の名前 : アンエスケープ
問題 : http://nabetani.sakura.ne.jp/hena/orde29unes/
実装リンク集 : https://qiita.com/Nabetani/items/f2db9b916c0a301b744f

次回のイベントは 2/2
see https://yhpg.doorkeeper.jp/events/84247

で。

当日、スタート直前に書き上がった、racc による実装。

racc
class E29Parser
rule
  result : BOL entries EOL { @ents = val[1] }
  entries : entry { result = [val.join] }
          | entries SLASH entry { result = val[0] + [val[2]]}
  entry : entry_unit  { result = val.join }
        | entry entry_unit { result = val.join }
  entry_unit : ALNUM { result = val[0] }
             | SLASH_PAIR { result = "/" }
             | dq_unit
             | sq_unit

  dq_unit : DQ in_dq DQ { result = val[1] }
          | DQ DQ { result = "" }
  in_dq : in_dq_atom { result = val.join }
        | in_dq in_dq_atom { result = val.join }
  in_dq_atom : SLASH_PAIR { result = val[0] }
             | ALNUM { result = val[0] }
             | SLASH { result = val[0] }
             | SQ { result = val[0] }

  sq_unit : SQ in_sq SQ { result = val[1] }
          | SQ SQ { result = "" }
  in_sq : in_sq_atom { result = val.join }
        | in_sq in_sq_atom { result = val.join }
  in_sq_atom : SLASH_PAIR { result = val[0] }
             | ALNUM { result = val[0] }
             | SLASH { result = val[0] }
             | DQ { result = val[0] }
end

---- inner
def parse( src )
  @q = [[:BOL, nil]] + src.scan( %r!\w+|\"|\'|//|/! ).to_a.map{ |t|
    type = case t
    when /\w+/; :ALNUM
    when '"'; :DQ
    when "'"; :SQ
    when "//"; :SLASH_PAIR
    when "/"; :SLASH
    else; raise "unexpected"
    end
    [ type, t ]
  } + [[:EOL,nil]]
  do_parse
  @ents
end

def next_token
  @q.shift
end

---- footer
require "json"

def solve( src )
  begin
    parser = E29Parser.new
    ents = parser.parse( src )
    ents.any?(&:empty?) ? "-" : ents.join(",")
  rescue Racc::ParseError => e
    return "-"
  end
end

def test( src, expected )
  actual =  solve( src )
  okay = actual == expected
  puts [
    ( okay ? "ok" : "**NG**" ),
    src, actual, expected
  ].join(" ")
end


if __FILE__ == $0
  data = JSON.parse( File.open( "data.json" ){ |f| f.read } )
  data["test_data"].each do |e|
    test( e["src"], e["expected"] )
  end
end

racc はシンタックスハイライトが効かないのがちょっと残念。
VSCode で書いたんだけど、VSCode でも白黒だった。そういうものか。

テストデータは上記の問題文ページの末尾にある data.json

実行方法は、上記の内容を e29.y として、

racc -g e29.y -o e29.rb && ruby e29.rb 

こんな感じ。

生まれて初めて racc 書いたのでちょっと大変だったけど、1時間前後だと思う。
もちろん自分が回答者だったら本番では選ばない選択だけど。

実装にあたっては、
https://qiita.com/lnznt/items/ecbc16cae8ab9c641391
を大いに参考にした。ありがとうございます。

不満は

  • dq_unit と sq_unit は大差ないのに両方ベタで書いてしまった
  • レキサ(scan)で、 /// と別のトークンにしたところ

の二点。

両方とも、rule の書き方がわかってないということだと思う。
もうちょっとあがいてみようと思うけれど、今日のところはこれぐらいで。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0