来自《龙书第二版》第3.5.3节“Lex中的冲突解决”:
We have alluded to the two rules that Lex uses to decide on the proper lexeme
to select, when several prefixes of the input match one or more patterns:
1. Always prefer a longer prefix to a shorter prefix.
2. If the longest possible prefix matches two or more patterns, prefer the
pattern listed first in the Lex program.
这个规则同样适用于Flex。以下是 Flex手册(第7章:匹配输入)中的说明。
When the generated scanner is run, it analyzes its input looking for strings
which match any of its patterns. If it finds more than one match, it takes the
one matching the most text (for trailing context rules, this includes the length
of the trailing part, even though it will then be returned to the input). If it
finds two or more matches of the same length, the rule listed first in the flex
input file is chosen.
如果我理解正确,您的词法分析器将像 Endif
这样的关键字视为标识符,因此在之后会被认为是表达式的一部分。如果这是您的问题,只需将关键字规则放在规范的顶部即可,例如以下内容:(假设大写单词是对应令牌的预定义枚举)
"If" { return IF; }
"Then" { return THEN; }
"Endif" { return ENDIF; }
"While" { return WHILE; }
"Do" { return DO; }
"EndWhile" { return ENDWHILE; }
\"(\\.|[^\\"])*\" { return STRING; }
[a-zA-Z_][a-zA-Z0-9_]* { return IDENTIFIER; }
由于规则2的限制,关键字会始终优先于标识符匹配。
编辑:
感谢您的评论,kol。我忘记添加字符串规则了。但我认为我的解决方案并没有错。 例如,如果有一个名为If_this_is_an_identifier
的标识符,规则1将应用,因此标识符规则将发挥作用(因为它是最长的字符串)。 我编写了一个简单的测试用例,并没有发现问题。这是我的lex.l文件:
%{
using namespace std;
%}
ID [a-zA-Z_][a-zA-Z0-9_]*
%option noyywrap
%%
"If" { cout << "IF: " << yytext << endl; }
"Then" { cout << "THEN: " << yytext << endl; }
"Endif" { cout << "ENDIF: " << yytext << endl; }
"While" { cout << "WHILE: " << yytext << endl; }
"Do" { cout << "DO: " << yytext << endl; }
"EndWhile" { cout << "ENDWHILE: " << yytext << endl; }
\"(\\.|[^\\"])*\" { cout << "STRING: " << yytext << endl; }
{ID} { cout << "IDENTIFIER: " << yytext << endl; }
. { cout << "Ignore token: " << yytext << endl; }
%%
int main(int argc, char* argv[]) {
++argv, --argc; /* skip over program name */
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
yylex();
}
我使用以下测试用例测试了我的解决方案:
If If_this_is_an_identifier > 0 Then read(b); Endif
c := "If I were...";
While While_this_is_also_an_identifier > 5 Do d := d + 1 Endwhile
它给了我以下输出(忽略与你提到的问题无关的其他输出。)
IF: If
IDENTIFIER: If_this_is_an_identifier
......
STRING: "If I were..."
......
WHILE: While
IDENTIFIER: While_this_is_also_an_identifier
lex.l程序是基于flex手册示例进行修改的(该示例使用相同的方法从标识符中匹配关键字)。
此外,还可以参考ANSI C语法,Lex规范。
我也在我的个人项目中使用了这种方法,目前没有发现任何问题。