2015-09-12 122 views
5

我正在學習如何一起使用可重入Bison和Flex。我已經有了一個簡單的計算器,沒有重入功能。但是,當我激活重入特性並進行必要的修改時,我無法使其工作。可重入Flex和Bison的問題

下面是代碼:

scanner.l

%{ 
#include <stdio.h> 
#include "parser.tab.h" 
%} 

%option 8bit reentrant bison-bridge 
%option warn noyywrap nodefault 
%option header-file="lex.yy.h" 

DIGIT [0-9] 

%% 

"+" { return ADD; } 
"-" { return SUB; } 
"*" { return MUL; } 
"/" { return DIV; } 
{DIGIT}+ { *yylval = atof(yytext); return NUM; } 
\n  { return EOL; } 
[ \t] { } 
.  { printf("What is this: %s.\n", yytext); } 
%% 

parser.y

%{ 
#include <stdio.h> 
#include "lex.yy.h" 

void yyerror(yyscan_t scanner, char const *msg); 
%} 

%define api.value.type {double} 
%define parse.error verbose 
%define api.pure 
%lex-param {yyscan_t scanner} 
%parse-param {yyscan_t scanner} 

%token NUM EOL     
%left ADD SUB 
%left MUL DIV 

%% 

input: %empty 
| input line 
; 

line: EOL { printf("|> ");} 
| exp EOL { printf("|R> %.4lf\n", $exp); } 
; 

exp: NUM { $$ = $1; } 
| exp ADD exp { $$ = $1 + $3; } 
| exp SUB exp { $$ = $1 - $3; } 
| exp MUL exp { $$ = $1 * $3; } 
| exp DIV exp { $$ = $1/$3; } 
; 

%% 

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

的main.c

#include <stdio.h> 
#include "parser.tab.h" 
#include "lex.yy.h" 

int main(void) { 

    yyscan_t scanner; 

    yylex_init(&scanner); 
    yyset_in(stdin, scanner); 

    yyparse(scanner); 

    yylex_destroy(scanner); 

    return 0; 
} 

,這是我使用Makefile

all: calc.x 

parser.tab.c parser.tab.h: parser.y 
    bison -d parser.y 

lex.yy.c lex.yy.h: scanner.l parser.tab.h 
    flex scanner.l 

calc.x: lex.yy.c lex.yy.h parser.tab.c parser.tab.h 
    gcc main.c parser.tab.c lex.yy.c -o calc.x 

clean: 
    rm calc.x lex.yy.c lex.yy.h parser.tab.c parser.tab.h *.o 

運行make,我得到了以下錯誤:

In file included from main.c:2:0: 
parser.tab.h:66:14: error: unknown type name ‘yyscan_t’ 
int yyparse (yyscan_t scanner); 
      ^
main.c: In function ‘main’: 
main.c:12:3: warning: implicit declaration of function ‘yyparse’ [-Wimplicit-function-declaration] 
    yyparse(scanner); 
^
In file included from parser.y:5:0: 
lex.yy.h:282:1: error: unknown type name ‘YYSTYPE’ 
YYSTYPE * yyget_lval (yyscan_t yyscanner); 
^ 
lex.yy.h:284:18: error: unknown type name ‘YYSTYPE’ 
void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner); 
       ^
lex.yy.h:332:17: error: unknown type name ‘YYSTYPE’ 
       (YYSTYPE * yylval_param ,yyscan_t yyscanner); 
       ^
parser.tab.c: In function ‘yyparse’: 
parser.tab.c:1130:16: warning: implicit declaration of function ‘yylex’ [-Wimplicit-function-declaration] 
     yychar = yylex (&yylval, scanner); 
       ^
Makefile:10: recipe for target 'calc.x' failed 
make: *** [calc.x] Error 1 

但我不明白,這個錯誤和警告的起源消息,例如:

main.c:12:3: warning: implicit declaration of function ‘yyparse’ 

但是yyparse是已定義在parser.tab.h,它包含在main.c中。又如:

parser.tab.h:66:14: error: unknown type name ‘yyscan_t’ 

而且裏面parser.y,我包括掃描頭lex.yy.h

我發現在互聯網上這些解決方案:

但他們都沒有工作,導致類似的錯誤。如果有人能夠在這個任務中指導我,我會很感激。

軟件版本

OS:Debian的(測試),野牛:3.0.4,軟硬度:39年2月5日,GCC 5.2.1,製作:4.0。

回答

3

我找到了一個解決方案後修改了一下。所以問題來自flex和野牛之間的循環依賴。

解析器產生的呼叫柔性程序以這樣的方式

yychar = yylex (&yylval, scanner); 

所以在野牛輸入我們必須包括掃描頭文件lex.yy.h ,它的定義爲:

int yylex (YYSTYPE * yylval_param ,yyscan_t yyscanner); 

YYSTYPE是在解析器頭文件parser.tab.h內定義,在我的情況下,我對野牛說我的類型將是double

typedef double YYSTYPE; 

現在的解決方案。在scanner.l的內部,您必須包含解析器頭文件,以便flex可以返回正確的記號(沒有任何更改)。

但裏面的parser.y您必須包括頭文件,如果你只包括lex.yy.h它會抱怨:

lex.yy.h:282:1: error: unknown type name ‘YYSTYPE‘ 

因爲YYSTYPE是內部parser.tab.h定義。最後,出於某種原因,野牛分析器不知道什麼yyscan_t甚至包括詞法頭:

error: unknown type name ‘yyscan_t’ 

一個解決辦法是將其定義爲void:

%lex-param {void *scanner} 
%parse-param {void *scanner} 

看到yyscan_t定義:flex yyscan_t

因此,這裏是最後的結果:

scanner.l

%{ 
#include <stdio.h> 
#include "parser.tab.h" 
%} 

%option 8bit reentrant bison-bridge 
%option warn noyywrap nodefault 
%option header-file="lex.yy.h" 

//rest of the scanner 

parser.y

%{ 
#include <stdio.h> 
#include "parser.tab.h" 
#include "lex.yy.h" 

void yyerror(yyscan_t scanner, char const *msg); 
%} 

%define api.value.type {double} 
%define parse.error verbose 
%define api.pure 
%lex-param {void *scanner} 
%parse-param {void *scanner} 

//rest of the input 

的main.c

#include <stdio.h> 

#include "parser.tab.h" 
#include "lex.yy.h" 

int main(void) { 

    yyscan_t scanner; 

    yylex_init(&scanner); 
    yyset_in(stdin, scanner); 

    yyparse(scanner); 

    yylex_destroy(scanner); 

    return 0; 
} 
0
由法布里西奧桑切斯

接受的答案幫我解決兩個問題:

  1. error: unknown type name ‘yyscan_t’確實已通過更改爲void *解決。

  2. 與循環依賴衝突決定非常嚴格的進口的順序:

你的代碼中的Flex /野牛的yyparse被稱爲:

#import "parser.h" 
#import "lexer.h" 

的Flex(詞法分析器。LM):

%{ 
#import "parser.h" 
%} 

野牛(Parser.ym):

%{ 
#import "parser.h" 
#import "lexer.h" 
%} 

我寫博客文章的創建使用Flex和Bison在Mac OS與例如折返解析器的過程它整合到Xcode項目:Reentrant parser using Flex and Bison

+0

問題:我已經從鏈接的博客開始工作。你能解釋爲什麼我不能包含像「#include 」這樣的文件嗎? –

+0

你使用Xcode嗎? –

+0

是的,我現在正在看你的例子。 –