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);