cbisonflex-lexerreentrancy

yydestruct too few arguments to function call (flex&bison)


I'm trying to make a reentrant flex&bison parser but I got this strange error:

too few arguments to function call, expected 5, have 4

I can see that the code generated by Bison looks like this:

static void
yydestruct (const char *yymsg,
            yysymbol_kind_t yykind, YYSTYPE *yyvaluep, void *scanner, struct BisonOutput *out)
{  ...some code... }

and

int
yyparse (void *scanner, struct BisonOutput *out)
{
  ...some code...
 yydestruct ("Cleanup: discarding lookahead",
                  yytoken, &yylval, out);   // <--- here void*scanner parameter is clearly missing 
  ...some code...
}

My code is this:

%define api.pure full
%lex-param {void *scanner}
%parse-param {void *scanner, struct BisonOutput *out}
%{
struct BisonOutput{
    int out; 
};
#include "syntax_parser.h"
#include "lex.yy.h"
#include <stdio.h>
%}
%define api.value.type union
%token <int> NUM
...bunch of other tokens...
%%
...bunch of grammar rules...
%%
... main function and such ...

And Flex code is as follows:

%{ 
#include "syntax_parser.h"
%} 
%option reentrant  bison-bridge noyywrap
blanks          [ \t\n]+ 
number          [0-9]+
%option noyywrap  
%% 
... bunch of rules ...

I'm really lost. Why doesn't bison plug scanner into yydestruct despite clearly using it in yyparse?


Solution

  • You are not allowed to put two parameters in a %*-param declaration. The correct way to produce the set of parameters you want is:

    %param { void* scanner }
    %parse-param { struct BisonOutput* out }
    

    Bison doesn't really parse the code between { and }. All it does is identify the last identifier which it assumes is the name of the parameter. It also assumes that the code is a syntactically-correct declaration of a single parameter, and it is inserted as such in the prototypes. Since it's actually two parameters, it can be inserted without problem into a prototype, but since only one argument is inserted into the calls to the function, these don't match the prototype.

    (Really, void* scanner should be yyscan_t scanner, with a prior typedef void* yyscan_t;. But perhaps it is not really better.)

    You might also consider putting the declaration of struct BisonOutput into a %code requires (or %code provides) block, so that it is automatically included in the bison-generated header file.