Algorithm 递归下降相同前缀

Algorithm 递归下降相同前缀,algorithm,parsing,context-free-grammar,recursive-descent,Algorithm,Parsing,Context Free Grammar,Recursive Descent,我正在学习递归体面解析,并提出了一些我认为算法不起作用的场景。考虑到这一简单语法,其中之一是: → E E→ id | id+id 然后字符串id+id在此语法的语言中有效。然而,如果我们执行递归下降算法,它将从S下降到E,然后下降到id,这是第一个匹配的终端。现在输入在+处,我们回到S尝试匹配然后失败;但是在S级别没有其他规则可供选择 我认为语法没有歧义,因为在id语言中只有两个字符串和id+id,每个都有一个唯一的解析树。这里的一般问题是,非终结符具有相同前缀的结果,并且可能会在递归的更深层

我正在学习递归体面解析,并提出了一些我认为算法不起作用的场景。考虑到这一简单语法,其中之一是:

→ E
E→ id | id+id

然后字符串
id+id在此语法的语言中有效。然而,如果我们执行递归下降算法,它将从
S
下降到
E
,然后下降到
id
,这是第一个匹配的终端。现在输入在
+
处,我们回到
S
尝试匹配
然后失败;但是在
S
级别没有其他规则可供选择

我认为语法没有歧义,因为在
id语言中只有两个字符串
id+id,每个都有一个唯一的解析树。这里的一般问题是,非终结符具有相同前缀的结果,并且可能会在递归的更深层次上进行匹配的选择,但会为较浅层次创建无效的输入

我读过关于递归下降的典型问题,比如左递归,但没有发现上面提到的问题。这真的是个问题还是我遗漏了什么



我从《解析技术:实用指南》第182-188页找到了权威的答案,该书将上述方法归类为幼稚的递归方法,并强调了同样的问题。有两种解决方案始终适用于无前瞻性的一般情况(因为通常所需的前瞻性长度随前缀长度的增加而增加):穷举递归下降,需要使用连续性和广度优先递归下降

我对这件事太生疏了,我可能就要发垃圾了,但这不是可以通过前瞻解决的吗?比如:

func recogniseS
    expect(E)
    expect(semicolon)

fund recogniseE
    expect(id)

    if nextTokenIs(plus) then 
        expect(plus)
        expect(id)
    endif
或者,类似地,您可以重新表述为:

S → id [+ id];

i、 e.本质就是
+
是可选的。因此,只要可以处理任何可选的问题,这种情况都可以处理。

只要我们能够像这样考虑语法(其中
E'
的第一个选项为空),这就不是问题:


对于
E'
,如果下一个令牌是
,我们预测第一个备选方案+

,这是一个问题,因为如果您编写这样的PEG语法,它将无法工作。这是一个已知的问题,偶尔也被描述为PEG解析的问题,但我认为将PEG无法处理的语法归咎于PEG是不公平的——其他解析形式也不能幸免


如果它不是一个PEG语法,而是一个普通的旧CFG,那么应该没有问题,除非您使用的工具很愚蠢或有bug。它应该能够将其转换为工作解析器,而不管它使用的是递归下降算法还是其他算法。如果它使用递归下降,它可能会使用前瞻,这将消除这种情况。

实际上,我知道有一种适用于这种情况的语法。只需不生成具有相同前缀的相同非终端,如E->E;|E+E′;和E'->id。但这个玩具示例是因为我想知道递归下降对于特定语法(不是该语法的语言,它也可以由使用递归下降或其变体LL(1)的替代语法描述)是否固有缺陷。是的,这是使用递归下降变体LL(1)的预测性解析。但我的问题是,递归下降法是否适用于特定的语法,而不是它的语言,它也可以用另一种适用于递归下降法的语法来描述。另一种可能性是,我描述的语法不是有效的上下文无关语法,似乎规则的有序匹配(即PEG)在这些情况下会导致递归下降失败。
S → E ;
E → id E'
E' → | + id