如何通过“win_flex bison”编写纯解析器和可重入扫描器?

时间:2014-10-21 09:49:23

标签: c bison flex-lexer lalr

我编写了一个用于评估逻辑表达式的解析器。我知道flex和bison使用全局变量(比如yylval)。我想要一个纯粹的解析器和一个可重入的扫描程序来进行线程编程。我的'。''文件在这里:

%{
#include <stdio.h>
#include <string>
#define YYSTYPE bool

void yyerror(char *);

//int  yylex (YYSTYPE* lvalp);

int yylex(void);
bool parseExpression(const std::string& inp);
%}

%token INTEGER
%left '&' '|'

%%

program:
        program statement '\n'
        | /* NULL */
        ;

statement:
        expression                      { printf("%d\n", $1); return $1; }
        ;

expression:
        INTEGER
        | expression '|' expression     { $$ = $1 | $3; }
        | expression '&' expression     { $$ = $1 & $3; }
        | '(' expression ')'            { $$ = $2; }
        | '!' expression                { $$ = !$2; }
        ;

%%

void yyerror(char *s) {
    fprintf(stderr, "%s\n", s);
}


void main(void) {

    std::string inp = "0|0\n";

    bool nasi = parseExpression(inp);
    printf("%s%d\n", "nasi ", nasi);
    printf("Press ENTER to close. ");
    getchar();
}

我的'。''文件在这里:

    /* Lexer */
%{
    #include "parser.tab.h"
    #include <stdlib.h>
    #include <string>
    #define YYSTYPE bool
    void yyerror(char *);
%}


%%

[0-1]      {
                if (strcmp(yytext, "0")==0)
                {
                    yylval = false;
                    //*lvalp = false;
                }
                else
                {
                    yylval = true; 
                    //*lvalp = true;
                }

                return INTEGER;
            }

[&|!()\n]     { return *yytext; }

[ \t]   ;       /* skip whitespace */

.               yyerror("Unknown character");

%%

int yywrap(void) {
    return 1;
}

bool parseExpression(const std::string& inp)
{
    yy_delete_buffer(YY_CURRENT_BUFFER);

    /*Copy string into new buffer and Switch buffers*/
    yy_scan_string(inp.c_str());
    bool nasi = yyparse();

    return nasi;


}

我已将%pure_parser添加到两个文件中,将yylex声明更改为int yylex (YYSTYPE* lvalp);并将yylval替换为*lvalp,但我看到了错误:'lvalp' is undeclared identifier. 。有很多关于'reentrant'和'pure'的例子,但我找不到最好的准则。

有人可以指导我吗?

提前致谢。

2 个答案:

答案 0 :(得分:5)

幸运的是,我做到了。这是我的代码。我认为这对于谁想要编写纯解析器来说是一个很好的指导。ل

我的可重入扫描仪:

    /* Lexer */
%{
    #include "parser.tab.h"
    #include <stdlib.h>
    #include <string>
    #define YYSTYPE bool
    void yyerror (yyscan_t yyscanner, char const *msg);
%}

%option reentrant bison-bridge

%%

[0-1]      {
                if (strcmp(yytext, "0")==0)
                {
                    *yylval = false;
                }
                else
                {
                    *yylval = true;
                }

                //yylval = atoi(yytext);
                return INTEGER;
            }

[&|!()\n]     { return *yytext; }

[ \t]   ;       /* skip whitespace */

.               yyerror (yyscanner, "Unknown character");

%%

int yywrap(yyscan_t yyscanner)
{
    return 1;
}

bool parseExpression(const std::string& inp)
{
    yyscan_t myscanner;
    yylex_init(&myscanner);
    struct yyguts_t * yyg = (struct yyguts_t*)myscanner;

    yy_delete_buffer(YY_CURRENT_BUFFER,myscanner);

    /*Copy string into new buffer and Switch buffers*/
    yy_scan_string(inp.c_str(), myscanner);

    bool nasi = yyparse(myscanner);
    yylex_destroy(myscanner);
    return nasi;
}

我的纯解析器:

%{
    #include <stdio.h>
    #include <string>

    #define YYSTYPE bool
    typedef void* yyscan_t;
    void yyerror (yyscan_t yyscanner, char const *msg);
    int yylex(YYSTYPE *yylval_param, yyscan_t yyscanner);
    bool parseExpression(const std::string& inp);
%}


%define api.pure full
%lex-param {yyscan_t scanner}
%parse-param {yyscan_t scanner}

%token INTEGER
%left '&' '|'

%%

program:
        program statement '\n'
        | /* NULL */
        ;

statement:
        expression                      { printf("%d\n", $1); return $1; }
        ;

expression:
        INTEGER
        | expression '|' expression     { $$ = $1 | $3; }
        | expression '&' expression     { $$ = $1 & $3; }
        | '(' expression ')'            { $$ = $2; }
        | '!' expression                { $$ = !$2; }
        ;

%%

void yyerror (yyscan_t yyscanner, char const *msg){
    fprintf(stderr, "%s\n", msg);
}


void main(void) {

    std::string inp = "1|0\n";

    bool nasi = parseExpression(inp);
    printf("%s%d\n", "nasi ", nasi);
    printf("Press ENTER to close. ");
    getchar();
}

请注意,我作弊并将yyg自己定义为

struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;

我找不到另一种获取YY_CURRENT_BUFFER的方法。所以,如果有人知道获得YY_CURRENT_BUFFER的最佳方式,请告诉我,PLZ。

答案 1 :(得分:2)

这是一个完整的Flex / Bison C ++示例。一切都是可重入的,不使用全局变量。解析器/词法分析器都封装在一个放在单独命名空间中的类中。您可以根据需要在尽可能多的线程中实例化尽可能多的“解释器”。

https://github.com/ezaquarii/bison-flex-cpp-example

免责声明:它未在Windows上进行测试,但代码应该是可移植的,只需稍加调整即可。