patchBison - Patches: patch #9618, C++17 skeleton with move semantics...

 
 

You are not allowed to post comments on this tracker with your current authentication level.

patch #9618: C++17 skeleton with move semantics and std::variant

Submitter:  Frank Heckenbach <frank>
Submitted:  Sat 14 Apr 2018 05:54:37 AM UTC
   
 
Category:  None Priority:  5 - Normal
Status:  Done Privacy:  Public
Assigned to:  None Open/Closed:  Closed

Wed 07 Nov 2018 05:00:00 PM UTC, comment #2: 

Bison 3.2 has caught up with this proposal.  Thanks again.

Akim Demaille <akim>
Group administrator
Sat 14 Apr 2018 05:57:05 AM UTC, comment #1: 

Patch depends on:
https://savannah.gnu.org/patch/index.php?9617
(where to add this properly?)

Frank Heckenbach <frank>
Sat 14 Apr 2018 05:54:37 AM UTC, original submission:  

Following the discussion starting in http://lists.gnu.org/archive/html/bug-bison/2018-03/msg00002.html I have implemented a Bison skeleton for C++17 supporting features such as move semantics and std::variant, based on the existing C++ skeleton. It is attached.

It uses new file names to avoid conflicts with existing Bison data:

  stack-c++11.hh
  variant-c++17.hh
  c++17.m4
  lalr1-c++17.cc

To use it, use the following setting in your parser:

  %skeleton "lalr1-c++17.cc"

An example calc-c++17, based on Bison's calc++ example, is included.

The new skeleton provides the following features:

- Includes bugfix for syntax_error constructor inlining, see: http://lists.gnu.org/archive/html/bug-bison/2018-03/msg00047.html

- Includes extra_header_prefix support, see http://lists.gnu.org/archive/html/bug-bison/2018-03/msg00058.html

- Always uses std::move (C++11) instead of copying internally, to support move-only types for semantic values. In user actions, it's up to you to use std::move where necessary (see the following point).

- A new define api.rhs.access that is applied automatically to all occurrences of "$n". E.g., the following setting will apply std::move to all such occurrences. Note that this can be dangerous if the same "$n" is used more than once in one action, or in an action and a previous mid-rule action. It's up to you then to make sure this does not occur, or take measures to avoid such problems when it occurs:

  %define api.rhs.access {std::move}

- In rules with no explicit user action, a default action "$$ = std::move ($1);" is executed. That's the behaviour according to the documentation, and also the behaviour of the C skeleton, and implementing it (when using std::variant) was less work than changing the documentation.

- When there is a user action, there is no pre-action of setting $$ to $1. (The C skeleton has one accidentally, but warns users not to rely on it. With move-only types, it would not be easily possible to provide such a pre-action without destroying $1.)

  Instead, $$ is set up before the user action as follows:

  Without variants, $$ is always set to { }, i.e. default-initialized.

  With variants, for non-empty rules, $$ is also default-initialized (to an invalid variant), so unless the user action sets $$, a bad_variant_access will happen when it's used by other rules. This may catch some errors in user actions.

  With variants, for empty rules, $$ is initialized to the default value of the correct type. The user action may set it or leave it. This makes it easier to build containers starting from a default (empty) one as in the following example:

  %type <std::vector <foo>> foo_list
  %type <foo> foo

  %%

  foo_list:
    %empty { }
  | foo_list foo { ($$ = std::move ($1)).push_back (std::move ($2)); };

- Bison's existing stack implementation works fine for the most part. Some cosmetic changes were made, such as using size_t where appropriate and explicitly declaring copy constructor/assignment as "= delete" instead of declaring and not defining them. The stealing push function was turned into a proper moving one (i.e., taking a rvalue reference).

- The stack continues to use std::vector by default, and I think that's fine. If, however, you want to use another container instead, you can now set the following defines, e.g. for std::deque:

  %define api.stack.include deque
  %define api.stack.container {std::deque}

  The included example does this, but also works without it.

  If your container requires some setup, you can overload yy::stack_prepare. By default, it does "reserve (200);" for std::stack (as before) and nothing for other containers.

- Uses std::variant (C++17) instead of Bison's own variant implementation.

  If you don't have C++17 support yet, you can use an alternative variant implementation such as https://github.com/mpark/variant . Boost.Variant might also work; I have not tried it.

- When using variants, to build tokens manually, instead of "yylval->build(...)", you must now use the std::variant interface such as "yylval->emplace<...>(...)". However, the provided make_FOO functions continue to work, are recommended anyway, and accept rvalue references now.

Using std::variant fixes the following problems:

- $<type> (especially in mid-rule actions) didn't work at all (see http://lists.gnu.org/archive/html/bug-bison/2017-06/msg00000.html), now works (internally, this required a variant_setter<> helper function in order to support the "=" syntax).

- $<type> where "type" is a type that does not occur in the variant:

  With lalr1.cc, if the type is not bigger than the largest variant, it would happen to work (if not for the previous bug), otherwise would assert if parse.assert is set, and result in undefined behaviour if not set.

  With the new skeleton, this fails at compile time.

- $<type>, reading a different variant than was set:

  With lalr1.cc, it would assert if parse.assert is set, otherwise undefined behaviour.

  With the new skeleton, throws std::bad_variant_access.

- Likewise when the lexer returns a wrong type of variant (can't happen with the make_FOO functions, but when building tokens manually).

- %destructor

  With lalr1.cc, it does not work reliably (with or without variants) whenever the dynamic type does not match the expected type of the token.

  The new skeleton removes support of "%destructor" and warns when it's declared. Regular C++ destructors should do the job in all cases and are applied to the correct dynamic type.

- %printer

  With lalr1.cc, it doesn't work for $<type> overrides (in particular with mid-rule actions) with variants.

  The new skeleton removes support of "%printer" when using variants, and warns. (It continues to work with non-variant semantic values.)

  The idiomatic way of doing this kind of thing with std::variant is std::visit which will always use the current dynamic type. The new skeleton does this, calling a new function yy::yy_print_value(). By default this function does nothing, but you can overload it; the generated code will always call it with a "const T&" argument, so unless you plan to call it yourself, you only need to overload const-reference versions.

  The included example contains two ways of defining yy_print_value in calc-c++17-parser.yy, one rather simple one and a more generic and more complex one. Depending on your needs, you can build on either of them or write your own print functions.

PS: I've signed a copyright assignment for GNU Bison many years ago, so I hope this code can be integrated without problems.

Frank Heckenbach <frank>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attached Files
file #43924:  c++17-skeleton.patch added by frank (76KiB - text/x-diff)

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by akim (Posted a comment)
  • -email is unavailable- added by frank (Submitted the item)
  • -email is unavailable- added by frank
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

     

    Follow 4 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2018-11-07 akim StatusNone Done
        Open/ClosedOpen Closed
    2018-04-14 frank Attached File- Added c++17-skeleton.patch, #43924
        Carbon-Copy- Added frank

    Back to the top

    Powered by Savane 3.13-02a9.
    Corresponding source code