Search code examples
c++bisonlex

How to move from a C to C++ style flex parser


I have the typical reentrant C style parser, where the parsed data is contained in an union like the following one:

%union {
    int number;
    const char *string;
    Item *item_ptr;
}

I would like to use Shared Pointers instead of normal pointers.

I cannot use std::shared_ptr because I cannot compile the source code with C++11, I am also forbidden to use boost::shared_ptr. Thus, I have my own class SharedPtr, implementing the desired behaviour.

Unfortunately, I cannot plug the SharedPtr class within the union as follows:

%union {
    int number;
    const char *string;
    SharedPtr<Item> item_ptr;
}

because I get the following error:

bisonparser.yy:92:20: error: member ‘SharedPtr<Item> YYSTYPE::item_ptr’ with constructor not allowed in union
bisonparser.yy:92:20: error: member ‘SharedPtr<Item> YYSTYPE::item_ptr’ with destructor not allowed in union
bisonparser.yy:92:20: error: member ‘SharedPtr<Item> YYSTYPE::item_ptr’ with copy assignment operator not allowed in union
bisonparser.yy:92:20: note: unrestricted unions only available with -std=c++11 or -std=gnu++11

An alternative could be inserting a level of indirection as follows:

%union {
    int number;
    const char *string;
    SharedPtr<Item> *item_ptr;
}

However, I wonder if there is a much cleaner way to design my project so that I can use my SharedPtr class directly instead of as a pointer. What are the minimal changes that I have too look for to get to the alternative solution?


Solution

  • The basic problem is that bison's C interface uses unions heavily (from %union) and C unions are pretty incompatible with C++ (pre-C++11 you can't use them at all with non-trivial types and even post C++11 they are hard to use safely).

    On possibility is to use Bison's C++ mode, but that is a fairly verbose and wide-ranging change. Alternately, you can (carefully) use raw pointers and other types that are safe to put in a union. You'll need to be very careful to avoid memory leaks however (and use bison's %destructor to avoid leaks with syntax errors)

    Another possibility is to not use %union at all -- instead use #define YYSTYPE SharedPtr<Item> to make the stack value a single shared pointer that you'll use everywhere in the code. You need to have your Item type be a base class with all your other types deriving from it, using virtual functions as appropriate.