Lambda 带有flex和bison的文件结束标记(仅在没有它的情况下有效)

Lambda 带有flex和bison的文件结束标记(仅在没有它的情况下有效),lambda,bison,eof,flex-lexer,lambda-calculus,Lambda,Bison,Eof,Flex Lexer,Lambda Calculus,好的,这是一个奇怪的问题,因为我这里的工作方式是我想要的。我正在做的是为lambda演算表达式编写解析器。因此,表达式可以是以下四种情况之一: 变数 不变的 (表情) (lambda变量.表达式) 如您所见,最后两个表达式中包含表达式。我想做的是确定整个表达式,以便报告它是哪种类型。例如,表达式((λx.(f1 x))100)是一个整体组合。我的想法是在flex到达文件末尾时,从flex返回一个END令牌。我的代码如下所示: overallexpr: combo END { printf("

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

  • 变数
  • 不变的
  • (表情)
  • (lambda变量.表达式)
如您所见,最后两个表达式中包含表达式。我想做的是确定整个表达式,以便报告它是哪种类型。例如,表达式((λx.(f1 x))100)是一个整体组合。我的想法是在flex到达文件末尾时,从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
;
如果我把结束标记放在overallexpr中的四个可能性后面,比如ComboEnd,而不是combo,它就不起作用了。但是解析器接收到结束标记。如果我在读取时打印每个标记(使用变量、函数和数值),它看起来是这样的

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

这可能很难说,但这应该行得通。组合以RPARENS结束,后面有一个结束标记。但它不能作为一个整体表达式进行计算。然而,如果我拿出末端标记,它似乎每次都起作用。我总是打印出一条完整的消息,即使overallexpr和expr的产品完全相同。输出与上一个相同,只是在结束标记之前表示“整体表达式是一个组合”。所以我的问题是为什么?野牛总是先尝试早期的作品吗?为什么它没有终点却没有终点?特别是因为你可以看到结束标记后,它说这是一个组合。我只是想更好地了解Bison是如何工作的。

如果不看你的代码,就很难判断这里发生了什么(而且我也不想费力地看),但我想冒险猜测一下:我的猜测是,你正在用你的结束标记替换标准的yylex EOF指示(即返回0)。如果bison解析器从未看到EOF,那么它永远不会完成解析

实际上,bison自己创造了一种特殊的产品:

__parse__: __start__ $;
parse是(实际上未命名的)产品,
\uuuu start\uuuu
是您声明为
%start
的内容(或者第一个非终端,如果您没有明确声明)。在您的情况下,我想这是
超过allexpr
$
是通常用于指示EOF标记的符号

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

因此,在所有的可能性中,解析器实际上不会执行
overallexpr
缩减——或者换句话说,它不会执行与
overallexpr
规则相关联的操作——直到它确信文件结尾标记是下一个标记


现在,如果你把你的
END
标记放在规则之外,lexer实际上返回了EOF,那么bison在看到EOF时会进行缩减。

如果不看到你的代码,就很难判断这里发生了什么(而且我也不想费力地看它),但我要冒昧地猜测一下:我的猜测是您正在用您的结束令牌替换标准yylex EOF指示(即返回0)。如果bison解析器从未看到EOF,那么它永远不会完成解析

实际上,bison自己创造了一种特殊的产品:

__parse__: __start__ $;
parse是(实际上未命名的)产品,
\uuuu start\uuuu
是您声明为
%start
的内容(或者第一个非终端,如果您没有明确声明)。在您的情况下,我想这是
超过allexpr
$
是通常用于指示EOF标记的符号

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

因此,在所有的可能性中,解析器实际上不会执行
overallexpr
缩减——或者换句话说,它不会执行与
overallexpr
规则相关联的操作——直到它确信文件结尾标记是下一个标记

现在,如果您将
END
标记保留在规则之外,并且lexer实际返回EOF,那么bison在看到EOF时进行缩减