Lex输入功能的返回值

时间:2018-03-03 12:13:54

标签: posix flex-lexer lex

根据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”:

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

使用输入功能后,我真的需要测试0和EOF吗?

1 个答案:

答案 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>[^*]+|[*]+  ;