首页 > 解决方案 > 奇怪的词法问题关键字与标识符正则表达式匹配

问题描述

我一直在努力理解 flex 的一些行为。

我开始定义一个类似玩具的小示例程序,它将标记为关键字和字符串。

正则表达式的一个定义按预期执行,但另一个定义完全不同,这与我的预期相反。

我玩这些东西已经有几年了,所以希望有人能指出我正确的方向。

我修改了令牌正则表达式以使其工作,但我真的很想了解为什么我最初的选择表现不同。

第一个示例是非工作代码

%{
#include <iostream>
using namespace std;
%}
%option noyywrap
%%
[ \t\n]                   {cout << "ws" << endl;};
buzz                      {cout << "kw" << endl;};
[^\n]+                    {cout << "str" << endl;};
%%
int main(){
yylex();
}

第二个例子是修改后的版本,它确实表现得很好。

%{
#include <iostream>
using namespace std;
%}
%option noyywrap
%%
[ \t\n]                   {cout << "ws" << endl;};
buzz                      {cout << "kw" << endl;};
[a-zA-Z]+                 {cout << "str" << endl;};
%%
int main(){
yylex();
}

在代码中,buzz 应该是一个关键字,后面的任何内容都应该被读取为一个字符串。

对于第一个示例,buzz 与剩余的单词一起被消耗为“str”。

在第二个例子中,buzz 被正确识别,剩下的单词变成了“str”。

我知道这两种情况下的第三条规则也是包含字符 Buzz 的令牌的有效定义。这四个字母中的每一个都在 [^\n]+ 以及 [a-zA-Z]+ 中。那么到底为什么行为不同呢?

示例输入为:

buzz lightyear
buzz aldren

谢谢!

标签: flex-lexer

解决方案


Flex(以及大多数其他词法分析器生成器)根据最大咀嚼规则工作。该规则表示,如果多个模式可以在当前输入上匹配,则选择产生最长匹配的模式。如果多个模式产生相同大小的匹配,则选择 .l 文件中第一个出现的模式。

因此,在您的工作解决方案中,模式buzz[a-zA-Z0-9]+两者都匹配buzz,因此buzz被选中,因为它首先出现在文件中(如果您切换了两行,str则会打印出来)。在您的非工作解决方案中buzz仍然会匹配buzz,但分别[^\n]+匹配buzz lightyearbuzz aldren,这是更长的匹配。因此它根据最大咀嚼规则获胜。


推荐阅读