[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: User-defined classes in C++ Bison grammar

From: Akim Demaille
Subject: Re: User-defined classes in C++ Bison grammar
Date: Tue, 4 Dec 2018 06:30:36 +0100

Hi Wouter!

> Le 3 déc. 2018 à 22:38, Wouter Beek <address@hidden> a écrit :
> Dear Bison devs,
> I really like the recent developments in Bison 3.1 and 3.2 that improve the
> support for modern C++ programming techniques.

Thanks for saying this!

> As a result, I'm writing my
> first C++ Bison parser, but run into some issues that may or may not be
> limitations of the current state of C++ support:
>  1. When I use a user-defined class in my Bison parser, I *must* define a
> default constructor.  Is this an inherent requirement/limitation of Bison?

Well, it's a limitation inherent to the Yacc model I guess.

The way Yacc works is by letting the user write actions as code,
involving the "input" ($1, $2, etc.), to compute and store the output
in $$.  

: exp "+" exp { $$ = $1 + $3; }
| exp "*" exp { $$ = $1 * $3; }
| "number"    { $$ = $1; }

So $$ must be constructed before we hand it over to the user action.

In some other world, it would have been possible to require that
the user action is not a statement, but an expression, something

: exp "+" exp ($1 + $3)
| exp "*" exp ($1 * $3)
| "number"    ($1)

in which case I guess it would have been possible to build $$ instead
of assigning to it.

But anyway C, C++ and Java (the languages currently supported by Bison)
offering a really poor support for rich expressions, I very much doubt
there would be enough interest to justify this new model of actions.   

> While it is always possible to define a ‘dummy’ default constructor in
> combination with using pointers for all member values, this sometimes makes
> the code less logical/pretty.  Specifically, when I use a user-defined
> class `A' with no default constructor the compiler emits the following
> errors:

I'll see if I can get a better error message in modern C++.

>  2. When I use a user-defined sub-class (`B') of a virtual class (`A'), I
> get the following errors during compilation.  Could it be that Bison does
> not (yet) support sub-classes / virtual classes?

I don't really see in what way Bison is concerned by the inheritance.
Note that you have to use the super classes in your %type.  Don't do
this (provide Sum derived from Exp):

%type <Exp*> exp
%type <Sum*> sum
sum: exp "+" exp { $$ = new Sum{$1, $3}; }
exp: sum

do this:

%type <Exp*> exp sum
sum: exp "+" exp { $$ = new Sum{$1, $3}; }
exp: sum

This is ok too:

%type <Exp*> exp
%type <Sum*> sum
sum: exp "+" exp { $$ = new Sum{$1, $3}; }
exp: sum         { $$ = $1; }

but your problem seems to be elsewhere.

>   Or is this something one
> can work around in some way?  I have an actual use case for this: I would
> like to define a pure virtual `Term' with sub-classes `BlankNode', `Iri',
> and `Literal'.
>     In file included from
> /usr/include/c++/8/x86_64-redhat-linux/bits/c++allocator.h:33,
>                      from /usr/include/c++/8/bits/allocator.h:46,
>                      from /usr/include/c++/8/string:41,
>                      from /usr/include/c++/8/bits/locale_classes.h:40,
>                      from /usr/include/c++/8/bits/ios_base.h:41,
>                      from /usr/include/c++/8/ios:42,
>                      from /usr/include/c++/8/ostream:38,
>                      from /usr/include/c++/8/iostream:39,
>                      from parser.yy:14,
>                      from parser.cpp:40:

Guessing your grammar file from the compiler errors is too hard for me
to be able to help you.

Of course, if Exp is an abstract class (A in your case) you cannot
do this:

%type <Exp> exp

you must go through a pointer (raw or not).

>  3. I regularly run into compilation issues due to the definition of the
> driver's methods `scan_begin()' and `scan_end()' in the parser source file
> `scanner.ll'.  Is it possible to make these methods part of `driver.cpp'?

It would make sense, sure, but these functions often need to call
functions of the scanner that are not exposed in a header file.
If it works for you to put them in the driver's implementation, that's
fine by me.

> The way in which the code is currently spread over files seems a bit
> unorganized.
> PS: I have published the accompanying code over at

Doh.  I should have started there...

Well, I believe the problem is here:

> class driver {
> public:
>   int parse(std::string& file_name);
>   std::string file_name;
>   yy::location location;
>   bool trace_parser {false};
>   bool trace_scanner {false};
>   std::vector<A> values;        <=============
>   void scan_begin();
>   void scan_end();
> };

Don't try to make vectors of abstract classes.  You need a pointer
or some indirection.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]