Flex/Bison (Lex/Yacc) 无法匹配的简单正则表达式模式

Simple Regex pattern unmatched with Flex/Bison (Lex/Yacc)

我使用 Flex 和 Bison 构建了一个简单的编译器,它可以识别源文件中的简单字符串,如果字符串被正确识别,我会使用标准错误流输出消息。

下面是我的代码和我意想不到的结果。

这是源文件 (testsource.txt),其中包含我尝试识别的字符串:

\end{document}

这是 Flex 文件 (UnicTextLang.l):

%{
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "y.tab.h"
    void yyerror(char *);
    int yylex(void);
    /* "Connect" with the output file  */
    extern FILE *yyout;
    extern int  yyparse();
%}

%%

^\end\{document\}$ { yyerror("end matched"); return END; }

    /* skip whitespace */
[ \t] ;

    /* anything else is an error */
. yyerror("invalid character");

%%

int main(int argc, char *argv[]) {
    if ( argc < 3 )
        yyerror("You need 2 args: inputFileName outputFileName");
    else {
        yyin = fopen(argv[1], "r");
        yyout = fopen(argv[2], "w");
        yyparse();
        fclose(yyin);
        fclose(yyout);
    }

    return 0;
}

这是 Bison 文件 (UnicTextLang.y):

%{
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "y.tab.h"
    void yyerror(char *);
    int yylex(void);

    /* "Connect" with the output file  */
    extern FILE *yyout;
%}

%token END

%%

document:
        END
        |
        ;

%%

int yywrap(void) {
    return 1;
}

void yyerror(char *s) {
    fprintf(stderr, "%s\n", s); /* Prints to the standard error stream */
}

我运行以下命令:

flex UnicTextLang.l
bison -dl -o y.tab.c UnicTextLang.y
gcc lex.yy.c y.tab.c -o UnicTextLang
UnicTextLang.exe testsource.txt output.txt

我希望在控制台中看到的打印内容是

end matched

但这就是我得到的:

invalid character
invalid character
invalid character
invalid character
invalid character
invalid character
invalid character
invalid character
invalid character
invalid character
invalid character
invalid character
invalid character
invalid character
invalid character

怎么了?

此问题是由于 Windows 机器的行尾代码是两个字符 (\r\n) 而在其他系统上是一个 (\n)。

这在flex manual中有解释:

‘r$’
an ‘r’, but only at the end of a line (i.e., just before a newline). Equivalent to ‘r/\n’.

Note that flex’s notion of “newline” is exactly whatever the C compiler used to compile flex interprets ‘\n’ as; in particular, on some DOS systems you must either filter out ‘\r’s in the input yourself, or explicitly use ‘r/\r\n’ for ‘r$’.

快速解决方案是更改:

^\end\{document\}$

^\end\{document\}\r\n

但是,如果您的表达式位于文件末尾而没有行尾,这在 Windows 中是可能的,那么您也必须专门匹配这种情况。 Flex 确实允许文件结尾匹配:

<<EOF>>

但这会导致各种其他副作用,并且通常更容易不将模式锚定到(行或文件的)末尾。