我正在尝试解析我的空闲时间,并且我想实现一个非常简单的语法的shift-reduce解析器。我读过很多在线文章,但我仍然对如何创建分析树感到困惑。下面是我想要做的一个例子:使用shift-reduce解析构建解析树
语法:
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
我明白:
- 移装置推堆栈上的第一输入令牌和从输入
- 减少装置替换堆栈上的一个或多个元素与语法元素 除去它
所以,基本上,这应该发生:
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
我应该创建一个新的节点吗?
什么时候我应该添加孩子到新创建的节点/何时应该创建一个新的根节点?
感谢您的详细解答。还有一件事:我应该尽可能减少堆叠或尽可能减少? (当有两个可能的减少,优先级是什么? –
“尽量减少堆栈”?如果您的解析操作不提供选择,则您无法选择堆栈大小。如果没有冲突,则不必做出选择 - }如果您有选择,可以为优先级问题定义不同的答案,并获得不同的shift-reduce分析器。如果你有冲突,你的语法不是LALR(1);通过选择一个,你已经隐含地定义了你指定的BNF的一个有趣的变体是合法的。这个问题的正确答案是“阅读一本关于解析的书”,因为细节变得非常技术化。 –