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
。