flex - negative lookahead中无法识别的规则

问题描述 投票:1回答:1

当我在这段代码上运行flex时,它会抱怨unrecognized rule。我想匹配像(b|B)^n(a|A)^m这样的字符串,使n >= 4 and m <= 3。我在regex101上测试了正则表达式,它运行正常。这是代码:

%{
    #include <stdio.h>
    ...
%}
* some rules *
STRING  ([bB]{4,}[aA]{1,3}(?!(a|A)+))+     // rule causing error
%%
...
{STRING} {      
            printf("%s ", yytext);
         }

编辑:应匹配整个字符串,并允许分隔符为whitespace和\或comma。不应匹配子字符串。

regex flex-lexer lex
1个回答
3
投票

(F)lex没有实施negative lookahead assertions。 (注意:前面的链接不是认可。)

您可以在flex manual中找到flex接受的正则表达式运算符的完整列表;如果语法不在该列表中,则无论在线正则表达式服务告诉您什么,都不会识别它。 (注意:前面的链接是认可。)

(F)lex确实实现了一个积极的先行断言,但只是在模式的最后。用trailing context operator /表示。您可以使用该运算符来识别您的令牌,要求它后面跟A以外的其他东西:

[bB]{4,}[aA]{1,3}/[^Aa]  { printf("%s ", yytext); }

但这并不是完全相同的语义,因为它不会在输入的最后识别令牌。它要求令牌后面跟不是A的东西;开始后面没有什么不算数。 (实际上,这可能没什么区别。如果你是从文本流中扫描输入,你可以合理地期望流有一个换行符作为最后一个字符,换行符将匹配[^Aa]。但是,如果你打算扫描可能根本没有换行的文本字符串,然后你需要知道这个问题。)

大多数时候,这不是你想要的。或者,如果它真的是你想要的,那么(f)lex可能不适合你的用例。

(F)lex旨在将输入分成连续的令牌。它不搜索令牌;它标识当前输入点的令牌。它期望整个输入将由标记组成,因此某些模式需要在每个点匹配。

在此基础上,您需要考虑不匹配序列是什么类型的令牌。举个例子:

bbbbbbbaaaa

这太多了,不能成为你的规则的“字符串”。那是什么?

  1. 有效令牌bbbbbbbaaa后跟另一个以?开头的令牌?
  2. 与其他模式匹配的有效令牌? (例如.LONG_STRING)?
  3. 应该忽略的无效令牌,允许扫描继续?
  4. 一个不可恢复的错误?

所有这些情况都可以在不使用任何环视操作符的情况下处理。

在第一种情况下,使用与有效令牌匹配的正则表达式就足够了:

[bB]{4,}[aA]{1,3}     { printf("Valid STRING: %s ", yytext); }

在第二种情况下,您可以依赖(f)lex最大munch匹配规则,该规则指出将使用与最长匹配相对应的模式:

[bB]{4,}[aA]{1,3}     { printf("Valid STRING: %s ", yytext); }
[bB]{4,}[aA]{4,}      { printf("Valid LONG STRING: %s ", yytext); }

这可以简化:

[bB]{4,}[aA]{1,3}     { printf("Valid STRING: %s ", yytext); }
[bB]{4,}[aA]          { printf("Valid LONG STRING: %s ", yytext); }

这将具有相同的效果,因为(f)lex规则决定两个具有最长匹配的模式之间是使用输入文件中的第一个模式。因此bbbbaa---的前六个字符匹配两种模式,因此第一个获胜,而bbbbaaaa---与第一个模式匹配七个字符,与第二个模式匹配一​​个八个字符,所以第二个获胜。

对于第三和第四种情况,也可以使用上述图案对;唯一的区别在于对应于第二种模式的动作。对于案例3:忽略令牌,可能发出警告;对于案例4:产生错误消息并终止扫描。

© www.soinside.com 2019 - 2024. All rights reserved.