我试图使一个正则表达式,将只工作时,一个有效的标识符名称是给定的,使用flex(名称不能以数字开头)。我使用以下代码:
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
%}
%%
"if" { printf("IF "); }
[a-zA-Z_][a-zA-Z_0-9]* { printf("%s ", yytext); }
%%
int main() {
yylex();
}
,但它不工作。如何确保flex只接受有效的标识符?
当我提供输入时:
if
abc
9abc
我看到如下输出:
IF
abc
9abc
但我期望:
IF
abc
(nothing)
您的模式与所有可能的输入不匹配。
在这种情况下,(f)lex添加一个默认的捕获规则,格式为
.|n { ECHO; }
换句话说,任何不能被您的模式识别的字符将被简单地打印在stdout
上。输入中的换行字符以及数字9就是这种情况。在9被默认规则识别之后,您的标识符规则将再次识别剩余的输入。
所以你可能想要这样的东西:
%option warn nodefault
%%
[[:space:]]+ ; /* Ignore whitespace */
"if" { /* TODO: Handle an "if" token */ }
[[:alpha:]_][[:alnum:]_]* { /* TODO: Handle an identifier token */ }
. { /* TODO: Handle an error */ }
与其将信息打印到stdout
作为调试或学习辅助,我强烈建议您在构建扫描仪时使用-T
(或--trace
)选项。自动输出一致完整的调试信息;例如,它会告诉您正在匹配默认规则。
指出:
%option nodefault
告诉flex不要插入默认规则。我建议经常使用它,因为它会让你远离麻烦。warn
选项确保在这种情况下发出警告;我认为warn
是默认的flex行为,但手册建议使用它,它不会伤害。使用标准字符类表达式是很好的风格。在字符类(
[
…]
)中,[:xxx:]
匹配标准库函数isxxx
返回true的任何内容。因此,[[:space:]]+
匹配一个或多个空白字符,包括空格、制表符和换行符(以及其他一些字符),[[:alpha:]_]
匹配任何字母或下划线,[[:alnum:]_]*
匹配字母、数字或下划线的任何数字(包括0)。请参阅手册中的模式部分。