2

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

%{
#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();
}

我的“.y”文件在这里:

    /* 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.. 关于“可重入”和“纯”的例子很多,但我找不到最好的指导方针。

有人可以指导我吗?

提前致谢。

4

2 回答 2

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,请告诉我。

于 2014-10-22T12:37:36.873 回答
2

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

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

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

于 2014-11-02T16:19:27.810 回答