非贪婪的多线和单线匹配

时间:2014-03-17 00:18:46

标签: flex-lexer

我正在尝试修改flex + bison生成器,以允许包含由周围的{{'}表示的代码段。和'}}'。与多行注释案例不同,我必须捕获所有内容。

我的尝试要么在{' {{'和'}}'是在同一条线上,或者它们很慢。

我的第一次尝试是这样的:

%{
#include <stdio.h>
// sscce implementation of a growing string buffer
char codeBlock[4096];
int codeOffset;
const char* curFilename = "file.l";
extern int yylineno;

void add_code_line(const char* yytext)
{
    codeOffset += sprintf(codeBlock + codeOffset, "#line %u \"%s\"\n\t%s\n", yylineno, curFilename, yytext);
}

%}

%option stack
%option yylineno

%x CODE_FRAG

%%

"{{"[ \n]*          { codeOffset = 0; yy_push_state(CODE_FRAG); }
<CODE_FRAG>"}}"     { codeBlock[codeOffset] = 0; printf("// code\n%s\n", codeBlock); yy_pop_state(); }
<CODE_FRAG>[^\n]*   { add_code_line(yytext); }
<CODE_FRAG>\n

\n
.

注意:&#34; codeBlock&#34;实施只是为了SSCCE的目的。这不是我实际使用的。

这适用于一个简单的测试用例:

{{ from line 1
from line 2
}}

{{

from line 7
}}

输出

// code
#line 1 "file.l"
    from line 1
#line 2 "file.l"
    from line 2

// code
#line 7 "file.l"
    from line 7

但它无法处理

{{ hello }}

我能想到的两个解决方案是:

    /* capture character-by-character */
    <CODE_FRAG>.  { add_code_character(yytext[0]); }

    <INITIAL>"{{".*?"}}" { int n = strlen(yytext); yytext + (n - 2) = 0; add_code(yytext + 2); }

前者似乎很慢,而后者只是感觉不对。

有什么想法吗?

---编辑---

以下似乎可以达到预期的效果,但我不确定它是否是一个好的&#34;灵活的方式来做到这一点:

"{{"[ \n]*          { codeOffset = 0; yy_push_state(CODE_FRAG); }
<CODE_FRAG>"}}"     { codeBlock[codeOffset] = 0; printf("// code\n%s\n", codeBlock); yy_pop_state(); }
<CODE_FRAG>.*?/"}}" { add_code_line(yytext); }
<CODE_FRAG>.*?      { add_code_line(yytext); }
<CODE_FRAG>\n

1 个答案:

答案 0 :(得分:2)

  1. Flex不会实现非贪婪的匹配。所以.*?将无法按照您期望的方式在flex中工作。 (它将是一个可选的.*,与.*无法区分

  2. 这是一个正则表达式,在没有{{的情况下尽可能与}}匹配:

    "{{"([}]?[^}])*

  3. 这可能不是您想要的,因为它不允许在您的代码块中嵌套{{...}}。但是,您没有提到这是一个要求,并且您的示例都没有这样的功能。

  4. 上面的正则表达式匹配结束}},它似乎是您想要的,因为它允许您在不修改临时缓冲区的情况下调用add_code(yytext+2) 。但是,您需要在操作中处理}}。见下文。

  5. 如果没有匹配的}},上面的正则表达式将匹配文件的末尾。你可能想把它当作一个错误处理;最简单的方法是在您尝试忽略}}

    时检查是否遇到EOF
    "{{"([}]?[^}])*   { add_code(yytext+2);
                        if (input() == EOF || input() == EOF) {
                          /* Produce an error, unclosed {{ */
                        }
                      }