Flex分词程序生成器概览
flex是一个分词程序生成器,我们只用指定各种标记满足的模式和碰到它们时应执行的C代码,flex就能生成对应C语言的记法分析程序。
用法
Flex命令用法是常规的:
flex [OPTIONS] [FILE]...
如不用-o选项指定输出文件,默认为lex.yy.c。
flex语法
flex文件的总体结构如:
定义
%%
规则
%%
用户代码
定义部分
名字定义形如:
名字 值
其中名字由字母或下划线开始然后是若干个字母、数字或下划线,值从名字后首个非空字符到行末。后面可用{名字}引用(值)。
除非在%option行,可以用C风格从/*到*/的注释,会复制到输出。
缩进了或被%{与%}行包围的也会原样复制到输出(不含%{和%}。被%top{与%}行包围的也会原样复制到输出(不含%top{和%}),但会放到flex的定义前。
%s 状态
定义了一个状态,处于初始状态也视为处于此状态。
%x 状态
定义了一个状态,处于初始状态不视为处于此状态。
规则部分
每条规则如:
模式 动作
其中模式是不缩进的正则表达式,前面可加上以尖括号包围的用逗号分隔的状态列表,表示仅当当前状态在列表中时才可用此规则。由于经常有多个模式有相同的开始条件,可以设立开始条件作用域,如:
<ESC>{
"\\n" return '\n';
"\\r" return '\r';
"\\f" return '\f';
"\\0" return '\0';
}
相当于
<ESC>"\\n" return '\n';
<ESC>"\\r" return '\r';
<ESC>"\\f" return '\f';
<ESC>"\\0" return '\0';
一种特别模式是可选的开始条件后接<<EOF>>而非正则表达式,它匹配文件结束,通常用于设置yyin以便从其它文件继续。
动作从模式后首个非空字符到行末(或者花括号块结束),可以是任何C语句或者用|表示与下一条规则的动作同。动作中可用以下宏或函数:
| 宏或函数 | 用途 |
|---|---|
| ECHO | 把yytext输出 |
| BEGIN(状态); | 进入状态 |
| REJECT | 回退并寻找次优匹配 |
| yymore() | 下一迭代中把匹配值附加到当前yytext后而非取代之 |
| yyless(n) | 把yytext除前n个外的字符送加输入流 |
| unput(c) | 把字符c送回输入流 |
| input() | 读入一个字符 |
| YY_FLUSH_BUFFER; | 清空内部缓冲 |
| yyterminate() | 结束扫描 |
| yy_push_state(new_state) | 把当前状态推入栈并把状态设为new_state |
| yy_pop_state () | 把栈顶弹出成当前状态 |
| yy_top_state () | 返回栈顶 |
除非在预期正则表达式的地方,可以用C风格从/*到*/的注释,会复制到输出。
缩进了或被%{与%}行包围的也会原样复制到输出(不含%{和%}。里面定义的变量局部于扫描过程。
用户代码
用户代码会被原样复制到输出,通常是调用扫描器或被扫描器调用的过程。如果没有,可省略第二个%%。
flex扫描器的工作方式
扫描器yylex()会确定满足其中某个模式的最长字符串并决定对应规则(若有多于一个则选最先声明的),然后让指针yytext指向该字符串开始,让yyleng的值为长度,再执行相应动作。接着对余下文本重复这过程。
如果没有匹配,则执行默认规则,匹配下一个字符并写到输出。也就是说,flex文件%%会生成一个复制器。
yytext可定义为字符数组或字符指针(默认),可以在定义部分用导言%array或%pointer设置。数组的大小由宏YYLMAX控制。
状态YYSTART初始时为INITIAL。
输入和输出文件用yyin的yyout变量设置,默认为标准输入和输出。在碰到文件结束后可通过设置yyin或调用yyrestart(FILE *),再调用yylex()继续从其它文件读取输入。
更准确地,扫描器用宏YY_INPUT(buf,result,max_size)读取输入(默认从yyin读),它展开为已读字符数,0表示文件结束。当扫描器收到YY_INPUT指示文件结束,它会调用yywrap(),若它返回0则扫描器继续,否则扫描器结束。如果不手动定义yywrap(),则要用导言%option noyywrap指示它总返回1或者在链接时加选项-lfl。