LR(0) 構文解析器と AST ベースの Rust コードジェネレーターを備えた GUI アプリケーション。
このプロジェクトは デュアルクレート構成 を採用しています。
| クレート | 名前 | 役割 |
|---|---|---|
| ライブラリ | lr0_parser_rs |
純粋な構文解析ロジック(GUI・I/O なし) |
| バイナリ | lr0-parser-gui |
egui GUI(ライブラリのラッパー) |
- LR(0) 構文解析: 文法規則に基づくパース処理、Shift/Reduce および Reduce/Reduce コンフリクトをハードエラーとして検出
- ステップアニメーション: パース過程をステップごとに再生・早送り可能
- パーステーブル表示: Action/Goto テーブルを 2D グリッドで表示
- AST 生成: 抽象構文木の自動生成・ツリー描画
- コードジェネレーター: AST から実行可能な Rust コードを生成・実行
- 終端記号ロール設定: 各終端記号に演算子・数値などのロールを割り当て
# ビルド
cargo build
# GUI アプリケーションを起動
cargo run
# テストをすべて実行
cargo test
# 特定のテストを実行
cargo test <test_name>
# モジュール単位でテストを実行
cargo test grammar::tests
cargo test runtime::tests- Production フィールドに文法規則を入力(デフォルト: 算術文法)
- Target String にパース対象の文字列を入力
- Parse ボタンを押してパース実行
- ステップアニメーションで Parse Trace を確認、パーステーブルと AST を参照
- Parser ページで文法と入力文字列を設定した後、Generator タブに切り替える
- Terminal Symbols セクションで各終端記号にロールを割り当てる
- Generate Code ボタンで AST → Rust コードを生成
- Run ボタンで生成コードを
rustcでコンパイル・実行
LHS -> RHS
LHS: 大文字 ASCII 1 文字(非終端記号)RHS: 大文字(非終端記号)と他の文字(終端記号)の列、空白は自動除去$は EOF 終端記号として予約済み(入力末尾に自動付加)- LR コンフリクトが発生した場合はコンパイルエラーとなる
E -> E*B
E -> E+B
E -> B
B -> 0
B -> 1
リポジトリルートにサンプルファイルを同梱:
| ファイル | 内容 |
|---|---|
reducer |
算術文法(LR(0) 適合、テストで使用) |
paren_reducer |
非 LR(0) 文法(EE->E による S/R コンフリクトを意図的に含む) |
Generator ページで各終端記号に設定可能なロール:
| ロール | 対象文字(デフォルト) |
|---|---|
Add |
+ |
Sub |
- |
Mul |
* |
Div |
/ |
Mod |
% |
LParen |
( < [ { |
RParen |
) > ] } |
Num |
0〜9 |
Token |
その他 |
grammar::parse_grammar_text(text) → Grammar
lr::compile(&grammar) → CompiledParser
runtime::run(&machine, &symbols) → ParserResult { ast: AstNode }
runtime::build_trace(...) → Vec<ParseStep> (アニメーション用ステップ列)
src/
├── lib.rs # ライブラリルート(pub re-export)
├── grammar.rs # テキスト → Grammar(生成規則・終端/非終端記号)
├── lr.rs # Grammar → CompiledParser(LR(0) 項集合・Action/Goto テーブル)
├── runtime.rs # CompiledParser + 入力 → ParserResult、build_trace
├── ast.rs # AstNode: Terminal(char) | NonTerminal(char, Vec<AstNode>)
├── validation.rs # 入力バリデーション
├── main.rs # ウィンドウセットアップ(初期サイズ 1200×800、最小 800×600)
├── app.rs # ParserApp 状態構造体 + eframe App 実装
│ # Page enum (Parser | Generator)
│ # ParseArtifacts, TraceCursorView, SmHighlightView
│ # build_parse_table(), build_animation_trace()
├── generator_engine.rs # GeneratorEngine: AST → Rust ソース生成
│ # run_generated_code(): temp ファイルに書き出して rustc 実行
└── pages/
├── mod.rs # ページモジュール宣言
├── parser.rs # Parser タブ UI(入力パネル・アニメーション・AST・パーステーブル)
├── generator.rs # Generator タブ UI(ロールセレクター・コードプレビューカード)
└── tree.rs # 共有ツリーレンダラー(LayoutNode, layout_ast, draw_tree)
# pub(super): pages モジュール内のみ参照可能
- LR コンフリクトはエラー:
lr::compileはコンフリクト発生時にErr(ParserError::ConflictReducer)を返す。UI ではUiError::Compileとして表示。 - Functional core / imperative shell: ライブラリモジュール(
grammar,lr,runtime)は純粋関数。副作用(ファイル I/O・プロセス起動)はgenerator_engine::run_generated_codeに限定。 - アルゴリズムスタブ:
ParserKind::Slr / Lalr / Lr1は拡張ポイントとして存在。選択すると "not yet implemented" を表示。 - 共有ツリーレンダラー:
pages/tree.rsはparser.rsとgenerator.rsの両方から利用。
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
eframe = "0.32.3"
egui = "0.32.3"- Rust edition 2024
rustcが PATH に存在する場合、Generator の Run 機能が利用可能
# リポジトリをクローン
git clone https://github.com/raiga0310/LR_parser.git
cd LR_parser
# ビルド
cargo build
# GUI を起動
cargo run