Search code examples
c++bisonflex-lexer

Flex Bison Reentrant C++ Parser: yyscanner undeclared identifier


I'm attempting to create a reentrant parser using C++ with flex and bison. I'm also using a driver class Driver. I'm getting the error 'yyscanner' : undeclared identifier on the lex side of things. I think it has something to do with the reentrant option in flex, which is strange since I would have assumed that driver would have been used in it's place, since I declare yylex as yylex(Driver& driver) in driver.h. Is there anything I've done wrong in my code below to get this error message? Any help would be much appreciated.

parser.y

%require "3.2"
%define parse.error verbose

%locations
%param { Driver& driver }
%language "c++"
%define api.value.type variant


%code requires {
  class Driver;
}

%code {
    #include "driver.h"
}

...

lexer.l


%option noyywrap noinput nounput
%option nodefault
%option nounistd
%option reentrant

%{
#include <iostream>
#include <string>
#include "driver.h"
#include "parser.tab.h"
%}
 
%%

%{
 yy::location& loc = driver.location;

%}

...

driver.h

#ifndef DRIVER_HH
#include "parser.tab.h"

#define YY_DECL \
        int yylex(Driver& driver)
YY_DECL;

class Driver
{
public:
    Driver()  {}

    yy::location location;
};
#endif // ! DRIVER_HH


Solution

  • If you generate a reentrant scanner, you must define its prototype to include a parameter named yyscanner of type yyscan_t. And you need to call the scanner with that argument. You cannot substitute some type you have defined for the yyscan_t argument, because your type does not include the data members which the flex-generated scanner uses. And you must use the name yyscanner because that's how the code generated by Flex references the data members.

    If you want a yylex which only needs one argument, the "official" way to do that is to put your data members (or a pointer to them) into the "extra data" in the yyscan_t. But it might be easier to just use two arguments.