I enthusiastically support this proposal. I agree with the preference for prefix positioning. The `%type` keyword is just noise, imho, and thus unnecessary.
I like the `name=<type>{ code }` syntax, too, but it's probably too late for that. Perhaps `{ code }[<type>name]` would be a plausible alternative syntax, although I'd still prefer `<type>` in prefix position. Although unrelated to this proposal, I would also favour allowing %% <type> nonterminal: rhs as an alternative to %type <type> nonterminal %% nonterminal: rhs Rici On Sun, Jun 17, 2018, 09:02 Akim Demaille <a...@lrde.epita.fr> wrote: > Hi all, > > > Le 29 juin 2017 à 15:55, Piotr Marcińczyk <piomar...@gmail.com> 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: > 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 > action: > - 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: > NUM > | expr %type<int>{ $$ = 42; } '+' NUM { std::cout << $2 << '\n'; }; > > It’s not clear whether it should be prefix or postfix > > expr: > NUM > | 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: > NUM > | expr <int>{ $$ = 42; } '+' NUM { std::cout << $2 << '\n'; }; > > or > > expr: > NUM > | expr { $$ = 42; }<int> '+' NUM { std::cout << $2 << '\n'; }; > > > Personally, I prefer the prefix forms, but they don’t blend > nicely with named references: > > expr: > NUM > | expr <int>{ $$ = 42; }[val] '+' NUM { std::cout << $val << '\n'; }; > > Thoughts? > > > > > > I wish we had chosen a prefix syntax for named references, say > > expr: > NUM > | 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: > NUM > | expr val<int>={ $$ = 42; } '+' NUM { std::cout << $val << '\n'; }; > > > > >