简单的正则表达式模式与Flex / Bison(Lex / Yacc)无法比拟

时间:2016-12-30 09:44:33

标签: grammar bison flex-lexer yacc lex

我使用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

我的正则表达式似乎正确,因为https://regex101.com/r/ZHHQpn/1匹配正常。怎么了?

1 个答案:

答案 0 :(得分:2)

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

flex manual

中对此进行了解释
  

“R $”
  一个'r',但只在一行的末尾(即在换行符之前)。相当于'r / \ n'。

     

请注意,flex的“换行符”概念正是C编译器用于编译flex解释'\ n'的任何内容;特别是,在某些DOS系统上,你必须自己过滤掉输入中的'\ r',或者明确地使用'r / \ r \ n'代替'r $'。

快速解决方案是改变:

^\\end\{document\}$

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

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

<<EOF>>

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