2014-10-21 1 views
2

나는 논리적 표현을 평가하기위한 파서를 작성했다. flex와 bison은 전역 변수 (예 : yylval)를 사용합니다. 순수한 파서와 쓰레드 프로그래밍을위한 재진입 스캐너가 필요하다. 내 '.Y'파일은 여기에 있습니다 :"win_flex bison"을 사용하여 순수 파서 및 재진입 스캐너를 작성하는 방법은 무엇입니까?

%{ 
#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'파일은 여기에 있습니다 : 나는 두 파일에 %pure_parser을 추가 int yylex (YYSTYPE* lvalp);로는 yylex 선언을 변경하고 yylval를 교체 한

/* 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; 


} 

*lvalp,하지만 오류가 발생했습니다 : 'lvalp' is undeclared identifier.. '재진입 성'과 '순수함'에 대한 사례가 많이 있지만 최고의 가이드 라인을 찾을 수 없습니다.

나를 안내해 줄 수 있습니까?

미리 감사드립니다.

답변

6

다행히도, 나는 그것을했다. 여기 내 코드가있다. . 나는 그것이 순수한 파서를 작성하고자하는 사람들을위한 좋은 지침이 될 수 있다고 생각 ل

내 재진입 스캐너 :

/* 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(); 
} 

공지 사항 속임수와

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

으로 yyg에게 자신을 정의 나는를 얻을 수있는 다른 방법을 찾을 수없는. 따라서 누군가가 YY_CURRENT_BUFFER을 얻는 가장 좋은 방법을 알고 있다면 알려주세요.

+0

(사용되지 않은) 초기 버퍼를 삭제하려면 'yypop_buffer_state' 할 수 없습니까? ('yy_scan_string'은 삭제하지 않는다고 가정하면됩니다.) – rici

2

다음은 완전한 Flex/Bison C++ 예제입니다. 모든 것은 재진입이고 전역 변수를 사용하지 않습니다. 파서/렉서는 모두 별도의 네임 스페이스에있는 클래스에 캡슐화됩니다. 원하는만큼 많은 스레드에서 "통역사"를 인스턴스화 할 수 있습니다.

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

면책 조항 :이 Windows에서 테스트하지,하지만 코드가 사소한 조작과 휴대해야한다.

관련 문제