在输入文件中达到EOF时如何做某事?

时间:2017-03-10 08:38:56

标签: bison flex-lexer eof

我正在尝试跟踪所有功能的签名以便检查 - 当所有输入文件都已被扫描时 - 如果已经定义了所有这些,则报告错误。为此,我希望扫描程序向解析器返回一个END_OF_FILE令牌,以便调用我的检查过程,但是我收到了“令牌未定义”错误,虽然我将其定义为解析器中的令牌。 / p>

有什么建议吗?

1 个答案:

答案 0 :(得分:4)

发送您自己的文件结尾令牌非常不错,如果您选择这样做,则需要非常谨慎。

幸运的是,几乎没有必要这样做。

如果要在解析结束之前执行代码,可以在开始生产中执行此操作:

start: program { /* Code to execute at the end of the parse */ }
     ;

如果您正在使用bison,则需要注意:代码将在解析完成时执行,无论代码是否成功完成。特别是,输入流中仍有未消耗的令牌。 [注1]

在许多情况下,这不是问题。将立即检测到错误(除非操作调用YYACCEPT)并进行额外检查,即使解析失败通常也不是问题。在某些应用程序中,您甚至可能想要这种行为;例如,如果要解析嵌入在较大文本中的表达式,并且不希望坚持将已解析的上下文扩展到文本的末尾。

但是,如果您确实需要知道解析是否完整,只需检查yychar的值是否为YYEOF就足够了(有关详细信息,请参阅bison manual 。)所以你可以用以下代码替换上一个:

start: program { if (yychar == YYEOF) {
                    /* Code to execute at the end of the parse */
                 }
                 else {
                    /* There is definitely an error. Probably do nothing. */
                 }
               }

如果您要发送自己的文件结束标记,则需要确保仍然保持解析器和词法扫描程序之间的合同,即:

  • 扫描器通过返回0作为标记值来指示输入结束;和
  • 解析器在收到0之后不会请求另一个令牌。

虽然词汇扫描程序有时可以处理违反第二个条件的行为,但它是未定义的行为,并且在某些情况下,生成的扫描程序将发生段错误或执行其他不良操作。由于解析器不会将您的自定义文件结束标记理解为输入结束,因此在收到后会继续请求更多标记。

这意味着您确实需要发送令牌和正确的END令牌,这意味着执行以下操作:

%% 
   /* This code is inserted at the top of yylex */
   static int eof_reached = 0; /* Note: not reentrant */
   if (eof_reached) return END;
 /* ... */
<<EOF>> { eof_reached = 1; return MY_END_OF_FILE; }

这样可行,但是由于没有办法重置eof_reached布尔值,扫描程序只能使用一次。您可以将其设置为全局扫描程序,或者可以构建可重入扫描程序并将其添加到扫描程序上下文对象的额外数据部分。这些都是在yylex调用之间维护扫描程序状态的有用技术,但在这种特殊情况下我不认为使用它们可以获得任何东西,因为如上所述,实际上几乎不需要发送自定义输入结束令牌。

至于您遇到的确切问题:

如果没有更多细节,就无法回复:

  

我收到“令牌未定义”错误,

从什么?野牛?柔性?编译器?消息准确地说了什么?你指的代码是什么? (你是否正确地调用了文件令牌的结尾END_OF_FILE?)

注释

  1. 由于在原始yacc中处理结束输入令牌的方式,原始yacc或byacc及其派生词不会发生这种情况。除非已经遇到输入结束令牌,否则具有与原始yacc相同的输入结束处理的解析器生成器通常不会执行与启动生成相关联的操作。