2025/11/12 04:16 Reproachfully Presenting Resilient Recursive Descent Parsing

やあ、ロボ子。今回のITニュースは、Rustでプログラミング言語を作る話じゃ。今回はパーシングについてみたいじゃな。

パーシングですか。コンパイラがソースコードの構文をチェックして、扱いやすいようにメモリ内に表現を作成するのですよね。

そうじゃ、そうじゃ!この記事によると、パーシングには色々な選択肢があるみたいじゃな。空白に意味を持たせるか、どんなキーワードを使うか、セミコロンを必須にするかとか。

末尾のカンマを許可するか、パーサー生成器を使うか、Earley法を使うか、手書きにするか、パーサーコンビネーターライブラリを使うか、PEGを使うか、などですね。

今回は、ハンドライティングされたパーサーを使うらしいぞ。しかも、レジリエンス(最初のエラーで止まらない)とフルフィデリティ(ソーステキストのすべての文字をツリーに表現する)が求められる。

なるほど。最初のエラーで止まらず、全ての文字をツリー構造にするのですね。具体的にはどのような戦略をとるのでしょう?

再帰下降パーサーを使うみたいじゃ。CSTライブラリには`rowan`を使うらしい。これはホモジニアスなn-ary木を格納できて、各ノードはタグと任意の子を持つんじゃ。

`rowan`、便利そうですね。字句解析には`logos`を使うとのことですが、これはどういう役割をするのですか?

字句解析は、入力文字列をトークンにグループ化する役割じゃ。`logos`を使うことで、それを簡単に行えるのじゃ。認識できない文字は`Syntax` enumに`Error`バリアントを追加して処理するみたいじゃな。

なるほど、エラー処理も考慮されているのですね。構文についても特徴的な点があるようですが。

変数は識別子で表現して、関数は`|`でパラメータを区切る。関数適用は空白で区切られた2つの要素で表現するみたいじゃ。括弧で曖昧さを解消して、`let`式を構文糖として導入するんじゃと。

`let`式は便利そうですね。Parser構造体には、エラーを蓄積する`errors`や、同じテキスト範囲で複数のエラーを報告しないようにする`in_error`があるのですね。

そうじゃ。CSTを構築する`builder`や、ソーステキストを管理する`input`もあるぞ。`peek()`で次のトークンを覗き見たり、`at()`で特定のトークンであるか確認したり、`advance()`で入力を進めたりするんじゃ。

`eat()`で特定のトークンを消費して、`expect()`で特定のトークンを期待し、エラー処理を行うのですね。エラー回復のためにアンカーセットを使うのも興味深いです。

エラーのあるトークンを`Error`ノードとしてツリーに追加するんじゃ。関数適用の解析では、左再帰を避けるために`expr`を直接再帰呼び出しせず、`atom`を解析するみたいじゃな。

`atom`は変数、整数、関数、括弧で囲まれた式ですね。`let`式の解析では、アンカーセットを積極的に利用して、エラーからの回復を試みると。

プログラムの解析では、先頭の空白を処理して、入力文字列全体が消費されるようにするんじゃ。なかなか奥が深いじゃろ?

はい、とても勉強になります。Rustでプログラミング言語を作るのは大変そうですが、楽しそうですね。

そうじゃな!ところでロボ子、パーシングって、まるで人間関係みたいじゃな。最初は字句解析で相手の言葉を理解して、構文解析でその意味を理解する。そして、意味が通じないとエラーを出すんじゃ!

博士、それは少し強引な例えですね… でも、エラー処理は重要という点は共通していますね。

まあ、そんなもんじゃ!エラーが出たら、アンカーセットで関係修復を試みるのじゃ!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。