我正在学习递归的正确解析,并提出了一些我认为算法不起作用的场景。其中一个是,考虑到这个简单的语法:
S→E;
E→id | id + id
然后字符串id + id;
在该语法的语言中有效。但是,如果我们执行递归下降算法,它会从S
下降到E
,然后再到id
,这是第一个匹配的终端。现在输入位于+
,我们回到S
尝试匹配;
,然后失败;但在S
级别没有其他规则可供选择。
我认为语法不含糊,因为语言id;
和id + id;
中只有2个字符串,每个字符串都有一个唯一的解析树。这里的一般问题是非终端具有相同前缀的产品,并且可能做出在递归中更深层次匹配但在较浅层次上创建无效输入的选择。
我已经读过关于递归下降的典型问题,如左递归,但没有发现上面提到的问题。这真的是一个问题,还是我错过了什么?
我从书Parsing Techniques: A Practical Guide p.182-188
中找到了一个权威的答案,它将上述方法归类为天真的递归体面,并突出了同样的问题。有两种解决方案总是适用于一般情况而没有预测(因为通常所需的前瞻长度随前缀长度而增加):穷举递归下降需要使用连续和广度优先递归下降。
答案 0 :(得分:1)
我在这方面如此生疏,以至于我可能要发布垃圾,但这不是可以解决的问题吗?类似的东西:
func recogniseS
expect(E)
expect(semicolon)
fund recogniseE
expect(id)
if nextTokenIs(plus) then
expect(plus)
expect(id)
endif
或者,同样地,你可以重新表述为:
S → id [+ id];
即。本质上只是+
是可选的。因此,只要可以处理任何可选项,就可以处理这种情况。
答案 1 :(得分:1)
这不是一个问题,因为可以像这样将语法分解(E'
的第一个选项是空的):
S → E ;
E → id E'
E' → | + id
对于E'
,如果下一个标记为;
,我们会预测第一个替代标记,如果下一个标记为+
,则预测第二个标记。
答案 2 :(得分:1)
这是一个问题,如果你写这样的PEG语法,它将无法工作。这是一个已知的问题,偶尔被描述为PEG解析的一个问题,但是我认为将人们编写的语法归咎于PEG是不公平的,因为其他解析形式也无法免除。
如果它不是PEG语法而是普通的旧CFG,除非你使用的工具是愚蠢的或有问题的,否则应该没有问题。它应该能够将其转换为有效的解析器,无论它是使用递归下降还是其他算法。如果它使用递归下降,它可能会使用lookahead,这将摆脱这种情况。