私は自由時間に構文解析を試していて、非常に単純な文法のシフト削減パーサーを実装したいと考えていました。多くのオンライン記事を読みましたが、解析ツリーの作成方法についてはまだ混乱しています。これが私がやりたいことの例です:
文法:
Expr -> Expr TKN_Op Expr
Expr -> TKN_Num
入力例を次に示します。
1 + 1 + 1 + 1
トークン化すると、次のようになります。
TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num
という事は承知しています:
- シフトとは、最初の入力トークンをスタックにプッシュし、それを入力から削除することを意味します
- 削減とは、スタック上の 1 つ以上の要素を文法要素に置き換えることを意味します。
したがって、基本的には、次のようになります。
Step 1:
Stack:
Input: TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num
What: Stack is empty. Shift.
Step 2:
Stack: TKN_Num
Input: TKN_Op TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num
What: TKN_Num can be reduced to Expr. Reduce.
Step 3:
Stack: Expr
Input: TKN_Op TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num
What: Cannot reduce. Shift.
Step 4:
Stack: Expr TKN_Op
Input: TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num
What: Cannot reduce. Shift.
Step 5:
Stack: Expr TKN_Op TKN_Num
Input: TKN_Op TKN_Num TKN_Op TKN_Num
What: TKN_Num can be reduced to Expr. Reduce.
// What should I check for reduction?
// Should I try to reduce incrementally using
// only the top of the stack first,
// then adding more stack elements if I couldn't
// reduce the top alone?
Step 6:
Stack: Expr TKN_Op Expr
Input: TKN_Op TKN_Num TKN_Op TKN_Num
What: Expr TKN_Op Expr can be reduced to Expr. Reduce.
Step 7:
Stack: Expr
Input: TKN_Op TKN_Num TKN_Op TKN_Num
What: ...
// And so on...
「何を減らすか」とは別に 間違いなく、解析ツリーを正しく構築する方法がわかりません。ツリーはおそらく次のようになります。
1 + o
|
1 + o
|
1 + 1
リダクションで新しいノードを作成する必要がありますか?
また、新しく作成したノードにいつ子を追加する必要がありますか? / 新しいルート ノードをいつ作成する必要がありますか?