具有联合YYSTYPE

时间:2017-05-22 02:30:50

标签: header-files bison flex-lexer yacc lex

我遇到一个问题,我认为flexbison生成的标头之间存在循环依赖关系。类型yyscan_t在lex头中定义,并且在yacc头中需要。宏YYSTYPE在yacc头中定义,并且在lex头中需要。无论我导入两个标题的顺序是哪一个,另一个都不会满意。

reentrant.lex:

%{
#include "reentrant.yacc.h"
%}

%option reentrant bison-bridge

%%

[0-9]+     { yylval->int_value = atoi(yytext); return INT_TERM; }
[a-zA-Z]+  { yylval->str_value = strdup(yytext); return STR_TERM; }
,          { return COMMA;    }

reentrant.yacc:

%{

// UN-COMMENT THE FOLLOWING LINE TO "FIX" THE CYCLE
//typedef void * yyscan_t

#include "reentrant.yacc.h"
#include "reentrant.lex.h"

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

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

%union {
  int int_value;
  char * str_value;
}

%token <int_value> INT_TERM
%token <str_value> STR_TERM
%token COMMA
%type  <int_value> int_non_term
%type  <str_value> str_non_term

%%

complete : int_non_term str_non_term { printf(" === %d === %s === \n", $1, $2); }

int_non_term : INT_TERM COMMA { $$ = $1; }
str_non_term : STR_TERM COMMA { $$ = $1; }

%%

int main(void) {
  yyscan_t scanner;

  yylex_init(&scanner) ;
  yyset_debug(1, scanner);
  yydebug=1;

  int val = yyparse(scanner);

  yylex_destroy (scanner) ;
  return val;
}

int yywrap (yyscan_t scanner) {
  return 1;
}

void yyerror(yyscan_t scanner, char * msg) {
  fprintf(stderr, msg);
}

GCC输出:

In file included from reentrant.yacc:5:0:
reentrant.yacc.h:74:14: error: unknown type name ‘yyscan_t’
 int yyparse (yyscan_t scanner);
              ^~~~~~~~

使用的命令参数:

bison -vt --debug --defines=reentrant.yacc.h -o reentrant.yacc.c reentrant.yacc
flex -8 -d --header-file=reentrant.lex.h -o reentrant.lex.c reentrant.lex 
gcc -Wall -Wno-unused-function -g reentrant.lex.c reentrant.yacc.c -o reentrant

软件版本

$ flex --version
flex 2.6.4

$ bison --version
bison (GNU Bison) 3.0.4
Written by Robert Corbett and Richard Stallman.

Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ gcc --version
gcc (GCC) 6.3.1 20170306
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

YYSTYPE:

在这里,您可以看到YYSTYPE在yacc标头中定义并在lex标头中使用。

$ grep 'YYSTYPE' *.h 
reentrant.lex.h:YYSTYPE * yyget_lval ( yyscan_t yyscanner );
reentrant.lex.h:void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner );
reentrant.lex.h:               (YYSTYPE * yylval_param , yyscan_t yyscanner);
reentrant.lex.h:               (YYSTYPE * yylval_param , yyscan_t yyscanner)
reentrant.yacc.h:#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
reentrant.yacc.h:union YYSTYPE
reentrant.yacc.h:typedef union YYSTYPE YYSTYPE;
reentrant.yacc.h:# define YYSTYPE_IS_TRIVIAL 1
reentrant.yacc.h:# define YYSTYPE_IS_DECLARED 1

yyscan_t:

在这里,您可以看到yyscan_t在lex标头中定义并在yacc标头中使用。

$ grep 'yyscan_t' *.h        
reentrant.lex.h:typedef void* yyscan_t;
<snip lots of function decls including yyscan_t>
reentrant.yacc.h:int yyparse (yyscan_t scanner);

1 个答案:

答案 0 :(得分:1)

这是一个非答案,真的,但我看到这个问题没有得到应有的关注,所以我发布这是一个令人沮丧的提醒,这是野牛设计中的这个严重缺陷。

不可能(至少在当前版本的bison / flex中)干净地包含适当的头文件。原因是bison生成的* .h文件的结构(与%union声明所代表的完全相同):union YYSTYPE {...} YYSTYPE;声明后面紧跟int yyparse( yyscanner_t yyscanner);声明{1}}(除非您将前缀yy更改为其他内容)。由于没有机制可以在两个声明之间插入flex 生成的词法定义文件,无论lexer定义包含在哪里,冲突都是不可避免的,无论解析器定义是否包括在内。将lexer * .h文件放在解析器之前(或%union声明之前),gcc会抱怨不知道YYSTYPE是什么。在---之后包含它,编译器将不知道yyscanner_t声明中yyparse的含义。

除非bison分别输出其%defines文件的不同块,否则不清楚如何解决这个问题。解决此问题的一种实用方法是在将yyscanner_t定义为void *之后首先包含解析器定义(无论是宏还是typedef,无关紧要,两者都有效,两者都是一样的丑陋),然后是flex生成的定义文件。