tag:crieit.net,2005:https://crieit.net/tags/Lrama/feed 「Lrama」の記事 - Crieit Crieitでタグ「Lrama」に投稿された最近の記事 2023-06-25T08:41:34+09:00 https://crieit.net/tags/Lrama/feed tag:crieit.net,2005:PublicArticle/18485 2023-06-25T08:41:34+09:00 2023-06-25T08:41:34+09:00 https://crieit.net/posts/ruby-lrama-parser Lramaで簡単な自作言語のパーサを書いた <p><a href="https://crieit.now.sh/upload_images/36b6f940e2f434c979b5ada813c8206f64977e25696d7.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/36b6f940e2f434c979b5ada813c8206f64977e25696d7.png?mw=700" alt="image" /></a></p> <p>先日 Ruby にマージされた LALR(1)パーサジェネレータ Lrama を使ってみました。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/ruby/lrama">https://github.com/ruby/lrama</a></p> <p>参考: <a target="_blank" rel="nofollow noopener" href="https://techracho.bpsinc.jp/hachi8833/2023_05_15/130116">RubyにlramaがマージされてBison依存がなくなった(RubyKaigi 2023)|TechRacho by BPS株式会社</a></p> <h1 id="できたもの"><a href="#%E3%81%A7%E3%81%8D%E3%81%9F%E3%82%82%E3%81%AE">できたもの</a></h1> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/sonota88/vm2gol-v2-c/tree/alt-parser-lrama">https://github.com/sonota88/vm2gol-v2-c/tree/alt-parser-lrama</a></p> <p>alt-parser-lrama ブランチに <code>mrcl_parser_lrama.y</code> が入っています。</p> <h1 id="概要"><a href="#%E6%A6%82%E8%A6%81">概要</a></h1> <p>Mini Ruccola は私がコンパイラ実装に入門するために作った自作言語とその処理系です。原始的だけどその分入門者(=私)視点では分かりやすい、という方向性のものです。私でも作れるコンパイラ。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/sonota88/vm2gol-v2">https://github.com/sonota88/vm2gol-v2</a></p> <p>作ったときに書いた備忘記事:</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/sonota88/items/f9cb3fc4a496b354b729">RubyでオレオレVMとアセンブラとコード生成器を2週間で作ってライフゲームを動かした話</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/sonota88/items/2b95378b43a22109513c">(2週間ちょっとで)Rubyでかんたんな自作言語のコンパイラを作った</a></li> </ul> <hr /> <p>コンパイラのパーサ部分は元々手書きの再帰下降パーサだったのですが、他のパーサライブラリも試したくて Racc 版と Parslet 版のパーサを以前書きました。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/sonota88/items/97ba1f0c377fbe86d5b1">Raccでかんたんな自作言語のパーサを書いた</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/sonota88/items/edce05e86d3248f49401">Parsletでかんたんな自作言語のパーサを書いた</a></li> </ul> <p>今回の Lrama 版はこのシリーズの延長です。</p> <hr /> <p>Mini Ruccola コンパイラはレキサ・パーサ・コード生成器が独立しています。そのため、レキサとコード生成器は Ruby 製のものをそのまま使い、パーサだけ別の言語で書いて一緒に動かすなんてことも可能です。</p> <p>可能なのですが、C言語への移植版<br /> <a target="_blank" rel="nofollow noopener" href="https://github.com/sonota88/vm2gol-v2-c">github.com/sonota88/vm2gol-v2-c</a><br /> を使った方が楽なので今回はこっちを使いました。</p> <p>参考: <a target="_blank" rel="nofollow noopener" href="https://memo88.hatenablog.com/entry/2020/09/06/043607">素朴な自作言語のコンパイラをCに移植した</a></p> <hr /> <p>Racc 版パーサ実装と C移植版がすでにありますから、あとは Racc 版パーサを Lrama + C 向けに書き直せば一丁あがり、という寸法です。</p> <p>たとえば以下は関数定義の規則とアクションの記述の比較です。</p> <pre><code class="ruby"># Racc func_def : "func" IDENT "(" args ")" "{" stmts "}" { _, fn_name, _, args, _, _, stmts, _, = val result = ["func", fn_name, args, stmts] } </code></pre> <pre><code class="c">// Lrama func_def : TS_KW_FUNC TS_IDENT TS_PAREN_L args TS_PAREN_R TS_SYM stmts TS_SYM // "func" fn_name "(" args ")" "{" stmts "}" { NodeList* func_def = NodeList_new(); NodeList_add_str(func_def, "func"); NodeList_add_str(func_def, $2); NodeList_add_list(func_def, $4); NodeList_add_list(func_def, $7); $$ = func_def; } </code></pre> <p>こんな感じで読み換えていきました。どちらも Yacc から派生した LALRパーサジェネレータなのでよく似ていますね。</p> <h1 id="メモ"><a href="#%E3%83%A1%E3%83%A2">メモ</a></h1> <ul> <li>1日くらいでババッと書いたものなので雑だったり手抜きで済ませている部分があります。一応動いてる、という程度の出来です。 <ul> <li>警告もひとまず放置</li> </ul></li> <li>Yacc, Bison もそのうち触ってみようと思いつつ結局今まで触らずじまいだった <ul> <li>今回ちょっとやってみて雰囲気が知れてよかった</li> <li>Rubyソースコード完全解説の <a target="_blank" rel="nofollow noopener" href="https://i.loveruby.net/ja/rhg/book/yacc.html">第9章 速習yacc</a> を読んだらとりあえずなんとかなった</li> </ul></li> <li>Rubyには慣れているけどCは分からないという状態で LALR パーサジェネレータに入門したい人は、まず Racc で入門するのが良いのではないかと思います。Ruby の知識だけで使えるので、いきなり Yacc や Bison や Lrama に挑戦するよりはお手軽かと。 <ul> <li>Racc の作者(青木峰郎さん)による解説本『Rubyを256倍使うための本 無道編』もまだ中古で入手可能(<a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/dp/4756137091">Amazon</a>)</li> </ul></li> </ul> <h1 id="この記事を読んだ人は(ひょっとしたら)こちらも読んでいます"><a href="#%E3%81%93%E3%81%AE%E8%A8%98%E4%BA%8B%E3%82%92%E8%AA%AD%E3%82%93%E3%81%A0%E4%BA%BA%E3%81%AF%EF%BC%88%E3%81%B2%E3%82%87%E3%81%A3%E3%81%A8%E3%81%97%E3%81%9F%E3%82%89%EF%BC%89%E3%81%93%E3%81%A1%E3%82%89%E3%82%82%E8%AA%AD%E3%82%93%E3%81%A7%E3%81%84%E3%81%BE%E3%81%99">この記事を読んだ人は(ひょっとしたら)こちらも読んでいます</a></h1> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/sonota88/items/6a96d2bcea9d134e38b7">Ruby/Racc: パース時のスタックの動きをFlameGraphっぽくビジュアライズする</a></li> </ul> <p>Racc の気持ちが分かるように↓こういう図を描かせてみたもの。</p> <p><a href="https://crieit.now.sh/upload_images/7a727bbde73b2e30d4a57505e10347d264977e43df695.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/7a727bbde73b2e30d4a57505e10347d264977e43df695.png?mw=700" alt="image" /></a></p> <hr /> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/sonota88/items/816b6b8d7a362ef4e332">Ruby: 入れ子の配列だけをパースできるパーサを作る(手書きの再帰下降パーサ)</a></li> </ul> <p>メソッドの再帰呼び出しについてすでに知っていれば1時間もかからず書ける内容。比較的簡単で時間がかからないので、LALR パーサにこだわる事情がなければ先に再帰下降パーサで入門するのも良いと思います。</p> <hr /> <ul> <li><p><a target="_blank" rel="nofollow noopener" href="https://qiita.com/sonota88/items/84e4c16e5602b9771e92">『RubyでつくるRuby』のMinRubyのパーサを書いた(手書きの再帰下降パーサ)</a></p></li> <li><p><a target="_blank" rel="nofollow noopener" href="https://zenn.dev/sonota88/articles/06c540eda79b98">四則演算と剰余のみのexprコマンドをRubyで作ってみた</a></p></li> <li><p><a target="_blank" rel="nofollow noopener" href="https://qiita.com/sonota88/items/5902f255e196b5b8b048">正規表現エンジン(ロブ・パイクのバックトラック実装)をRubyで写経した</a></p></li> </ul> sonota486