重入Flex和Bison的问题

我正在学习如何一起使用可重入的Bison和Flex。 我已经有一个简单的计算器工作,没有可重入的function。 但是,当我激活可重入function并进行必要的修改时,我无法使其工作。

这是代码:

scanner.l

%{ #include  #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  #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  #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

我在互联网上找到了这些解决方案:

  • 在没有全局或静态变量的情况下配置Bison和Flex
  • Flex和Bison的重入解析器
  • 使用Flex和Bison创建一个可重入的解析器
  • 用Flex编写重入词法分析器
  • 在Bison和Flex中实现可重入的解析器

但它们都不起作用,导致类似的错误。 如果有人可以指导我完成这个任务,我将不胜感激。

软件版本

操作系统:Debian(测试),Bison:3.0.4,Flex:2.5.39,GCC:5.2.1,制作:4.0。

经过修补后我找到了一个解决方案。 因此,问题来自于flex和bison之间的循环依赖。

解析器以这种方式生成了调用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甚至包括lexer头:

 error: unknown type name 'yyscan_t' 

一种解决方法是将其定义为void:

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

yyscan_t定义: flex yyscan_t

所以这是最终的结果:

scanner.l

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

Fabricio Sanches接受的答案帮助我解决了两个问题:

  1. error: unknown type name 'yyscan_t'确实已通过更改为void *来解决。

  2. 与循环依赖相关的冲突决定了非常严格的导入顺序

您调用Flex / Bison的yyparse的代码:

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

Flex(Lexer.lm):

 %{ #import "parser.h" %} 

野牛(Parser.ym):

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

我在Mac OS上编写了关于使用Flex和Bison创建重入解析器的过程的博客文章,其中包含了与Xcode项目集成的示例: 使用Flex和Bison的重入解析器 。