如何在 flex lexer 中将局部变量添加到 yylex 函数?

How to add local variables to yylex function in flex lexer?

我正在编写一个词法分析器文件,该文件匹配 xyz$this is stringxyz 形式的简单自定义分隔字符串。我几乎就是这样做的:

%{
char delim[16];
uint8_t dlen;
%}

%%

.*$ {
    dlen = yyleng-1;
    strncpy(delim, yytext, dlen);
    BEGIN(STRING);
}

<STRING>. {
    if(yyleng >= dlen) {
        if(strncmp(delim, yytext[yyleng-dlen], dlen) == 0) {
            BEGIN(INITIAL);
            return STR;
        }
    }
    yymore();
}

%%

现在我想将其转换为可重入词法分析器。但是除了修改生成的词法分析器之外,我不知道如何将 delim 和 dlen 作为 yylex 中的局部变量。有人请帮助我我应该怎么做。

我不建议将它们存储在 yyextra 中,因为这些变量不需要在对 yylex 的多次调用中持续存在。因此,我更喜欢一个指导我将这些声明为局部变量的答案。

在 (f)lex 文件中,%% 和第一条规则之间的任何缩进行都被逐字复制到第一条语句之前的 yylex() 中,正是为了允许您声明和初始化局部变量。

此行为由 Posix 规范保证;它不是 flex 扩展:(强调)

Any such input (beginning with a <blank>or within "%{" and "%}" delimiter lines) appearing at the beginning of the Rules section before any rules are specified shall be written to lex.yy.c after the declarations of variables for the yylex() function and before the first line of code in yylex(). Thus, user variables local to yylex() can be declared here, as well as application code to execute upon entry to yylex().

Flex 手册中有类似的说法section 5.2, Format of the Rules Section


您提出的策略肯定会奏效,但效率不高。您可能想考虑使用 input() 一次读取一个字符,尽管这也不是非常有效。无论如何,delim 是不必要的:

%%
    int dlen;

[^$\n]{1,16}$ {
    dlen = yyleng-1;
    yymore();
    BEGIN(STRING);
}

<STRING>. {
    if(yyleng > dlen * 2) {
        if(memcmp(yytext, yytext + yyleng - dlen, dlen) == 0) {
            /* Remove the delimiter from the reported value of yytext. */
            yytext += dlen + 1;
            yyleng -= 2 * dlen + 1;
            yytext[yyleng] = 0;
            return STR;
        }
    }
    yymore();
}

%%