[Top][All Lists]

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

Re: Bison C++ mid-rule value lost with variants

From: Akim Demaille
Subject: Re: Bison C++ mid-rule value lost with variants
Date: Sun, 17 Jun 2018 16:02:32 +0200

Hi all,

> Le 29 juin 2017 à 15:55, Piotr Marcińczyk <address@hidden> a écrit :
> I supposedly found a bug in lalr1.cc skeleton with variant semantic type.
> When using mid-rule action { $<type>$ = value; } to return a value that
> will be used in further semantic actions, it appears that the value on
> stack becomes zero. Tested with Bison version 3.0.4.

Piotr’s grammar file includes:

%token <int> NUM
| expr { $<int>$ = 42; } '+' NUM { std::cout << $<int>2 << '\n'; };

and one can see that when run, $<int>2 is not 42, but 0.

My opinion on this is somewhat different from the ones that
have been expressed so far.  IMHO, it has no good reason
to work.

Yes, it works with plain old unions.  But that’s unsafe, and
that’s because you hide things from your tool (Bison).  I
personally see these typed accesses to the semantical
values ($<int>2) are no different from a cast (and actually,
that’s exactly what they are with unions).

Yes, it works with C++ variants, or even std::any, when
used as a store for semantical values.  But we are still lying
to the tool.

I think this example shows that the design of mid-rules
actions has some loopholes, and in particular something which is
critically missing is the type of its semantical value.  Since,
Bison does not know the type of the semantical value of a mid-rule
- the user must use $<int>$, not $$
- the destructor will not work
- the printer won’t work either
- the user must also be explicit when using the value in
  the other actions ($<int>2).

Sure, using std::variant or std::any we avoid the first three issues,
but that’s still by hiding things from Bison and relying on
magic on the language side.  And obviously that works only for
C++, and actually modern C++.

I think we should rather provide typed mid-rule actions.

How about:

| expr %type<int>{ $$ = 42; } '+' NUM { std::cout << $2 << '\n'; };

It’s not clear whether it should be prefix or postfix

| expr { $$ = 42; } %type<int> '+' NUM { std::cout << $2 << '\n'; };

The regular use of %type is prefix (%type <int> expr), but the
directives in rules are usually presented as postfix
(exp: "if" exp exp %prec "then"), although it is not mandatory.

Or go for a lighter syntax

| expr <int>{ $$ = 42; } '+' NUM { std::cout << $2 << '\n'; };


| expr { $$ = 42; }<int> '+' NUM { std::cout << $2 << '\n'; };

Personally, I prefer the prefix forms, but they don’t blend
nicely with named references:

| expr <int>{ $$ = 42; }[val] '+' NUM { std::cout << $val << '\n'; };


I wish we had chosen a prefix syntax for named references, say

| expr val={ $<int>$ = 42; } '+' NUM { std::cout << $<int>val << '\n'; };

I think we discussed this with Joel E. Denny, but I don’t remember
the details. We could have used

| expr val<int>={ $$ = 42; } '+' NUM { std::cout << $val << '\n'; };

reply via email to

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