根据POSIX Lex的说法,当达到文件结尾时,函数 input 将返回零:
int input(void) 返回输入中的下一个字符,或者在文件结尾处返回零。尽管可能,它应该从流指针yyin获得输入 通过中间缓冲区。因此,一旦扫描开始,效果 更改yyin的值是不确定的。阅读的字符应该是 无需任何处理即可从扫描仪的输入流中删除 通过扫描仪。
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/lex.html
但是,至少在Flex中,似乎输入有时会返回-1(EOF)而不是0.此外,我看到的一些示例依赖于EOF而不是0,例如在书中“Lex和Yacc”:
使用输入功能后,我真的需要测试0和EOF吗?
答案 0 :(得分:1)
我担心你确实需要检查这两个值。
据我所知,Posix总是要求input()
在输入结束时返回0,这是基于原始AT& T lex的行为。虽然这个规范可以很容易地重新定义input()
以接受来自字符串而不是外部文件的输入,但它也使得基本上不可能区分输入流中的NUL字节和EOF。对于原始的lex实现来说,这不是一个真正的问题,它没有尝试处理具有NUL字节的输入流。 (Posix不要求文本文件能够包含NUL字节,所以它也不是Posix的问题。)
Flex,渴望处理任意8位输入,重新定义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()
返回的值相同(& #34;下一个字节为unsigned char
转换为int
")。这肯定是flex的作用。如果您决定依靠该解释,您可以简单地测试input()
的返回值是否小于或等于0.
作为一个社论,我从未使用input()
而最终没有后悔。几乎总有一种更好的解决方案,通常涉及启动条件。除了此问题引用的详细信息之外,input()
与Flex基础结构无法很好地集成。使用input()
读取的字符无法添加到当前令牌中,也无法使用yyless()
进行重新处理。如果使用yylineno
读取换行符,则input()
的自动维护将失败,这可能会影响用户提供的列位置维护。等等。
使用AT& T lex,使用input()
跳过多行注释的文本有一定意义。在20世纪70年代,RAM是比现在更宝贵的资源,并且lex在处理大型令牌方面不是很擅长。因此,阅读(和构建)评论标记是不必要且具有潜在危险的一步,因为多行注释可能非常大(相对于标识符标记而言)。 AT& T lex使用input()
(通常别名为fgetc
)一次读取文件输入一个字符,因此使用input()
不会产生任何开销。
现在,这些都不成立。 RAM相对便宜,并且flex
不会因为必须使用足够大的内部缓冲区来保持多行注释而负担。另一方面,由于flex维护自己的内部缓冲区,因此需要在自己的缓冲区管理之上模拟input()
,这会产生一定的开销。因此,看到像我在flex手册中提到的那些片段一样,这应该是不常见的;基于开始条件的评论检测器更高效,更短,并且可读性更高:
"/*" BEGIN(COMMENT);
<COMMENT>[*]+/ BEGIN(INITIAL);
<COMMENT>[^*]+|[*]+ ;