恐怕您确实需要检查这两个值。
据我所知,Posix 一直要求 input() 在输入结束时返回 0,这是基于原始 AT&T lex 的行为。虽然这个规范使得重新定义input() 以接受来自字符串而不是外部文件的输入变得很容易,但它也使得在输入流中的 NUL 字节和 EOF 之间进行区分基本上是不可能的。这对于最初的 lex 实现来说并不是真正的问题,它没有尝试处理具有 NUL 字节的输入流。 (Posix 不要求文本文件能够包含 NUL 字节,因此对 Posix 来说也不是问题。)
渴望处理任意 8 位输入的 Flex 重新定义了 input() API 以返回 EOF(负数,通常为 -1)以指示输入结束。在 2016 年 3 月 1 日发布的 2.6.1 版本之前,它的行为一直如此,该版本更改了接口以符合 Posix。至少,我认为这就是改变界面的原因。我找不到任何解释更改的文档,commit 没有提供任何信息。
该更改未反映在文档中,该文档继续包含example code with the old specification。 (此代码与 John Levine 书中的示例代码非常相似。)badly-title bug complaining about the change 已关闭,没有评论。更改不会出现在Change Log 中。
无论如何,Posix 在这一点上不太可能发生变化,因此lex 工具的其他实现可能会实现历史上的 flex 约定或 Posix 要求。由 flex 生成的分析器返回的值将取决于用于构建分析器的 flex 版本。因此可移植代码必须同时支持这两种约定。
Posix 没有明确要求 input() 返回的值是正数,但假设其意图是该值与 fgetc() 返回的值相同似乎是合理的(“下一个字节为unsigned char 转换为 int")。这当然是 flex 所做的。如果您决定依靠这种解释,您可以简单地测试来自 input() 的返回值是否小于或等于 0。
除了社论之外,我从来没有使用过input() 而不最终后悔。几乎总是有更好的解决方案,通常涉及开始条件。除了这个问题引用的细节之外,input() 没有与 flex 基础设施很好地集成。使用input() 读取的字符不能添加到当前令牌中,也不能使用yyless() 重新处理。如果使用input() 读取换行符,yylineno 的自动维护将失败,这可能会影响用户提供的列位置维护。以此类推。
对于 AT&T lex,使用input() 跳过多行 cmets 的文本具有一定的意义。在 1970 年代,RAM 是比现在更宝贵的资源,而 lex 不太擅长处理大型令牌。因此,读取(和构建)注释标记是不必要且潜在危险的步骤,因为多行 cmets 可能非常大(例如,相对于标识符标记)。 AT&T lex 读取文件使用input()(通常别名为fgetc)一次输入一个字符,因此使用input() 不会产生任何开销。
这些天来,这些都不成立。 RAM 相对便宜,flex 不必使用足够大的内部缓冲区来保存多行注释。另一方面,由于 flex 维护自己的内部缓冲区,它需要在自己的缓冲区管理之上模拟input(),这确实会产生一定的开销。因此,像我在 flex 手册中提到的那样看到 sn-ps 应该是不常见的;基于开始条件的评论检测器更高效、更短,并且可以说更具可读性:
"/*" BEGIN(COMMENT);
<COMMENT>[*]+/ BEGIN(INITIAL);
<COMMENT>[^*]+|[*]+ ;