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

标签 bison flex-lexer eof

我正在尝试跟踪所有函数的签名,以便检查 - 当所有输入文件都已扫描时 - 是否所有函数都已定义,否则报告错误。为此,我希望扫描器将 END_OF_FILE 标记返回给解析器,以便调用我的检查过程,但我收到“标记未定义”错误,尽管我将其定义为标记解析器。

有什么建议吗?

最佳答案

发送您自己的文件结束标记很少是个好主意,如果您选择这样做,则需要格外小心。

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

如果你想在解析结束之前执行代码,你可以在开始生产时这样做:

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

如果您使用的是 bison,请注意:代码将在解析完成时执行,无论它是否成功完成。特别是,输入流中可能仍有未使用的 token 。 [注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. */
                 }
               }

如果您要发送自己的文件结束 token ,您需要确保仍然维护解析器和词法扫描器之间的契约,即:

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

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

这意味着您确实需要同时发送您的 token 和正确的 END token ,这意味着执行如下操作:

%% 
   /* 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 bool 值。您可以使它成为一个全局的,或者您可以构建一个可重入扫描器并将其添加到扫描器上下文对象的额外数据部分。这些都是在调用 yylex 之间维护扫描器状态的有用技术,但在这种特殊情况下,我认为使用它们不会获得任何好处,因为如上所述,几乎永远不需要发送自定义输入结束 token 。


至于您遇到的具体问题:

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

I get a "token undefined" error,

来自什么? Bison ?柔性?编译器?消息到底说了什么?它指的是你的代码的哪一行? (你是否准确地调用了文件结束标记 END_OF_FILE?)

注意事项

  1. 由于在原始 yacc 中处理输入结束标记的方式,原始 yacc 或 byacc 及其衍生版本不会发生这种情况。具有与原始 yacc 相同的输入结束处理的解析器生成器通常不会执行与开始生成相关的操作,除非已经遇到输入结束标记。

关于bison - 在输入文件中到达 EOF 时如何做某事?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42713823/

相关文章:

makefile - Make 添加意外的 mv 命令

c++ lex和bison对自制标记器/解析器的优势是什么

image - Docker - 从 docker repo 拉取失败 (EOF/403) 但从 RH repo 下载有效

ubuntu - stream_descriptor 的 boost::asio::async_read() 现在返回 EOF

c - 在 C 语言中正确使用 EOF

c - Bison:纯推送解析器中存储的最后一个 $$ 值在哪里?

c++ - 如何打印在 Yacc/Bison 中看到的任何内容?

c - flex bison,从文件读取时遇到标记后标记化停止

bison - flex/bison 将数字解释为 float

c++ - 匹配 ipv4 点分十进制表示法的 lex 模式