最近、 LALRジェネレーターを書くのに十分なほどLALRに頭を悩ませており、そのためのJavaまたはc#スタイルの文法を構築しようとしています(その始まりはここで指定されています)。
車輪の再発明のように、パーサー ジェネレーターを作成するのは余分な労力であることはわかっていますが (なぜ Antlr を使用しないのですか?)、私の目標は、サードパーティのツールチェーンに依存せずに自分自身をコンパイルできるホビー OS をブートストラップすることです。私の問題はジェネレーターではなく、文法にあります。
ステートメントと式のあいまいさを減らす/減らすことに遭遇しています。
dangling-else などの特定の種類のあいまいさを解決する方法は知っていますが、これらのいくつかは直感的ではなく、困惑しています。
これらを解決する最善の方法は何ですか? また、ソリューションの視覚化に役立つプロトタイピング ツールはありますか? それとも、振り出しに戻って、文法用の GLR パーサー ジェネレーターを実装してみるべきでしょうか?
これらのステートメントは合法です。
Generic.List<int> myVar1 = x + 4, myVar2; // stmt -> var-decl ;
// var-decl -> type-name var-decl-list
t = 99; // simple-stmt -> assign
i++; // simple-stmt -> incr-decr
// incr-decr -> primary-expr ++
json.deserialize<list<int>>(obj); // simple-stmt -> call
// call -> primary-expr ( params )
// ... -> primary-expr . basic-name ( params )
// ... -> basic-name . basic-name ( params )
設定方法は次のとおりです。
basic-name : ident < type-list >
| ident
nested-name : nested-name . basic-name
| basic-name
basic-type : int | bool | ...
type-name : nested-name
| basic-type
stmt : var-decl ;
| simple-stmt ;
| ...
var-decl : type-name var-decl-list
var-decl-list : var-decl-list , var-init
| var-init
var-init : ident assign-op expression
| ident
simple-stmt : assign
| call
| incr-decr
expr : assign-expr
assign-expr : assign
| cond-expr
assign : unary-expr assign-op expr
...
rel-expr : rel-expr < shift-expr
...
| shift-expr
...
unary-expr : unary-op primary-expr
| primary-expr
unary-op : + - ! ~ ++ -- // Prefix operators
| ( type-name ) // Conversion operator
primary-expr : call
| primary-expr . basic-name
| primary-expr ++
| ( expr )
...
| basic-name
call : primary-expr ( params )
incr-decr : primary-expr ++
| -- primary-expr
| ...
したがって、パーサーがステートメントを予期している場合、*LR(k) アイテム セット カーネルはmethod-body -> { * stmts-opt }
、状態の完全なアイテム セットは次のようになります。
method-body -> { * stmts-opt }
stmts-opt -> * stmts
stmts-opt -> *
stmts -> * stmts stmt
stmt -> * var-decl ;
stmt -> * simple-stmt ;
var-decl -> * type-name var-decl-list
simple-stmt -> * assign
simple-stmt -> * call
simple-stmt -> * incr-decr
type-name -> * nested-name
type-name -> * basic-type
nested-name -> * nested-name . basic-name
nested-name -> * basic-name
basic-name -> * ident < type-list >
basic-name -> * ident
assign -> * unary-expr assign-op expr
unary-expr -> * unary-op primary-expr
unary-expr -> * primary-expr
unary-op -> * ( typename )
unary-op -> * ! | ~ | ...
primary-expr -> * call
primary-expr -> * primary-expr . basic-name
primary-expr -> * primary-expr ++
primary-expr -> * basic-name
primary-expr -> * ( expr )
call -> * primary-expr ( params )
incr-decr -> * primary-expr ++
...
識別子がシフトされると、次の状態になります。
basic-name -> ident *
basic-name -> ident * < type-list >
これは解析または縮小され、次の状態になります。
nested-name -> basic-name *
primary-expr -> basic-name *
競合の可能性。nested-name
親状態では、とにドットがあるため、先読みは役に立ちませんprimary-expr
。よし、ネストされた名前で削減してみましょう:
type-name -> nested-name *
nested-name -> nested-name * . basic-name
ここには何も表示されません...では、primary-expr
代わりに by を減らすのはどうですか:
unary-expr -> primary-expr *
primary-expr -> primary-expr * . basic-name
primary-expr -> primary-expr * ++
call -> primary-expr * ( params )
incr-decr -> primary-expr * ++
...
++ をシフトすると、次のようになります。
primary-expr -> primary-expr ++ *
incr-decr -> primary-expr ++ *
...別のreduce-reduce競合。
(
の代わりに をシフトしてみましょうident
:
primary-expr -> ( * expr )
unary-op -> ( * type-name )
expr -> * assign-expr
assign-expr -> * assign
assign-expr -> * cond-expr
assign -> * unary-expr assign-op expr
unary-expr -> * unary-op primary-expr
unary-expr -> * primary-expr
unary-op -> * ( typename )
unary-op -> * ! | ~ | ...
primary-expr -> * call
primary-expr -> * primary-expr . basic-name
primary-expr -> * primary-expr ++
primary-expr -> * basic-name
primary-expr -> * ( expr )
call -> * primary-expr ( params )
cond-expr -> * ...
...
rel-expr -> * rel-expr < shift-expr
rel-expr -> * shift-expr
...
type-name -> * nested-name
type-name -> * basic-type
nested-name -> * nested-name . basic-name
nested-name -> * basic-name
basic-name -> * ident < type-list >
basic-name -> * ident
ident
または(
をスタックにシフトする場合も同じ問題が発生します。
これらは、私がこれまでに遭遇したものです。basic-name
は よりも優先されるため、 のようなものは と解釈され、実際に関係式である場合はエラーになるとrel-expr
想定しています。x < n
basic-name -> ident < type-list *
私の脳は、本当に助けが必要なところまで来ました。