> On 8 Mar 2018, at 00:33, Frank Heckenbach <[email protected]> wrote: > >>> Sure, it's not required (nothing about the C++ mode is), but it >>> might be convenient for the user as it avoids a trap. I have a >>> number of such rules in my grammars, and if you hadn't mentioned it, >>> I'd have been caught by this, not even at compile-time, but at >>> runtime. (Though such a bug would probably be rather obvious and >>> easy to fix in all places, not the end of the world.) >> >> It should complain if not having a not supported semicolon. > > Not sure I follow you here. If I have a rule like "foo: bar;" where > foo and bar have the same (non-void) type, the C skeleton does > "$$ = $1"; the standard C++ skeleton just default-initializes $$ > (so it will not be undefined, just empty). My patch does > "$$ = std::move ($1)" (effectively).
We are speaking about different things here: In Yacc grammar one drop the ";". >> It might be good to be able to change container, C++ perhaps sues >> a deque for stack as copying might be expensive. > > Since std::stack moves instead of copying when possible, not quite > so expensive. Also bison by default reserve()s 200 entries, and I > think you rarely need a parser stack deeper than this, so this might > be a theoretical problem. The type std::stack is older, but some benefits of std::deque are mentioned here: http://en.cppreference.com/w/cpp/container/deque >>>> Using inline functions for the actions might do it. The compiler >>>> can then remove the inlines, but the moves should be still applied >>>> correctly. Or maybe not, depending on how the C++ standard is >>>> written. >>> >>> AFAIK, it allows for (and modern compilers do) automatic moving for >>> the return value only. So inline functions would help in cases such >>> as the default action ("$$ = $1", if "$$ =" was replaced by "return" >>> and "$1" was a function parameter), and similar cases such as >>> "$$ = $2" (which typically occurs in rules such as '(' expr ')') >>> where a default action doesn't help. >> >> Perhaps if it know that $1 expires, it can apply a move assignment. > > It could do that if $1 is mentioned only once. In fact, I just > checked my grammars and in almost all cases that's so (not counting > a later "free ($1)" or "delete $1" which is part of the manual > pointer management which would disappear with unique_ptr); for me > that's because I prefer to keep my actions short and do all > non-trivial work in subfunctions. > > It's still not a silver bullet: Others might prefer longer actions > that regularly mention $n more than once, and even I have at least > one such rule, basically: > > a: b c { $$ = $2.empty () ? $1 : combine ($1, $2); }; > > Here, moving from $1 would be safe in both places as only one is > executed; moving from $2 is safe in the combine() call, not in the > empty() call (but also not required, since empty() is a const member > function). That's not too difficult for a programmer to see, but > almost impossible for Bison to do automatically. > > Of course, Bison could give up there (and possibly warn about it), > and still do automatic moving in other situations. I think it would be complicated, so just std::move for now. >>> I think it's an interesting idea, also for syntactic reasons: >>> Writing "return" instead of "$$ =" seems more natural (though of >>> course, you have to watch out: "$$ =" can be followed by other >>> statements, "return" cannot, so Bison couldn't simply replace it, >>> but a user can deal with it). Also functions could have named >>> parameters (which you seem to prefer anyway) always instead of "$1" >>> etc. So if I'd design Bison now, that's probably what I'd do. But >>> given things as they are, this might be too big a change, both to >>> implement, and for many users to adopt. >> >> I though of it just as an implementation, but whatever. > > I did so at first, but then I realized that Bison would have to > replace "$$ =" with "return" which is dangerous as I said. So it > would probably be easier in the long run to leave this to the > programmer. (But again, I doubt this will be implemented.) And maybe the C++ standard does not admit one relying on it. >> [GC] >> >> I use it for dynamic polymorphism like in Scheme/Guile, where you >> can't tell when the object expires. > > shared_ptr also does it (and I used it where I need it), but ... The std::shared_ptr is simplistic, and the more advanced variation I used turned out to be too complicated. > >> Where automatic objects can be used, that is better. > > ... indeed, most of the time, automatic objects or unique_ptr > suffices for me and I prefer to use it. A GC possibility is isolate object with known lifetime and register those with pointers into the GC heap. >>> 3. shared_ptr: Has the performance problems as I described. >> >> I don't recall this. > > Lack of release method, so it would propagate throughout all my > code. See first mail in thread. I am not sure why you need it in the parser. Just put the object on the heap and use shared_ptr in the semantic value, but nowhere else. >>>> Since C++17 now is available and supported by GCC7, std::variant would be >>>> best to use. >>> >>> Agreed. It will require some changes to the code using it, but it >>> will actually make it simpler. >> >> And more reliable, as the compiler developers pay attention to it. > > And more type-safe. std::variant checks more at compile-time that > Bison's variant doesn't. You may do your own M4 files, and as Bison isn't development, there is no risk for it to become outdated, and maybe get it integrated later.
