feat: add SLR(1) parsing strategy and item-set viewer - #18
Open
raiga0310 wants to merge 1 commit into
Open
Conversation
`lr::compile` を `compile_lr0` / `compile_slr` に分割し、内部を `Strategy` enum で切り替える `compile_with` に共通化した。LR(0) は 還元を全終端記号に対して行い、SLR は FOLLOW 集合を先読みに使う。 - `follow.rs` を新規追加。nullable / FIRST / FOLLOW を不動点反復で計算し、 SLR の還元先読みを供給する。ライブラリ内部専用 (`pub(crate)`)。 - `ParserError::ConflictReducer` を `ParserError::Conflict(Conflict)` に変更。 競合した状態・先読み終端・既存 action・投入 action を保持し、 UI で「どこで何が競合したか」を提示できるようにした。 - 拡張開始記号を確保できない場合の `NoAvailableStartSymbol` を追加。 - `pages/item_sets.rs` を新規追加。各状態の LR 項集合をドット位置つきで 表示し、SLR では還元項に先読みを併記する。 - `pages/parser.rs`: `ParserKind` から compile 関数を注入する形に変更し、 `Slr` を実装済みとして有効化。あわせて、run が失敗しても compile が 成功していれば状態機械と項集合を表示するよう順序を入れ替えた (入力エラー時こそ項集合を見たいため)。 - `grammar.rs`: EOF 終端 `$` を `grammar::EOF` 定数として公開。 Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
LR(0) だけだった解析エンジンに SLR(1) を追加し、GUI に 項集合 (Item Sets) ビューを追加しました。あわせて、競合エラーが「どこで何と何が競合したか」を報告できるようになっています。
変更内容
ライブラリ側
lr::compileをcompile_lr0/compile_slrに分割内部は
Strategyenum を受け取るcompile_withに共通化しました。項集合の構築とテーブル生成は完全に共有し、両者の差は「還元の先読みをどう決めるか」の一点だけです。FOLLOW(A)に含まれる終端記号にのみ還元するsrc/follow.rsを新規追加nullable 判定 → FIRST 集合 → FOLLOW 集合を不動点反復で計算します。
FOLLOW(S') = {$}を起点に伝播させる標準的な構成です。ライブラリ内部専用 (pub(crate)) で、公開 API は増やしていません。ParserError::ConflictReducer→ParserError::Conflict(Conflict)Conflictは競合した状態番号・先読み終端・既存の action・投入しようとした action を保持します。kind()が"Shift/Reduce"/"Reduce/Reduce"を返します。ParserError::NoAvailableStartSymbolを追加26 文字の大文字がすべて非終端記号として使われていると拡張開始記号
S'を作れないため、その場合を明示的なエラーにしました。grammar::EOF定数を公開ハードコードされていた
Terminal('$')を定数に切り出しました。GUI 側
src/pages/item_sets.rsを新規追加各状態の LR 項をドット位置つきで表示します。還元可能な項(ドットが末尾)には先読み集合を併記するため、SLR が LR(0) より通る理由が画面上で追えます。現在の遷移元状態をハイライトします。
pages/parser.rs: 解析法の選択を compile 関数の注入に変更ParserKind→CompileFnのマッピングだけで解析法が決まる形にしたので、Slrが「未実装」から実装済みに変わりました。Lalr/Lr1は引き続きNotImplementedです。従来の「grammar is not LR(0)」だけの表示から、状態番号・先読み・競合する 2 つの action を出すようにしました。
レビュアーに見てほしい点
handle_parse_withの処理順を入れ替えています。 従来はrunが失敗するとstate_infosを空にして返していましたが、状態機械と項集合は compile 成功の時点で確定しておりrunの成否とは独立です。むしろ入力エラーのときこそ項集合を見たい場面なので、runより前に組み立てるようにしました。この挙動は GUI を目視する以外に観測手段がないため、run_failure_still_exposes_state_infosテストで固定しています。Conflictを公開型としてlib.rsから re-export しています。 競合の詳細を UI に渡すために必要ですが、公開 API を増やす判断なので妥当かご確認ください。S -> aA / S -> a / A -> bを使っています (SLR_ONLY_GRAMMAR)。LR(0) ではbで Shift/Reduce 競合、SLR では通る、という差分をparser_kind_selects_the_compile_functionで確認しています。テスト
cargo testは全て通過しています(ライブラリ側 + GUI クレート 17 件)。補足
CLAUDE.mdの Architecture セクションがlr::compile/ParserError::ConflictReducerという旧名のままです。本 PR のスコープ外としましたが、別途更新が必要です。