Parsing 基于表的LL解析器是否可以在没有正确递归的情况下处理重复?
我理解LL递归下降解析器如何处理这种形式的规则:Parsing 基于表的LL解析器是否可以在没有正确递归的情况下处理重复?,parsing,parser-generator,ll,Parsing,Parser Generator,Ll,我理解LL递归下降解析器如何处理这种形式的规则: A = B*; 使用一个简单的循环,根据前瞻令牌是否匹配第一组B中的终端来检查是否继续循环。然而,我对基于表的LL解析器感到好奇:这种形式的规则在那里如何工作?据我所知,在一个实例中处理这种重复的唯一方法是通过右递归,但在不需要右关联解析树的情况下,这会打乱关联性 我很想知道,因为我目前正在尝试编写一个基于LL(1)表的解析器生成器,我不知道如何在不更改预期的解析树形状的情况下处理这样的情况。语法 让我们将EBNF语法扩展为简单的BNF,并假设
A = B*;
使用一个简单的循环,根据前瞻令牌是否匹配第一组B中的终端来检查是否继续循环。然而,我对基于表的LL解析器感到好奇:这种形式的规则在那里如何工作?据我所知,在一个实例中处理这种重复的唯一方法是通过右递归,但在不需要右关联解析树的情况下,这会打乱关联性
我很想知道,因为我目前正在尝试编写一个基于LL(1)表的解析器生成器,我不知道如何在不更改预期的解析树形状的情况下处理这样的情况。语法
让我们将EBNF语法扩展为简单的BNF,并假设b
是一个终端,
是一个空字符串:
A -> X
X -> BX
X -> <e>
B -> b
跟戏
Follow(A)
是可以
立即出现在非终结符a
的右侧
Follow(A) : $
Follow(X) : $
Follow(B) : b$
桌子
我们现在可以基于集合构建表,$
是输入结束标记
+---+---------+----------+
| | b | $ |
+---+---------+----------+
| A | A -> X | A -> X |
| X | X -> BX | X -> <e> |
| B | B -> b | |
+---+---------+----------+
结论
如您所见,可以毫无问题地解析形式为A=B*
的规则。为inputbb
生成的具体解析树是:
是的,这绝对是可能的。重写为BNF并构造解析表的标准方法对于计算解析器应该如何工作非常有用——但据我所知,您要问的是如何避免递归部分,这意味着您将得到AST的倾斜二叉树/链表形式 如果您手工编写解析器,您可以简单地使用一个循环,使用解析表中的lookaheads指示一个递归调用,以决定再次循环。(也就是说,您可以只使用
而使用那些lookahead作为条件。)然后对于每个迭代,您只需将构造的子树作为当前父树的子树追加。在您的情况下,A
将得到几个直接的B
-子级
现在,据我所知,您正在构建一个解析器生成器,通过plan BNF遵循标准过程可能是最简单的。然而,这并不是一个真正的问题;毕竟,迭代和递归之间没有实质性的区别。您只需要有一类“助手规则”,它们不引入新的AST节点,而是将它们的结果附加到触发它们的非终端的节点。因此,当将重复转换为X->BX
时,而不是构造X
节点,您可以使用X
规则通过自己的子节点扩展A
或X
的子列表。您最终仍然会看到A
有几个B
子节点,并且看不到X
节点。此答案使用标准的右递归过程。问题是如何避免正确的递归,以及生成的AST与EBNF不匹配。
+---+---------+----------+
| | b | $ |
+---+---------+----------+
| A | A -> X | A -> X |
| X | X -> BX | X -> <e> |
| B | B -> b | |
+---+---------+----------+
+-------+-------+-----------+
| Stack | Input | Action |
+-------+-------+-----------+
| A $ | bb$ | A -> X |
| X $ | bb$ | X -> BX |
| B X $ | bb$ | B -> b |
| b X $ | bb$ | consume b |
| X $ | b$ | X -> BX |
| B X $ | b$ | B -> b |
| b X $ | b$ | consume b |
| X $ | $ | X -> <e> |
| $ | $ | accept |
+-------+-------+-----------+