Return Lex 输入函数的值

Return value of Lex input function

根据 POSIX Lex,函数 input 在到达文件末尾时应 return 为零:

int input(void) Returns the next character from the input, or zero on end-of-file. It shall obtain input from the stream pointer yyin, although possibly via an intermediate buffer. Thus, once scanning has begun, the effect of altering the value of yyin is undefined. The character read shall be removed from the input stream of the scanner without any processing by the scanner.

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/lex.html

但是,至少在 Flex 中,有时 input 似乎是 returns -1 (EOF) 而不是 0。此外,我看到的一些示例依赖于EOF 而不是 0,例如书中 "Lex and Yacc":

https://books.google.se/books?id=fMPxfWfe67EC&pg=PA152&lpg=PA152&dq=flex+input+returns+eof&source=bl&ots=RdLSgm5LEO&sig=sXajxhnlydQLz_GcZZuIaUONYlk&hl=sv&sa=X&ved=0ahUKEwjE58OwidDZAhWLiSwKHVdSD8kQ6AEIYDAF#v=onepage&q=flex%20input%20returns%20eof&f=false

我真的需要在使用函数 input 后测试 0 和 EOF 吗?

恐怕您确实需要检查这两个值。

据我所知,Posix 一直要求输入结束时 input() 到 return 0,这是基于原始 AT&T lex 的行为。虽然此规范使重新定义 input() 以接受来自字符串而不是外部文件的输入变得容易,但它也使得基本上无法区分输入流中的 NUL 字节和 EOF。这对于原始的 lex 实现来说并不是真正的问题,它没有尝试处理具有 NUL 字节的输入流。 (Posix 不要求文本文件能够包含 NUL 字节,因此对于 Posix 也不是问题。)

Flex,立志于处理任意8位输入,将input()API重新定义为returnEOF(负数,通常为-1)表示输入结束。在 2016 年 3 月 1 日发布的版本 2.6.1 之前,这是它的行为,该版本更改了接口以符合 Posix。至少,我认为这就是更改界面的原因。我找不到任何解释更改的文档,并且 commit 没有提供任何信息。

该更改未反映到文档中,该文档继续包含 example code with the old specification. (This code is very similar to the sample code in John Levine's books.) A badly-title bug complaining about the change was closed without commentary. The change does not appear in the Change Log

无论如何,Posix 此时不太可能更改,因此 lex 工具的其他实现可能会实现历史性的 flex 约定或 Posix 要求。 return 由 flex-generated 分析器编辑的值将取决于用于构建分析器的 flex 版本。因此可移植代码必须允许这两种约定。

Posix 没有明确要求 input() 编辑的值 return 是正数,但假设其意图是该值与return 由 fgetc() ("the next byte as an unsigned char converted to an int") 编辑的值。这当然是 flex 所做的。如果您决定依赖该解释,您可以简单地测试 input() 中的 return 值是否小于或等于 0。

作为社论,我从来没有使用过 input() 最终后悔。几乎总有更好的解决方案,通常涉及启动条件。除了这个问题引用的细节之外,input() 没有很好地与 flex 基础设施集成。使用input()读取的字符不能添加到当前令牌中,也不能使用yyless()重新处理。如果使用input()读取换行符,yylineno的自动维护将失败,这可能会影响user-supplied列位置的维护。等等。

对于 AT&T lex,使用 input() 跳过多行注释的文本具有一定的意义。在 1970 年代,RAM 是比现在珍贵得多的资源,而 lex 不太擅长处理大令牌。因此,读取(和构建)注释标记是一个不必要且具有潜在危险的步骤,因为多行注释可能非常大(相对于标识符标记而言)。 AT&T lex 读取文件使用 input()(通常别名为 fgetc)一次输入一个字符,因此使用 input() 不会产生任何开销。

这些天,none 成立。 RAM 相对便宜,并且 flex 不必使用足够大的内部缓冲区来容纳多行注释。另一方面,由于 flex 维护自己的内部缓冲区,它需要在自己的缓冲区管理之上模拟 input(),这确实会产生一定的开销。因此,很少会看到像我在 flex 手册中提到的那样的片段; start-condition-based 评论检测器更有效、更短,而且可以说更具可读性:

"/*"                 BEGIN(COMMENT);
<COMMENT>[*]+/       BEGIN(INITIAL);
<COMMENT>[^*]+|[*]+  ;