1

好的,这是一个奇怪的问题,因为我这里的东西按我想要的方式工作。我正在做的是为 lambda 演算表达式编写解析器。因此,表达式可以是以下四种情况之一:

  • 多变的
  • 持续的
  • (表情表达)
  • (lambda 变量。表达式)

现在如您所见,最后两个表达式中包含表达式。我试图做的是确定整体表达式,以便我可以报告它是哪种类型。例如,表达式 ((lambda x.(f1 x)) 100) 是一个整体组合。我的想法是当它到达文件末尾时从 flex 返回一个 END 令牌。我的代码如下所示:

overallexpr: combo END { printf(" The overall expression is a combination\n"); } |
         constant END { printf(" The overall expression is a constant\n"); } |
         VARIABLE END { printf(" The overall expression is a variable\n"); } |
         l_expr END { printf(" The overall expression is a lambda expression\n"); }
;

expr: combo | constant | VARIABLE | l_expr
;

combo: LPARENS expr expr RPARENS
;

constant: FUNCTION | NUMBER
;

l_expr: LPARENS LAMBDA VARIABLE DOT expr RPARENS
;

如果我将那个 END 标记放在像组合 END 一样的整体表达式中的四种可能性之后,而不是仅仅组合,它就行不通。但是解析器会收到 END 令牌。如果我在读取时打印每个标记(带有变量、函数和数值),它看起来像这样

LPARENS  LPARENS  LAMBDA  VARIABLE x  DOT  LPARENS  FUNCTION f1  VARIABLE x  RPARENS  RPARENS  NUMBER 100  RPARENS  END Sorry, Charlie

可能很难说,但这应该有效。该组合以 RPARENS 结尾,并且紧随其后有一个 END 标记。但它不会作为一个整体表达式进行评估。但是,如果我取出 END 令牌,它似乎每次都有效。即使overallexpr 和expr 的产生完全相同,我总是会打印出整体消息。输出与最后一个相同,只是它在 END 标记之前显示“整体表达式是一个组合”。所以我的问题是为什么?野牛总是先尝试早期的作品吗?为什么它可以在没有 END 而没有 END 的情况下工作?特别是因为您可以在它说它是一个组合之后立即看到 END 令牌。我只是想更好地了解 Bison 的工作原理。

4

1 回答 1

1

在没有看到您的代码的情况下很难判断这里发生了什么(而且我真的不想涉足它,无论如何),但我会冒险猜测:我的猜测是您正在替换标准 yylex EOF使用您的 END 令牌指示(即返回 0)。如果野牛解析器从未看到 EOF,则它永远不会完成解析。

实际上,野牛自己创造了一个特殊的产品:

__parse__: __start__ $;

parse是(实际上是未命名的)产生式,并且__start__是您声明的任何内容%start(或第一个非终端,如果您没有明确声明它)。在你的情况下,我想它是overallexpr. $是通常用于表示 EOF 标记的符号。

现在,野牛解析器操作何时发生?尽管在某些情况下,它们可能会发生在您认为会发生的地方(即紧接在生产中的最后一个标记之后),但它们通常不会发生,直到解析器偷看下面的标记。允许这样做;这就是为什么它被称为LALR(1)解析器:1它是在决定如何处理已经获得的令牌之前允许查看的未来令牌的数量。它几乎总是需要这些信息,并且经常像它一样工作,即使在你和我看来它不需要。

所以很可能,解析器实际上不会进行overallexpr归约——或者换句话说,它不会执行与overallexpr规则相关的动作——直到它说服自己文件结束标记是下一个标记.

现在,如果您将END令牌排除在规则之外并且词法分析器实际上返回 EOF,那么野牛在看到 EOF 时会进行归约。

于 2012-11-02T06:13:13.863 回答