三. Flex进阶:需要了解的一些知识
参考:
词法分析器生成工具flex
词法分析器总结--flex&bison
词法分析生成器flex的选项
1. Flex的一些常见选项:
%option 7bit
,%option 8bit
:指示flex生成一个7bit或8bit的扫描器与-7,-8 选项等价。
%option caseful
,%option case-sensitive
:区分大小写,与-i相反。
%option case-insensitive
,%option caseless
:忽略大小写,与-i选项等价。
%option debug
:让生成的扫描器运行在debug模式,与-d选项等价。
%option yylineno
:flex 生成的扫描器用全局变量yylineno 维护着输入文件的当前行编号。option lex-compat隐含有这个选项。
%option interactive
:指示flex生成一个交互式的扫描器。交互式扫描器就是向前查看下一个匹配的token是什么。结果就是总向前多看了一个字符,即使是在扫描器已经看够了文本已经排除了token 的歧义。但向前查看给了扫描器强大的交互能力。与-I等价。
%option yylineno
:记录符号所在行号。如果使用了%option lex-compat
,则隐含地使用了该选项。
%option yywrap
:如果没有设置(就如%option noyywrap
),当扫描器遇到end-of-file 时,不会调用yywrap(),但简单的假定没有更多的文件可以扫描(直到用户把yyin 指向新的文件并再一次调用yylex())。
%option bison-bridge
:生成的扫描器API能够被bision调用。API为与bision兼容而作了些小改变。
%option reentrant
:生成可重用的扫描器API,这些API用于多线程环境。
%option c++
:如果没有指定该选项,生成的扫描器.c文件是C语言格式的,指定后则生成C++文件。
%option array
:yytext的类型由char *变为数组。
%option pointer
:与--array, %option array相反。
2. 一些常用全局变量和宏
(1) FILE
\*yyin
,\*yyout
:为指向字符输入和结果输出文件的指针。如用户未对其定义,则设为标准输入文件stdin
和stdout
。
(2)int yylex()
:为词法分析程序,它自动移动文件指针yyin和yyout
。在定义模式动作时,用户可用return语句结束yylex()
,return 必须返回一整数。由于yylex()的运行环境都是以全局变量
的方式保存,因此,在下一次调用yylex()时,yylex()可从上次扫描的断点处继续 扫描,在语法分析时,可利用这一特性。若用户未定义相应的return语句,则yylex()继续分析被扫描的文件,直到碰到文件结束标志EOF
。在读到 EOF时,yylex()调用int yywrap()
函数(该函数用户必须提供),若该函数返回非0值,则yylex()返回0而结束。否则,yylex()
继续对yyin
指向的文件扫描。
(3) char *yytext
:存放当前被识别的词形
。
(4) int yyleng
:存放字符串yytext的长度
。
(5)int yywrap()
:参见(2)
(6) yymore()
:将当前识别的词形保留在yytext中,分析器下次扫描时的词形将加追加在yytext中。例模式定义如下
……
hello {printf(“%s!”,yytext);yymore();}
world {printf(“%s!”,yytext);}
……
当输入串为”helloworld”时,将输出”hello!helloworld!”
(7) yyless(int n)
:回退当前识别的词形中n个字符到输入中
(8) unput(char c)
:回退字符c到输入,它将作为下一次扫描的开始字符
(9) input()
:让分析器从输入缓冲区
中读取当前字符,并将yyin
指向下一字符
(10) yyterminate()
:中断对当前文件的分析,将yyin指向EOF。
(11) yyrestart(FILE * file)
:重新设置分析器的扫描文件为file
(12) ECHO
:将当前识别的字符串拷贝到yyout
(13) BEGIN
:激活开始条件对应的模式
(14) REJECT
:放弃当前匹配的字符串和当前的模式,让分析器重新扫描当前的字符串,并选择另一个最佳的模式再次进行匹配。
3. 条件模式
LEX提供控制模式在一定状态下使用的功能,称为条件模式。LEX首先在定义部份通过%start
来定义条件句。在规则部份可通过宏
BEGIN 条件名
来激活条件。BEGIN INITIAL
或BEGIN 0
将休眠所有的条件模式,使分析器回到开始状态。
例:将输入文件中的单词”magic” 作如下处理:识别”magic”时,如”magic”所在行行首为字符’a’,则输出”first”;若为’b’,则输出”second”;否则,输出”magic”。如不用条件模式,LEX源文件可这样写:
%{int flag;}%
%%
^a {flag=’a’;ECHO;}
^b {flag=’b’;ECHO;}
/n {flag=0;ECHO;}
magic {
switch(flag)
{
case ‘a’:printf(“first”);break;
case ‘b’:printf(“second”);break;
default :ECHO;break;
}
}
%%
如使用条件模式,则上述源文件可简化为
%start AA BB CC
%%
^a {ECHO;BEGIN AA;}
^b {ECHO;BEGIN BB;}
/n {ECHO;BEGIN 0;}
<AA>magic {printf(“first”);}
<BB>magic {printf(“second”);}
%%