我有一个匹配的简单模式:head + content + tail,我有一个如下所示的lex文件:
$ cat b.l
%{
#include<stdio.h>
%}
%%
"12" {printf("head\n");}
"34" {printf("tail\n");}
.* {printf("content\n");}
%%
我希望在会面时能够满足&#34; 12&#34;它将打印&#34; head&#34;,当遇到&#34; 34&#34;它将打印&#34; tail&#34;,任何其他连续的字符串,它将打印&#34; content&#34;。
所以我编译并运行它:
lex b.l && gcc lex.yy.c -ll
$ echo '12sdaesre34'|a.out
content
我的期望是,它会打印
head
content
tail
但实际上它只打印&#34;内容&#34;线。我有什么不妥,怎么纠正?
谢谢!
答案 0 :(得分:2)
(F)lex始终匹配最长的令牌。由于.*
会匹配任何不包含换行符的序列,因此它会很乐意匹配12sdaesre34
。 (在(f)lex中,.
匹配除换行符之外的任何字符。)因此,34
不再可用于匹配。
要解决此问题,您必须明确要content
匹配的内容。例如,以下内容将匹配任何不包含数字的内容:
[^[:digit:]]+ { printf("content\n"); }
您可能希望将新行添加到不匹配的字符列表中:
[^\n[:digit:]]+ { printf("content\n"); }
或者您想要匹配不包含34
的最长序列。这很棘手,但可以做到:
([^3]|3+[^34])+ { printf("content\n"); }
但是,这仍然会与初始12
匹配,因此它不足以解决问题。
如果您的输入始终由可能与其他内容穿插的12...34
形式的字符串组成,则可以匹配整个12...34
序列并将其拆分为三个标记。这无疑是最简单的解决方案,因为开始和结束标记具有已知长度。以下第一个模式匹配一个不开始12
的字符串,在12
的第一个实例之前结束,第二个匹配从12
开始并结束的字符串在34
的第一个实例(匹配)。这两种模式都不会匹配包含不匹配12
的输入;所以增加了第三条规则以匹配该案例;它看起来很像第二条规则,但最后并没有包含34
的匹配。因为(f)lex总是匹配最长的令牌,所以第三条规则只有在第二条规则失败时才会成功。
([^1]|1+[^12])* { puts("content"); }
12([^3]|3+[^34])*34 { puts("head content tail"); }
12([^3]|3+[^34])* { puts("error"); }
通常,您希望实际捕获content
的值以传递给调用程序。在第一条规则中,这只是yytext
,但在第二条规则中,内容包含从yyleng-4
开始的yytext+2
个字符(为了删除前导和尾随分隔符)。
对于大多数用途,如果需要保留匹配的令牌,则必须复制匹配的令牌,因为yytext
指向词法扫描器使用的内部数据结构,指针将被下一个模式匹配无效。对于第一条规则,您可以使用strcpy
创建字符串的副本,但对于第二条规则,您希望自己制作副本:
([^1]|1+[^12])* { yylval = strcpy(yytext); ... }
12([^3]|3+[^34])*34 { yylval = malloc(yyleng-3);
memcpy(yylval, yytext, yyleng-4);
yylval[yyleng-4] = '\0';
...
}
那些假设yylval
是char*
类型的全局变量,并且代码中的某个地方free()
由规则保存的字符串。他们还假设您在省略的代码(yylval
)中使用...
执行某些操作,或者您返回到调用者,并指示是否遇到了头部和尾部。