flex学习 - Lex和Posix的兼容性
flex是AT&T Unix Lex工具的重写版(不过,这两个实现不共享任何代码),由一些扩展和不兼容性,对于那些希望编写两种实现都能接受的扫描程序的人来说,这两个问题都值得关注。flex完全符合POSIX Lex规范,除了使用%pointer(默认值)时,调用unput()会破坏yytext的内容,这与POSIX规范相反。在本节中,我们将讨论flex、AT&T lex和POSIX规范之间所有已知的不兼容性。flex的’-l’选项打开了与原始AT&T lex实现的最大兼容性,代价是生成的扫描器性能损失很大。我们将在下面说明使用’-l’选项可以克服哪些不兼容性。flex与lex完全兼容,但有以下例外:
1、不支持未记录的lex扫描器内部变量yylineno,除非使用’-l’或%option yylineno
2、应该以每个缓冲区为基础维护yylineno,而不是以每个扫描器(单个全局变量)为基础
3、yylineno不是POSIX规范的一部分
4、input()函数是不可重新定义的,尽管可以调用它来读取规则匹配的字符。如果input()遇到文件末尾,则完成正常的yywrap()处理。一个”真实的”文件结束符被input()作为EOF返回。
5、而是通过定义YY_INPUT()宏来控制输入
6、不能重新定义input()的灵活限制是与POSIX规范一致的,POSIX规范只是没有指定控制扫描器输入的任何方式,而是通过对yyin进行初始赋值。
7、unput()函数不可以被重新定义。此限制与POSIX一致。
8、flex扫描器不像lex扫描器那样可重入。特别是,如果你有一个交互式扫描器和一个中断处理程序,它从扫描器中跳出,并且扫描器随后被再次调用,你可能会得到以下消息:
fatal flex scanner internal error--end of buffer missed
要重新进入扫描器,请先使用:
yyrestart( yyin );
注意,这个调用将丢弃任何缓冲的输入;通常这不是交互式扫描器的问题。查看可重入章节,关于flex可重入API。
9、还要注意flex C++扫描器类是可重入的,所以如果你可以选择使用C++,那么你应该使用它们。查看Cxx章节,和可重入章节的详细信息
10、output()不被支持。从ECHO宏输出到文件指针yyout(默认的stdout)。
11、output()不是POSIX规范的一部分
12、lex不支持独占开始条件(%x),尽管它们在POSIX规范中
13、当展开定义时,flex将它们括在括号中。lex的使用,如下:
NAME [A-Z][A-Z0-9]*
%%
foo{NAME}? printf( "Found it\n" );
%%
将不匹配字符串’foo’,因为当宏展开时,规则相当于’foo[A-Z][A-Z0-9]?’,优先级是这样的,’?’与’[A-Z0-9]’相关联。使用flex,规则将扩展到’foo([A-Z][A-Z0-9])?’,因此字符串foo将匹配。
14、请注意,如果定义以’^’开头或以’$’结尾,则不会用括号展开,以允许这些操作符出现在定义中而不会失去器特殊含义。但是’<s>’,’/’和<
15、使用’-l’会导致定义周围没有括号的lex行为
16、POSIX规范要求定义用圆括号括起来
17、lex的一些实现允许规则的操作从单独的行开始,如果规则的模式有尾随空格的话:
%%
foo|bar
{ foobar_action();}
flex不支持这个功能。
18、不支持lex %r(生成一个Ratfor扫描程序)选项。它不是POSIX规范的一部分
19、在调用unput()之后,yytext在匹配下一个标记之前是未定义的,除非扫描器是使用%array构建的。lex和POSIX规范不是这种情况。’-l’选项消除了这种不兼容性。
20、‘{,}’(数值范围)运算符的优先级不同。lex的AT&T和POSIX规范将’abc{1,3}’解释为匹配’abc’的一次、两次或三次出现,而flex将其解释为匹配’ab’后跟’c’的一次、两次或三次出现。’-l’和’--posix’选项消除了这种不兼容性。
21、‘^’操作符的优先级不同。lex将’^foo|bar’解释为匹配foo在一行的开头,或bar在任何地方,而flex将其解释为匹配foo或bar,如果它们出现在一行的开头。后者与POSIX规范一致。
22、flex扫描器不需要lex支持的特殊表大小声明,例如%a。flex忽略了它们。
23、FLEX_SACNNER这个名字是#define的,因此扫描器可以编写为flex或lex。扫描器还包括YY_FLEX_MAJOR_VERSION,YY_FLEX_MINOR_VERSION和YY_FLEX_SUBMINOR_VERSION,这表明了生成扫描器的flex版本。例如,对于2.5.22版本,这些定义将分别是2、5和22。如果使用的flex版本是测试版,则定义符号flex beta
24、输入代码段中的符号’[[’和’]]’可能与m4分隔符冲突。查看M4分隔符章节
下面的flex功能没有被包括在lex或POSIX规范中:
1、C++扫描器
2、%option
3、开始条件范围
4、开始条件栈
5、交互/非交互扫描器
6、yy_scan_string()和friends
7、yyterminate()
8、yy_set_interactive()
9、yy_set_bol()
10、YY_AT_BOL()<
11、<
12、YY_DECL
13、YY_START
14、YY_USER_ACTION
15、YY_USER_INIT
16、#line directives
17、%{}’s around actions
18、可重入C API
19、单行上的多动作
20、几乎所有的flex命令行选项
“一行多动作”的特点是指使用flex,你可以把多个动作放在同一行,用分号分隔,而是用lex,以下内容:
foo handle_foo(); ++num_foos_seen;
(相当惊讶的)被截断为:
foo handle_foo();
flex不会截断动作。没有用大括号括起来的操作只是在行尾终止。