0. 引言
1. start condition
flex为有条件地激活规则提供了一种机制。 只有当扫描器处于名为“sc”的开始条件时,其模式前缀为“<sc>”的任何规则才会处于激活状态。 例如:
<STRING>[^"]* { /* eat up the string body ... */
...
}
< >
中可以为任意字符。比如上面的STRING,只有当扫描器处于“STRING”开始状态时,规则[^"]才会激活。
那么,如何退出这种规则呢?开始条件本身使用BEGIN激活。退出时使用BEGIN(0)
,BEGIN(0)
返回到没有启动条件的规则处于活动状态的原始状态。 这个状态也可以被称为开始条件INITIAL
,所以BEGIN(INITIAL)
等同于BEGIN(0)
。
为了说明启动条件的用法,下面是一个扫描器,它提供了两种不同的字符串解释,例如“123.456”。 默认情况下,它会将它视为三个标识(token),整数“123”,点('。')和整数“456”。 但是如果字符串在字符串“expect-floats”的前面出现,它会将其视为单个标记,即浮点数123.456:
%{
#include <math.h>
%}
%s expect
%%
expect-floats BEGIN(expect); //如果出现expect-floats ,进行expect的规则匹配
<expect>[0-9]+"."[0-9]+ {
printf( "found a float, = %f\n\n",
atof( yytext ) );
}
<expect>\n {
BEGIN(INITIAL); //如果匹配到换行符,退出整个expect匹配
}
// 下面的匹配规则不在BEGIN(expect); 之列,还和之前一样正常匹配。出现expect-floats时才触发BEGIN
[0-9]+ {
printf( "found an integer, = %d\n",
atoi( yytext ) );
}
"." printf( "found a dot\n" );
%%
int main(int argc, char* argv[]) {
yylex();
return 0;
}
int yywrap() {
return 1;
}
运行结果:
- 注意:开始条件没有自己的名称空间; %s和%x的声明方式与#define相同。
- 注意:expect-floats条件满足时输出的数小数点后保留6位是c语言的特性。
2. yymore()
告诉扫描程序下次匹配规则时,应将相应的令牌附加到yytext的当前值上,而不是替换它。
%%
mega- ECHO; yymore();
kludge ECHO;
例如,上面的程序。如果没有yymore的情况下,在输入为“ mega-kludge”时,会输出“mega-kludge”,在有yymore()的情况下,mega-匹配打印完还在缓存区存着一份mega-。在kludge 匹配成功后,缓冲区的mega-随着kludge 一起打印,所以将输出以下内容“ mega-mega-kludge”:
3. yyless()
yyless(n)将当前token的除前n个字符外的所有字符返回给输入流,在此位置,当扫描程序寻找下一个匹配项时,将重新扫描它们。 yytext和yyleng已适当调整(例如yyleng现在等于n)。
%%
foobar ECHO; yyless(3);
[a-z]+ ECHO;
例如,在输入“ foobar”上,以下内容将写出“ foobarbar”。相当于yyless(3)会将foobar的后三个(除前3个外)字符再进行一次匹配。
- 注意:yyless()出现在需要进行回退处理的情况下,yyless()的参数0将导致再次扫描整个当前输入字符串。 除非您更改了扫描程序随后处理其输入的方式(例如,使用BEGIN),否则将导致无限循环。
4. 综合应用——匹配字符串
code:
%%
\"[^\"\n]*\" {
if(yytext[yyleng-2]=='\\') /* 检查这个引号是不是转义字符 */
{
yyless(yyleng-1); /* 如果是转义字符需要退回进行重新匹配 */
yymore(); /*下一次被匹配的字符串被添加在当前识别出的字符串后面*/
}
else
{
printf("%s\n",yytext);;
}
}
\"[^\"\n]*$ {printf("Line %3d: Unterminated string %s\n",yylineno,yytext);}
/*此处\n不能省;帮忙判断一次输入结束*/
. ECHO;
%%
int main(int argc, char* argv[]) {
yylex();
return 0;
}
int yywrap() {
return 1;
}
结果:
这种是考虑的比较周到的;像中间有转义的引号的情况都能处理;"hello\"world"这样的字符串都能处理。
本文参考:https://zhuanlan.zhihu.com/p/65490271
更详细的flex使用方法:https://zhuanlan.zhihu.com/p/108167693
网友评论