如何匹配该行开头?

时间:2015-12-09 11:44:12

标签: compiler-construction lex

我正在用lex编写cat(1)实用程序。 当我考虑如何实现选项-n时,即每行编号。 但我必须写这样的东西:

^. {
printf("%8d  ", ++lino);
ECHO;
}

我知道行尾(EOL)可以匹配使用锚$\n,所以我想知道是否有相似的东西来匹配行首(BOL)锚点,所以我不必使用ECHO;

1 个答案:

答案 0 :(得分:2)

(我同意Joachim Pileborg的评论lex

}实施cat的工具。其余的答案是本着解释一下lex。)

  1. 如果输入中有空行,则提供的lex程序将无效,因为^.与空行不匹配。 (在lex中,.与换行符不匹配。)因此,一个合理的最小(f)lex输入文件将是:

    %options noyywrap noinput nounput
    %%
      int lino = 0;
    ^(.|\n)    { printf("%8d   %c", ++lino, *yytext); }
    

    在这里,我只打印printf中匹配的令牌,这相当于使用ECHO。所以它并没有真正“消除”ECHO

  2. (f)lex规则必须至少匹配一个字符。因此,模式实际上不可能只由$组成,而模式只能由^(这是一个BOL锚点)组成。从这个意义上讲,你的问题的答案就是“不”。

  3. 更容易理解(可能更有效)的解决方案是实际匹配每一行。此解决方案从不使用ECHO,即使在默认规则中也没有,所以我告诉flex不要生成默认规则:

    %options noyywrap noinput nounput nodefault
    %%
      int lino = 0;
    .*\n?    { printf("%8d   %s", ++lino, yytext); }
    

    这不太完美,因为它会截断包含NUL字符的行。 (也就是说,printf将有效地截断该行;该行将被正确解析。)要修复它,必须使用fwrite而不是printf

    %options noyywrap noinput nounput nodefault
    %%
      int lino = 0;
    .*\n?    { printf("%8d   %s", ++lino);
               fwrite(yytext, 1, yyleng, yyout); }
    

    如果文件的最后一行没有以换行符终止,则换行符是可选的(\n?)。因为(f)lex模式永远不会匹配零个字符,所以该规则实际上等同于更精确但更笨重的正则表达式.*\n|.+