Cyclic Dependency in reentrant flex / bison headers with union YYSTYPE

戏子无情 提交于 2019-12-23 02:34:38

问题


I have a problem where I believe there is a cyclic dependency between the headers generated by flex and bison. The type yyscan_t is defined in the lex header and needed in the yacc header. The macro YYSTYPE is defined in the yacc header and needed in the lex header. No matter which order I import the two headers, the other will not be happy.

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 Output:

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

Command Arguments Used:

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

Software Versions:

$ 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:

Here you can see that YYSTYPE is defined in the yacc header and consumed in the lex header.

$ 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:

Here you can see that yyscan_t is defined in the lex header and consumed in the yacc header.

$ 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:


This is a non-answer, really, but I see that the question has not received the attention it should have so I am posting this as a depressing reminder of this serious flaw in bison's design.

It is not possible (at least in the current version of bison/flex) to cleanly include the appropriate header files. The reason is the structure of the *.h file produced by bison (which is exactly the same as what appears in place of the %union declaration): the union YYSTYPE {...} YYSTYPE; declaration is followed immediately by the declaration for int yyparse( yyscanner_t yyscanner); (unless you changed the prefix yy to something else). As there is no mechanism to insert the lexer definitions file produced by flex between the two declarations, no matter where the lexer definitions are included, the conflict is inevitable, whether or not the parser defines are included as well. Put the lexer *.h file before the parser one (or before the %union declaration) and gcc will complain about not knowing what YYSTYPE is. Include it after---and the compiler will not know what yyscanner_t means in the yyparse declaration.

Unless bison outputs different chunks of its %defines file separately, it is unclear how this can be resolved. A practical way to circumvent this problem is to include the parser defines first after defining yyscanner_t as void * (whether as a macro or a typedef, does not matter, both work and both are equally ugly), followed by the definitions file produced by flex.



来源:https://stackoverflow.com/questions/44103798/cyclic-dependency-in-reentrant-flex-bison-headers-with-union-yystype

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!