Parsing 语法中的间接递归

Parsing 语法中的间接递归,parsing,recursion,compiler-construction,grammar,Parsing,Recursion,Compiler Construction,Grammar,我试图从以下语法中删除间接递归: F -> P X X -> R C R -> C R | I R | epsilon 所有大写字母都是非终端,我刚刚停止制作,因为它们并不重要 在这之后,您可以看到我将得到类似于F->p(C | I)*C的东西,这会给我的递归下降解析器带来问题 任何有效的表达式都必须以C结尾,但这个最终的C总是通过重复使用R产品来使用,没有为X->R C产品的最终C留下任何标记 以下面的令牌表达式为例:“p C I C” 我们使用F->px产品删除第一个P

我试图从以下语法中删除间接递归:

F -> P X
X -> R C
R -> C R | I R | epsilon
所有大写字母都是非终端,我刚刚停止制作,因为它们并不重要

在这之后,您可以看到我将得到类似于F->p(C | I)*C的东西,这会给我的递归下降解析器带来问题

任何有效的表达式都必须以C结尾,但这个最终的C总是通过重复使用R产品来使用,没有为X->R C产品的最终C留下任何标记

以下面的令牌表达式为例:“p C I C”

  • 我们使用F->px产品删除第一个P,留下“cic”
  • 然后X->R C->C R C,这样我们就可以消耗C,留下“I C”
  • 然后R C->I R C,这样我们就可以消耗离开“C”的I
现在我们来解决这个问题。递归解析器只需选择继续扩展R,如下所示:

  • R C->C R C,所以我们消耗最后一个字符C,不留下任何剩余标记
在这一点上,尽管输入有效,我的程序还是会出错,因为最终的rc->C(使用epsilon产品)没有剩余的C可以匹配

我想我需要做的就是以某种方式巧妙地重新安排语法,以消除这种歧义。非常感谢您的帮助

您可以将
p(C | I)*C
重写为
pi*C+(I+C+)*
,这很容易作为递归下降解析器实现。如果你把它写成一个正确的递归BNF语法,你会得到不正确的结合性,但是通常你会用循环来编写递归下降解析器,使用上面的扩展BNF。[注1]

实际上,一旦解析了
p
,就会得到如下结果:

do {
  while (try_parse(I)) {}
  parse(C);
  while (try_parse(C)) {}
} while (try_parse(I));

笔记
  • 或者,如果我再写递归下降解析器,至少我会这么做。这是一个更直接的左递归语法,它是LALR(1),因此您可以使用bison生成解析器

  • @如果你对不涉及递归的语法使用“递归”下降解析器,它不是递归下降解析器…@Am\u I\u help它在逻辑上是正确的。如果语法没有递归,那么解析时就不需要递归。在OP的语法中解析R的方法必然会递归,因为语法是递归的。@davmac-嗯,的确如此。学习编译器设计课程已经有很长时间了(一年多以前),你是对的。我同意,@OP-应该是单词
    下降
    ,不合适。输入后面是否有一个终止符(文件结尾或类似的东西),您可以使用它(通过向前看)为
    R
    选择正确的生成规则?在后面(F)是第一(I)吗?