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

时间:2017-12-30 11:11:12

标签: regex flex-lexer lex

当我对此代码运行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。不应匹配子字符串。

1 个答案:

答案 0 :(得分: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

有太多 a s是&#34;字符串&#34;与你的规则。那是什么?

  1. 有效令牌bbbbbbbaaa后跟另一个以 a 开头的令牌?

  2. 与其他模式匹配的有效令牌? (例如LONG_STRING)?

  3. 应忽略的无效令牌,允许扫描继续?

  4. 无法恢复的错误?

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

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

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

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

    [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:产生错误消息并终止扫描。