问题
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