我的 lex 模式无法匹配我的输入文件,如何更正它?
My lex pattern doesn't work to match my input file, how to correct it?
我有一个简单的匹配模式:head+content+tail,我有一个如下所示的 lex 文件:
$ cat b.l
%{
#include<stdio.h>
%}
%%
"12" {printf("head\n");}
"34" {printf("tail\n");}
.* {printf("content\n");}
%%
我希望遇到“12”时打印"head",遇到“34”时打印"tail",任何其他连续的字符串,打印"content"。
所以我编译并 运行 它:
lex b.l && gcc lex.yy.c -ll
$ echo '12sdaesre34'|a.out
content
我的预期是,它会打印出来
head
content
tail
但实际上它只打印 "content" 行。我有没有看错,如何改正?
谢谢!
(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
开头并以 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] = '[=14=]';
...
}
那些假设 yylval
是类型 char*
的全局变量,并且在代码的某处你 free()
规则保存的字符串。他们还假设您在省略的代码 (...
) 中用 yylval
做了一些事情,或者您向调用者 return 指示是否遇到了头和尾。
我有一个简单的匹配模式:head+content+tail,我有一个如下所示的 lex 文件:
$ cat b.l
%{
#include<stdio.h>
%}
%%
"12" {printf("head\n");}
"34" {printf("tail\n");}
.* {printf("content\n");}
%%
我希望遇到“12”时打印"head",遇到“34”时打印"tail",任何其他连续的字符串,打印"content"。
所以我编译并 运行 它:
lex b.l && gcc lex.yy.c -ll
$ echo '12sdaesre34'|a.out
content
我的预期是,它会打印出来
head
content
tail
但实际上它只打印 "content" 行。我有没有看错,如何改正?
谢谢!
(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
开头并以 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] = '[=14=]';
...
}
那些假设 yylval
是类型 char*
的全局变量,并且在代码的某处你 free()
规则保存的字符串。他们还假设您在省略的代码 (...
) 中用 yylval
做了一些事情,或者您向调用者 return 指示是否遇到了头和尾。