diff --git a/packages/PEGTL/.gitrepo b/packages/PEGTL/.gitrepo
index 918765134b65b22ad91cb3017ec1f701e3a2d144..13c3bc8b31205195acd81b7e81e3089b28b88ba3 100644
--- a/packages/PEGTL/.gitrepo
+++ b/packages/PEGTL/.gitrepo
@@ -6,6 +6,6 @@
 [subrepo]
 	remote = git@github.com:taocpp/PEGTL.git
 	branch = master
-	commit = 2830ae439ccb330f096557fb3e3b2836e528412e
-	parent = b18425061085e4396454779a0efbe200927f4a9d
+	commit = 0a5ab8c8efb421f00d9b0e3f593c971991888a97
+	parent = 8a3664d89a9a662c3dfdd402d573b3618ebbdbbf
 	cmdver = 0.3.1
diff --git a/packages/PEGTL/CMakeLists.txt b/packages/PEGTL/CMakeLists.txt
index fb3e696fd20f1d495c7f5f97635c7994e6e75570..c355e7cfb804aa7da64055d1b24ebde39d40c781 100644
--- a/packages/PEGTL/CMakeLists.txt
+++ b/packages/PEGTL/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required (VERSION 3.3.0 FATAL_ERROR)
 
-project (pegtl VERSION 2.7.0 LANGUAGES CXX)
+project (pegtl VERSION 2.7.1 LANGUAGES CXX)
 
 # installation directories
 set (PEGTL_INSTALL_INCLUDE_DIR "include" CACHE STRING "The installation include directory")
diff --git a/packages/PEGTL/doc/Changelog.md b/packages/PEGTL/doc/Changelog.md
index 692a3b8f09ca8428c792a0ff4265a1a794e454fa..06b7ff0fd4ed30b01bb38acfeb3ebd1d82a8fad5 100644
--- a/packages/PEGTL/doc/Changelog.md
+++ b/packages/PEGTL/doc/Changelog.md
@@ -1,5 +1,15 @@
 # Changelog
 
+## 2.7.1
+
+Released 2018-09-29
+
+* Added new ASCII convenience rule [`forty_two`](Rule-Reference.md#forty_two-c-).
+* Added experimental `if_then` rule.
+* Simplified how parse tree nodes can be selected.
+* Reduced the number of intermediate parse tree nodes.
+* Allowed an action class template to be used with the parse tree.
+
 ## 2.7.0
 
 Released 2018-07-31
diff --git a/packages/PEGTL/doc/Installing-and-Using.md b/packages/PEGTL/doc/Installing-and-Using.md
index c3741a9db4ab384afae27aa61d377b454753e10b..7c3ab624bbaf76bdc3b220722b582eeda131ba20 100644
--- a/packages/PEGTL/doc/Installing-and-Using.md
+++ b/packages/PEGTL/doc/Installing-and-Using.md
@@ -10,7 +10,6 @@
   * [Embedding in Binaries](#embedding-in-binaries)
   * [Embedding in Libraries](#embedding-in-libraries)
   * [Embedding in Library Interfaces](#embedding-in-library-interfaces)
-* [Limitations](#limitations)
 
 ## Requirements
 
diff --git a/packages/PEGTL/doc/README.md b/packages/PEGTL/doc/README.md
index 1d9cc5b71e8d97094edbb7a648aa852b77e0ead1..4fc2c5e2d351f9598e0470b4288a7583972a7f28 100644
--- a/packages/PEGTL/doc/README.md
+++ b/packages/PEGTL/doc/README.md
@@ -121,6 +121,7 @@
 * [`eolf`](Rule-Reference.md#eolf) <sup>[(ascii rules)](Rule-Reference.md#ascii-rules)</sup>
 * [`extender`](Rule-Reference.md#extender) <sup>[(icu rules)](Rule-Reference.md#icu-rules-for-binary-properties)</sup>
 * [`failure`](Rule-Reference.md#failure) <sup>[(atomic rules)](Rule-Reference.md#atomic-rules)</sup>
+* [`forty_two< C... >`](Rule-Reference.md#forty_two-c-) <sup>[(ascii rules)](Rule-Reference.md#ascii-rules)</sup>
 * [`full_composition_exclusion`](Rule-Reference.md#full_composition_exclusion) <sup>[(icu rules)](Rule-Reference.md#icu-rules-for-binary-properties)</sup>
 * [`general_category< V >`](Rule-Reference.md#general_category-v-) <sup>[(icu rules)](Rule-Reference.md#icu-rules-for-enumerated-properties)</sup>
 * [`grapheme_base`](Rule-Reference.md#grapheme_base) <sup>[(icu rules)](Rule-Reference.md#icu-rules-for-binary-properties)</sup>
diff --git a/packages/PEGTL/doc/Rule-Reference.md b/packages/PEGTL/doc/Rule-Reference.md
index 4582a688f1bf264865b1f6540a2fafd5a3e8ecf0..bb91804332e446e6150ca005520be874f8eae9fa 100644
--- a/packages/PEGTL/doc/Rule-Reference.md
+++ b/packages/PEGTL/doc/Rule-Reference.md
@@ -408,6 +408,10 @@ can be matched by either `tao::pegtl::ascii::string< 0xe2, 0x82, 0xac >` or `tao
 
 * Equivalent to `sor< eof, eol >`.
 
+###### `forty_two< C... >`
+
+* Equivalent to `rep< 42, one< C... > >`.
+
 ###### `identifier_first`
 
 * Matches and consumes a single ASCII character permissible as first character of a C identifier.
@@ -494,7 +498,7 @@ can be matched by either `tao::pegtl::ascii::string< 0xe2, 0x82, 0xac >` or `tao
 ###### `space`
 
 * Matches and consumes a single space, line-feed, carriage-return, horizontal-tab, vertical-tab or form-feed.
-* Equivalent to `one< ' ', '\n', '\r', 't', '\v', '\f' >`.
+* Equivalent to `one< ' ', '\n', '\r', '\t', '\v', '\f' >`.
 
 ###### `string< C... >`
 
@@ -1097,6 +1101,7 @@ The term *input value* indicates a correspondingly sized integer value read from
 * [`eolf`](#eolf) <sup>[(ascii rules)](#ascii-rules)</sup>
 * [`extender`](#extender) <sup>[(icu rules)](#icu-rules-for-binary-properties)</sup>
 * [`failure`](#failure) <sup>[(atomic rules)](#atomic-rules)</sup>
+* [`forty_two< C... >`](#forty_two-c-) <sup>[(ascii rules)](#ascii-rules)</sup>
 * [`full_composition_exclusion`](#full_composition_exclusion) <sup>[(icu rules)](#icu-rules-for-binary-properties)</sup>
 * [`general_category< V >`](#general_category-v-) <sup>[(icu rules)](#icu-rules-for-enumerated-properties)</sup>
 * [`grapheme_base`](#grapheme_base) <sup>[(icu rules)](#icu-rules-for-binary-properties)</sup>
diff --git a/packages/PEGTL/include/tao/pegtl/ascii.hpp b/packages/PEGTL/include/tao/pegtl/ascii.hpp
index d1542e603520b34097dee34cca0273744fafb85e..b440b4d910253b33cacb11d1bf6fc22b1af15a38 100644
--- a/packages/PEGTL/include/tao/pegtl/ascii.hpp
+++ b/packages/PEGTL/include/tao/pegtl/ascii.hpp
@@ -23,6 +23,7 @@ namespace tao
          struct blank : internal::one< internal::result_on_found::SUCCESS, internal::peek_char, ' ', '\t' > {};
          struct digit : internal::range< internal::result_on_found::SUCCESS, internal::peek_char, '0', '9' > {};
          struct eolf : internal::eolf {};
+         template< char... Cs > struct forty_two : internal::rep< 42, internal::one< internal::result_on_found::SUCCESS, internal::peek_char, Cs... > > {};
          struct identifier_first : internal::identifier_first {};
          struct identifier_other : internal::identifier_other {};
          struct identifier : internal::identifier {};
diff --git a/packages/PEGTL/include/tao/pegtl/buffer_input.hpp b/packages/PEGTL/include/tao/pegtl/buffer_input.hpp
index 4557aaf9afe3b64456f4b36ef24eac9dd65e36c2..143d94d3155f75df52d440e64210286e5ff879b0 100644
--- a/packages/PEGTL/include/tao/pegtl/buffer_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/buffer_input.hpp
@@ -176,6 +176,7 @@ namespace tao
          iterator_t m_current;
          char* m_end;
          const Source m_source;
+         void* internal_state = nullptr;
       };
 
    }  // namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/changes.hpp b/packages/PEGTL/include/tao/pegtl/contrib/changes.hpp
index 04a6fbe9d801dc4bf2226c677926c1b7e0141c07..0aa8ab038dd195273b3f91edf690d32922405e88 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/changes.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/changes.hpp
@@ -7,6 +7,8 @@
 #include "../config.hpp"
 #include "../normal.hpp"
 
+#include "../internal/conditional.hpp"
+
 namespace tao
 {
    namespace TAO_PEGTL_NAMESPACE
@@ -21,23 +23,6 @@ namespace tao
             }
          };
 
-         template< bool >
-         struct conditional;
-
-         template<>
-         struct conditional< true >
-         {
-            template< typename R, typename >
-            using type = R;
-         };
-
-         template<>
-         struct conditional< false >
-         {
-            template< typename, typename R >
-            using type = R;
-         };
-
          template< apply_mode A, typename State >
          using state_disable_helper = typename conditional< A == apply_mode::ACTION >::template type< State, dummy_disabled_state >;
 
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/if_then.hpp b/packages/PEGTL/include/tao/pegtl/contrib/if_then.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..496ada60ec1565923b41130d2125be56a9303711
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/if_then.hpp
@@ -0,0 +1,61 @@
+// Copyright (c) 2018 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_IF_THEN_HPP
+#define TAO_PEGTL_CONTRIB_IF_THEN_HPP
+
+#include <type_traits>
+
+#include "../config.hpp"
+
+#include "../internal/if_then_else.hpp"
+#include "../internal/seq.hpp"
+#include "../internal/skip_control.hpp"
+#include "../internal/trivial.hpp"
+
+namespace tao
+{
+   namespace TAO_PEGTL_NAMESPACE
+   {
+      namespace internal
+      {
+         template< typename Cond, typename Then >
+         struct if_pair
+         {
+         };
+
+         template< typename... Pairs >
+         struct if_then;
+
+         template< typename Cond, typename Then, typename... Pairs >
+         struct if_then< if_pair< Cond, Then >, Pairs... >
+            : if_then_else< Cond, Then, if_then< Pairs... > >
+         {
+            template< typename ElseCond, typename... Thens >
+            using else_if_then = if_then< if_pair< Cond, Then >, Pairs..., if_pair< ElseCond, seq< Thens... > > >;
+
+            template< typename... Thens >
+            using else_then = if_then_else< Cond, Then, if_then< Pairs..., if_pair< trivial< true >, seq< Thens... > > > >;
+         };
+
+         template<>
+         struct if_then<>
+            : trivial< false >
+         {
+         };
+
+         template< typename... Pairs >
+         struct skip_control< if_then< Pairs... > > : std::true_type
+         {
+         };
+
+      }  // namespace internal
+
+      template< typename Cond, typename... Thens >
+      using if_then = internal::if_then< internal::if_pair< Cond, internal::seq< Thens... > > >;
+
+   }  // namespace TAO_PEGTL_NAMESPACE
+
+}  // namespace tao
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp b/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp
index 905f7ccd2ec8a7f38da8fccc3c2cef1ce5ac59e2..66401e5eadd149fa96dd90fec341d92dcdb205d7 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp
@@ -16,6 +16,9 @@
 #include "../nothing.hpp"
 #include "../parse.hpp"
 
+#include "../analysis/counted.hpp"
+#include "../analysis/generic.hpp"
+#include "../internal/conditional.hpp"
 #include "../internal/demangle.hpp"
 #include "../internal/iterator.hpp"
 
@@ -163,7 +166,7 @@ namespace tao
                }
             };
 
-            template< typename Node, typename S, typename = void >
+            template< typename Node, typename Selector, typename = void >
             struct transform
             {
                template< typename... States >
@@ -172,54 +175,102 @@ namespace tao
                }
             };
 
-            template< typename Node, typename S >
-            struct transform< Node, S, decltype( S::transform( std::declval< std::unique_ptr< Node >& >() ), void() ) >
+            template< typename Node, typename Selector >
+            struct transform< Node, Selector, decltype( Selector::transform( std::declval< std::unique_ptr< Node >& >() ), void() ) >
             {
                template< typename... States >
-               static void call( std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( S::transform( n ) ) )
+               static void call( std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( Selector::transform( n, st... ) ) )
                {
-                  S::transform( n, st... );
+                  Selector::transform( n, st... );
                }
             };
 
-            template< template< typename > class S, template< typename > class C >
-            struct make_control
+            template< unsigned Level, typename Analyse, template< typename... > class Selector >
+            struct is_leaf
+               : std::false_type
             {
-               template< typename Rule, bool >
-               struct control;
+            };
 
-               template< typename Rule >
-               using type = control< Rule, S< Rule >::value >;
+            template< analysis::rule_type Type, template< typename... > class Selector >
+            struct is_leaf< 0, analysis::generic< Type >, Selector >
+               : std::true_type
+            {
+            };
+
+            template< analysis::rule_type Type, unsigned Count, template< typename... > class Selector >
+            struct is_leaf< 0, analysis::counted< Type, Count >, Selector >
+               : std::true_type
+            {
+            };
+
+            template< analysis::rule_type Type, typename... Rules, template< typename... > class Selector >
+            struct is_leaf< 0, analysis::generic< Type, Rules... >, Selector >
+               : std::false_type
+            {
+            };
+
+            template< analysis::rule_type Type, unsigned Count, typename... Rules, template< typename... > class Selector >
+            struct is_leaf< 0, analysis::counted< Type, Count, Rules... >, Selector >
+               : std::false_type
+            {
+            };
+
+            template< bool... >
+            struct bool_sequence;
+
+            template< bool... Bs >
+            using is_all = std::is_same< bool_sequence< Bs..., true >, bool_sequence< true, Bs... > >;
+
+            template< unsigned Level, typename Rule, template< typename... > class Selector >
+            using is_unselected_leaf = std::integral_constant< bool, !Selector< Rule >::value && is_leaf< Level, typename Rule::analyze_t, Selector >::value >;
+
+            template< unsigned Level, analysis::rule_type Type, typename... Rules, template< typename... > class Selector >
+            struct is_leaf< Level, analysis::generic< Type, Rules... >, Selector >
+               : is_all< is_unselected_leaf< Level - 1, Rules, Selector >::value... >
+            {
             };
 
-            template< typename Control, template< typename... > class Action, typename Input, typename... States >
-            struct return_type_apply0
+            template< unsigned Level, analysis::rule_type Type, unsigned Count, typename... Rules, template< typename... > class Selector >
+            struct is_leaf< Level, analysis::counted< Type, Count, Rules... >, Selector >
+               : is_all< is_unselected_leaf< Level - 1, Rules, Selector >::value... >
             {
-               using type = decltype( Control::template apply0< Action >( std::declval< const Input& >(), std::declval< States&& >()... ) );
             };
 
-            template< typename Control, template< typename... > class Action, typename Iterator, typename Input, typename... States >
-            struct return_type_apply
+            template< typename Node, template< typename... > class Selector, template< typename... > class Control >
+            struct make_control
+            {
+               template< typename Rule, bool, bool >
+               struct control;
+
+               template< typename Rule >
+               using type = control< Rule, Selector< Rule >::value, is_leaf< 8, typename Rule::analyze_t, Selector >::value >;
+            };
+
+            template< typename Node, template< typename... > class Selector, template< typename... > class Control >
+            template< typename Rule >
+            struct make_control< Node, Selector, Control >::control< Rule, false, true >
+               : Control< Rule >
             {
-               using type = decltype( Control::template apply< Action >( std::declval< const Iterator& >(), std::declval< const Input& >(), std::declval< States&& >()... ) );
             };
 
-            template< template< typename > class S, template< typename > class C >
+            template< typename Node, template< typename... > class Selector, template< typename... > class Control >
             template< typename Rule >
-            struct make_control< S, C >::control< Rule, false >
-               : C< Rule >
+            struct make_control< Node, Selector, Control >::control< Rule, false, false >
+               : Control< Rule >
             {
-               template< typename Input, typename Node, typename... States >
-               static void start( const Input& in, state< Node >& state, States&&... st )
+               template< typename Input, typename... States >
+               static void start( const Input& in, States&&... st )
                {
-                  C< Rule >::start( in, st... );
+                  Control< Rule >::start( in, st... );
+                  auto& state = *static_cast< internal::state< Node >* >( in.internal_state );
                   state.emplace_back();
                }
 
-               template< typename Input, typename Node, typename... States >
-               static void success( const Input& in, state< Node >& state, States&&... st )
+               template< typename Input, typename... States >
+               static void success( const Input& in, States&&... st )
                {
-                  C< Rule >::success( in, st... );
+                  Control< Rule >::success( in, st... );
+                  auto& state = *static_cast< internal::state< Node >* >( in.internal_state );
                   auto n = std::move( state.back() );
                   state.pop_back();
                   for( auto& c : n->children ) {
@@ -227,83 +278,56 @@ namespace tao
                   }
                }
 
-               template< typename Input, typename Node, typename... States >
-               static void failure( const Input& in, state< Node >& state, States&&... st ) noexcept( noexcept( C< Rule >::failure( in, st... ) ) )
+               template< typename Input, typename... States >
+               static void failure( const Input& in, States&&... st ) noexcept( noexcept( Control< Rule >::failure( in, st... ) ) )
                {
-                  C< Rule >::failure( in, st... );
+                  Control< Rule >::failure( in, st... );
+                  auto& state = *static_cast< internal::state< Node >* >( in.internal_state );
                   state.pop_back();
                }
-
-               template< typename Input, typename Node, typename... States >
-               static void raise( const Input& in, state< Node >& /*unused*/, States&&... st )
-               {
-                  C< Rule >::raise( in, st... );
-               }
-
-               template< template< typename... > class Action, typename Input, typename Node, typename... States >
-               static typename return_type_apply0< C< Rule >, Action, Input, States... >::type apply0( const Input& in, state< Node >& /*unused*/, States&&... st )
-               {
-                  return C< Rule >::template apply0< Action >( in, st... );
-               }
-
-               template< template< typename... > class Action, typename Iterator, typename Input, typename Node, typename... States >
-               static typename return_type_apply< C< Rule >, Action, Iterator, Input, States... >::type apply( const Iterator& begin, const Input& in, state< Node >& /*unused*/, States&&... st )
-               {
-                  return C< Rule >::template apply< Action >( begin, in, st... );
-               }
             };
 
-            template< template< typename > class S, template< typename > class C >
-            template< typename Rule >
-            struct make_control< S, C >::control< Rule, true >
-               : C< Rule >
+            template< typename Node, template< typename... > class Selector, template< typename... > class Control >
+            template< typename Rule, bool B >
+            struct make_control< Node, Selector, Control >::control< Rule, true, B >
+               : Control< Rule >
             {
-               template< typename Input, typename Node, typename... States >
-               static void start( const Input& in, state< Node >& state, States&&... st )
+               template< typename Input, typename... States >
+               static void start( const Input& in, States&&... st )
                {
-                  C< Rule >::start( in, st... );
+                  Control< Rule >::start( in, st... );
+                  auto& state = *static_cast< internal::state< Node >* >( in.internal_state );
                   state.emplace_back();
                   state.back()->template start< Rule >( in, st... );
                }
 
-               template< typename Input, typename Node, typename... States >
-               static void success( const Input& in, state< Node >& state, States&&... st )
+               template< typename Input, typename... States >
+               static void success( const Input& in, States&&... st )
                {
-                  C< Rule >::success( in, st... );
+                  Control< Rule >::success( in, st... );
+                  auto& state = *static_cast< internal::state< Node >* >( in.internal_state );
                   auto n = std::move( state.back() );
                   state.pop_back();
                   n->template success< Rule >( in, st... );
-                  transform< Node, S< Rule > >::call( n, st... );
+                  transform< Node, Selector< Rule > >::call( n, st... );
                   if( n ) {
                      state.back()->emplace_back( std::move( n ), st... );
                   }
                }
 
-               template< typename Input, typename Node, typename... States >
-               static void failure( const Input& in, state< Node >& state, States&&... st ) noexcept( noexcept( C< Rule >::failure( in, st... ) ) && noexcept( std::declval< node& >().template failure< Rule >( in, st... ) ) )
+               template< typename Input, typename... States >
+               static void failure( const Input& in, States&&... st ) noexcept( noexcept( Control< Rule >::failure( in, st... ) ) && noexcept( std::declval< node& >().template failure< Rule >( in, st... ) ) )
                {
-                  C< Rule >::failure( in, st... );
+                  Control< Rule >::failure( in, st... );
+                  auto& state = *static_cast< internal::state< Node >* >( in.internal_state );
                   state.back()->template failure< Rule >( in, st... );
                   state.pop_back();
                }
+            };
 
-               template< typename Input, typename Node, typename... States >
-               static void raise( const Input& in, state< Node >& /*unused*/, States&&... st )
-               {
-                  C< Rule >::raise( in, st... );
-               }
-
-               template< template< typename... > class Action, typename Input, typename Node, typename... States >
-               static typename return_type_apply0< C< Rule >, Action, Input, States... >::type apply0( const Input& in, state< Node >& /*unused*/, States&&... st )
-               {
-                  return C< Rule >::template apply0< Action >( in, st... );
-               }
-
-               template< template< typename... > class Action, typename Iterator, typename Input, typename Node, typename... States >
-               static typename return_type_apply< C< Rule >, Action, Iterator, Input, States... >::type apply( const Iterator& begin, const Input& in, state< Node >& /*unused*/, States&&... st )
-               {
-                  return C< Rule >::template apply< Action >( begin, in, st... );
-               }
+            template< typename >
+            struct element
+            {
             };
 
             template< typename >
@@ -313,6 +337,14 @@ namespace tao
 
          }  // namespace internal
 
+         struct store_content : std::true_type
+         {
+            template< typename Node, typename... States >
+            static void transform( std::unique_ptr< Node >& /*unused*/, States&&... /*unused*/ ) noexcept
+            {
+            }
+         };
+
          // some nodes don't need to store their content
          struct remove_content : std::true_type
          {
@@ -323,45 +355,101 @@ namespace tao
             }
          };
 
-         // if a node has only one child, replace the node with its child
-         struct fold_one : std::true_type
+         // if a node has only one child, replace the node with its child, otherwise apply B
+         template< typename Base >
+         struct fold_one_or : Base
          {
             template< typename Node, typename... States >
-            static void transform( std::unique_ptr< Node >& n, States&&... /*unused*/ ) noexcept( noexcept( n->children.size(), n->children.front() ) )
+            static void transform( std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( n->children.size(), Base::transform( n, st... ) ) )
             {
                if( n->children.size() == 1 ) {
                   n = std::move( n->children.front() );
                }
+               else {
+                  Base::transform( n, st... );
+               }
             }
          };
 
-         // if a node has no children, discard the node
-         struct discard_empty : std::true_type
+         // if a node has no children, discard the node, otherwise apply B
+         template< typename Base >
+         struct discard_empty_or : Base
          {
             template< typename Node, typename... States >
-            static void transform( std::unique_ptr< Node >& n, States&&... /*unused*/ ) noexcept( noexcept( n->children.empty() ) )
+            static void transform( std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( n->children.empty(), Base::transform( n, st... ) ) )
             {
                if( n->children.empty() ) {
                   n.reset();
                }
+               else {
+                  Base::transform( n, st... );
+               }
             }
          };
 
-         template< typename Rule, typename Node, template< typename > class S = internal::store_all, template< typename > class C = normal, typename Input, typename... States >
+         using fold_one = fold_one_or< remove_content >;
+         using discard_empty = discard_empty_or< remove_content >;
+
+         template< typename Rule, typename... Collections >
+         struct selector : std::false_type
+         {
+         };
+
+         // TODO: Implement in a non-recursive way
+         // TODO: Check for multiple matches (currently: first match wins)
+         template< typename Rule, typename Collection, typename... Collections >
+         struct selector< Rule, Collection, Collections... >
+            : TAO_PEGTL_NAMESPACE::internal::conditional< Collection::template contains< Rule >::value >::template type< typename Collection::type, selector< Rule, Collections... > >
+         {
+         };
+
+         template< typename Base >
+         struct apply
+         {
+            template< typename... Rules >
+            struct to
+               : internal::element< Rules >...
+            {
+               using type = Base;
+
+               template< typename Rule >
+               using contains = std::is_base_of< internal::element< Rule >, to >;
+            };
+         };
+
+         using apply_store_content = apply< store_content >;
+         using apply_remove_content = apply< remove_content >;
+         using apply_fold_one = apply< fold_one >;
+         using apply_discard_empty = apply< discard_empty >;
+
+         template< typename Rule,
+                   typename Node,
+                   template< typename... > class Selector = internal::store_all,
+                   template< typename... > class Action = nothing,
+                   template< typename... > class Control = normal,
+                   typename Input,
+                   typename... States >
          std::unique_ptr< Node > parse( Input&& in, States&&... st )
          {
             internal::state< Node > state;
-            if( !TAO_PEGTL_NAMESPACE::parse< Rule, nothing, internal::make_control< S, C >::template type >( in, state, st... ) ) {
+            assert( in.internal_state == nullptr );
+            in.internal_state = &state;
+            if( !TAO_PEGTL_NAMESPACE::parse< Rule, Action, internal::make_control< Node, Selector, Control >::template type >( in, st... ) ) {
                return nullptr;
             }
             assert( state.stack.size() == 1 );
             return std::move( state.back() );
          }
 
-         template< typename Rule, template< typename > class S = internal::store_all, template< typename > class C = normal, typename Input, typename... States >
+         template< typename Rule,
+                   template< typename... > class Selector = internal::store_all,
+                   template< typename... > class Action = nothing,
+                   template< typename... > class Control = normal,
+                   typename Input,
+                   typename... States >
          std::unique_ptr< node > parse( Input&& in, States&&... st )
          {
-            return parse< Rule, node, S, C >( in, st... );
+            return parse< Rule, node, Selector, Action, Control >( in, st... );
          }
 
       }  // namespace parse_tree
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp b/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp
index 9de8867a369854ad053e76f34ecde1695008a879..9936b81178bcd25a48e0f201baee53211216709d 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp
@@ -69,7 +69,7 @@ namespace tao
          template< char Marker, char Close >
          struct at_raw_string_close
          {
-            using analyze_t = analysis::generic< analysis::rule_type::ANY >;
+            using analyze_t = analysis::generic< analysis::rule_type::OPT >;
 
             template< apply_mode A,
                       rewind_mode,
@@ -189,8 +189,6 @@ namespace tao
       template< char Open, char Marker, char Close, typename... Contents >
       struct raw_string
       {
-         using analyze_t = analysis::generic< analysis::rule_type::ANY >;
-
          // This is used for binding the apply()-method and for error-reporting
          // when a raw string is not closed properly or has invalid content.
          struct content
@@ -198,6 +196,8 @@ namespace tao
          {
          };
 
+         using analyze_t = typename internal::seq< internal::bytes< 1 >, content, internal::bytes< 1 > >::analyze_t;
+
          template< apply_mode A,
                    rewind_mode M,
                    template< typename... > class Action,
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/unescape.hpp b/packages/PEGTL/include/tao/pegtl/contrib/unescape.hpp
index 1c52e3951da24daa5e249d6a49fc8b964bfb2e75..704ede62ab8f7e7a9b4f368419b4dc1418418745 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/unescape.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/unescape.hpp
@@ -122,24 +122,26 @@ namespace tao
             static void apply( const Input& in, State& st )
             {
                assert( in.size() == 1 );
-               st.unescaped += apply_one( *in.begin(), static_cast< const T* >( nullptr ) );
+               st.unescaped += apply_one( in, static_cast< const T* >( nullptr ) );
             }
 
-            template< char... Qs >
-            static char apply_one( const char c, const one< Qs... >* /*unused*/ )
+            template< typename Input, char... Qs >
+            static char apply_one( const Input& in, const one< Qs... >* /*unused*/ )
             {
                static_assert( sizeof...( Qs ) == sizeof...( Rs ), "size mismatch between escaped characters and their mappings" );
-               return apply_two( c, { Qs... }, { Rs... } );
+               return apply_two( in, { Qs... }, { Rs... } );
             }
 
-            static char apply_two( const char c, const std::initializer_list< char >& q, const std::initializer_list< char >& r )
+            template< typename Input >
+            static char apply_two( const Input& in, const std::initializer_list< char >& q, const std::initializer_list< char >& r )
             {
+               const char c = *in.begin();
                for( std::size_t i = 0; i < q.size(); ++i ) {
                   if( *( q.begin() + i ) == c ) {
                      return *( r.begin() + i );
                   }
                }
-               throw std::runtime_error( "invalid character in unescape" );  // NOLINT, LCOV_EXCL_LINE
+               throw parse_error( "invalid character in unescape", in );  // NOLINT, LCOV_EXCL_LINE
             }
          };
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/conditional.hpp b/packages/PEGTL/include/tao/pegtl/internal/conditional.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..dbf356da1c061a057de4c8991d344ceb48d89f98
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/internal/conditional.hpp
@@ -0,0 +1,38 @@
+// Copyright (c) 2018 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_INTERNAL_CONDITIONAL_HPP
+#define TAO_PEGTL_INTERNAL_CONDITIONAL_HPP
+
+#include "../config.hpp"
+
+namespace tao
+{
+   namespace TAO_PEGTL_NAMESPACE
+   {
+      namespace internal
+      {
+         template< bool >
+         struct conditional;
+
+         template<>
+         struct conditional< true >
+         {
+            template< typename T, typename >
+            using type = T;
+         };
+
+         template<>
+         struct conditional< false >
+         {
+            template< typename, typename T >
+            using type = T;
+         };
+
+      }  // namespace internal
+
+   }  // namespace TAO_PEGTL_NAMESPACE
+
+}  // namespace tao
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/file_mapper_win32.hpp b/packages/PEGTL/include/tao/pegtl/internal/file_mapper_win32.hpp
index 6e87dd536b67d33dc936f8f3140200ea323c572a..0f4d8f2b6c0586227da0aa95b39495bb0fd88074 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/file_mapper_win32.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/file_mapper_win32.hpp
@@ -14,7 +14,7 @@
 #define TAO_PEGTL_WIN32_MEAN_AND_LEAN_WAS_DEFINED
 #endif
 
-#include <Windows.h>
+#include <windows.h>
 
 #if defined( TAO_PEGTL_NOMINMAX_WAS_DEFINED )
 #undef NOMINMAX
diff --git a/packages/PEGTL/include/tao/pegtl/memory_input.hpp b/packages/PEGTL/include/tao/pegtl/memory_input.hpp
index eb03184a3a090cd2b49bb2b041df7e3f24681510..021b21142fe42bd955b36577df8e8068ab47dbaa 100644
--- a/packages/PEGTL/include/tao/pegtl/memory_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/memory_input.hpp
@@ -350,6 +350,8 @@ namespace tao
          {
             return std::string( begin_of_line( p ), end_of_line( p ) );
          }
+
+         void* internal_state = nullptr;
       };
 
 #ifdef __cpp_deduction_guides
diff --git a/packages/PEGTL/include/tao/pegtl/parse.hpp b/packages/PEGTL/include/tao/pegtl/parse.hpp
index 4a1fc8d15e1c9908e6cfdabaf535e6fff03cf9f2..1f3254964e9452dce820435d9232ca0ec1d85eb9 100644
--- a/packages/PEGTL/include/tao/pegtl/parse.hpp
+++ b/packages/PEGTL/include/tao/pegtl/parse.hpp
@@ -4,6 +4,8 @@
 #ifndef TAO_PEGTL_PARSE_HPP
 #define TAO_PEGTL_PARSE_HPP
 
+#include <cassert>
+
 #include "apply_mode.hpp"
 #include "config.hpp"
 #include "normal.hpp"
@@ -11,10 +13,38 @@
 #include "parse_error.hpp"
 #include "rewind_mode.hpp"
 
+#include "internal/action_input.hpp"
+
 namespace tao
 {
    namespace TAO_PEGTL_NAMESPACE
    {
+      namespace internal
+      {
+         template< typename From >
+         struct copy_internals
+         {
+            template< typename To >
+            static void apply( const From& from, To& to ) noexcept
+            {
+               assert( to.internal_state == nullptr );
+               to.internal_state = from.internal_state;
+            }
+         };
+
+         template< typename Input >
+         struct copy_internals< action_input< Input > >
+         {
+            template< typename To >
+            static void apply( const action_input< Input >& from, To& to ) noexcept
+            {
+               assert( to.internal_state == nullptr );
+               to.internal_state = from.input().internal_state;
+            }
+         };
+
+      }  // namespace internal
+
       template< typename Rule,
                 template< typename... > class Action = nothing,
                 template< typename... > class Control = normal,
@@ -38,6 +68,7 @@ namespace tao
       bool parse_nested( const Outer& oi, Input&& in, States&&... st )
       {
          try {
+            internal::copy_internals< Outer >::apply( oi, in );
             return parse< Rule, Action, Control, A, M >( in, st... );
          }
          catch( parse_error& e ) {
diff --git a/packages/PEGTL/include/tao/pegtl/version.hpp b/packages/PEGTL/include/tao/pegtl/version.hpp
index 6db79796d0f92e81457c4105caae7198d2a03856..491c38b7fe02fdda6256539aa295b36fac5d56c0 100644
--- a/packages/PEGTL/include/tao/pegtl/version.hpp
+++ b/packages/PEGTL/include/tao/pegtl/version.hpp
@@ -4,11 +4,11 @@
 #ifndef TAO_PEGTL_VERSION_HPP
 #define TAO_PEGTL_VERSION_HPP
 
-#define TAO_PEGTL_VERSION "2.7.0"
+#define TAO_PEGTL_VERSION "2.7.1"
 
 #define TAO_PEGTL_VERSION_MAJOR 2
 #define TAO_PEGTL_VERSION_MINOR 7
-#define TAO_PEGTL_VERSION_PATCH 0
+#define TAO_PEGTL_VERSION_PATCH 1
 
 // Compatibility, remove with 3.0
 #define TAOCPP_PEGTL_VERSION TAO_PEGTL_VERSION
diff --git a/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp b/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp
index 8830b54cd3fc7654c58a0fbd160691aadedc6dd8..6251172ae34664f15c327845e3d9b8dce655e187 100644
--- a/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp
+++ b/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp
@@ -4,6 +4,7 @@
 #include <algorithm>
 #include <iostream>
 #include <iterator>
+#include <map>
 #include <set>
 #include <sstream>
 #include <string>
@@ -33,35 +34,98 @@ namespace tao
    {
       namespace abnf
       {
+         using node_ptr = std::unique_ptr< parse_tree::node >;
+
          namespace
          {
             std::string prefix = "tao::pegtl::";  // NOLINT
 
-            // clang-format off
             std::set< std::string > keywords = {  // NOLINT
-               "alignas", "alignof", "and", "and_eq",
-               "asm", "auto", "bitand", "bitor",
-               "bool", "break", "case", "catch",
-               "char", "char16_t", "char32_t", "class",
-               "compl", "const", "constexpr", "const_cast",
-               "continue", "decltype", "default", "delete",
-               "do", "double", "dynamic_cast", "else",
-               "enum", "explicit", "export", "extern",
-               "false", "float", "for", "friend",
-               "goto", "if", "inline", "int",
-               "long", "mutable", "namespace", "new",
-               "noexcept", "not", "not_eq", "nullptr",
-               "operator", "or", "or_eq", "private",
-               "protected", "public", "register", "reinterpret_cast",
-               "return", "short", "signed", "sizeof",
-               "static", "static_assert", "static_cast", "struct",
-               "switch", "template", "this", "thread_local",
-               "throw", "true", "try", "typedef",
-               "typeid", "typename", "union", "unsigned",
-               "using", "virtual", "void", "volatile",
-               "wchar_t", "while", "xor", "xor_eq"
+               "alignas",
+               "alignof",
+               "and",
+               "and_eq",
+               "asm",
+               "auto",
+               "bitand",
+               "bitor",
+               "bool",
+               "break",
+               "case",
+               "catch",
+               "char",
+               "char16_t",
+               "char32_t",
+               "class",
+               "compl",
+               "const",
+               "constexpr",
+               "const_cast",
+               "continue",
+               "decltype",
+               "default",
+               "delete",
+               "do",
+               "double",
+               "dynamic_cast",
+               "else",
+               "enum",
+               "explicit",
+               "export",
+               "extern",
+               "false",
+               "float",
+               "for",
+               "friend",
+               "goto",
+               "if",
+               "inline",
+               "int",
+               "long",
+               "mutable",
+               "namespace",
+               "new",
+               "noexcept",
+               "not",
+               "not_eq",
+               "nullptr",
+               "operator",
+               "or",
+               "or_eq",
+               "private",
+               "protected",
+               "public",
+               "register",
+               "reinterpret_cast",
+               "return",
+               "short",
+               "signed",
+               "sizeof",
+               "static",
+               "static_assert",
+               "static_cast",
+               "struct",
+               "switch",
+               "template",
+               "this",
+               "thread_local",
+               "throw",
+               "true",
+               "try",
+               "typedef",
+               "typeid",
+               "typename",
+               "union",
+               "unsigned",
+               "using",
+               "virtual",
+               "void",
+               "volatile",
+               "wchar_t",
+               "while",
+               "xor",
+               "xor_eq"
             };
-            // clang-format on
 
             using rules_t = std::vector< std::string >;
             rules_t rules_defined;  // NOLINT
@@ -238,22 +302,45 @@ namespace tao
             template<> const std::string error_control< defined_as >::error_message = "expected '=' or '=/'";  // NOLINT
             template<> const std::string error_control< c_nl >::error_message = "unterminated rule";  // NOLINT
             template<> const std::string error_control< rule >::error_message = "expected rule";  // NOLINT
+            // clang-format on
 
          }  // namespace grammar
 
-         struct node
-            : tao::TAO_PEGTL_NAMESPACE::parse_tree::basic_node< node >
+         template< typename Rule >
+         struct selector
+            : parse_tree::selector<
+                 Rule,
+                 parse_tree::apply_store_content::to<
+                    grammar::rulename,
+                    grammar::prose_val,
+                    grammar::hex_val::value,
+                    grammar::dec_val::value,
+                    grammar::bin_val::value,
+                    grammar::hex_val::range,
+                    grammar::dec_val::range,
+                    grammar::bin_val::range,
+                    grammar::hex_val::type,
+                    grammar::dec_val::type,
+                    grammar::bin_val::type,
+                    grammar::repeat,
+                    grammar::defined_as_op >,
+                 parse_tree::apply_remove_content::to<
+                    grammar::option,
+                    grammar::and_predicate,
+                    grammar::not_predicate,
+                    grammar::rule >,
+                 parse_tree::apply_fold_one::to<
+                    grammar::alternation,
+                    grammar::group,
+                    grammar::repetition,
+                    grammar::concatenation > >
          {
-            template< typename... States >
-            void emplace_back( std::unique_ptr< node > child, States&&... st );
          };
 
-         template< typename Rule > struct selector : std::false_type {};
-         template<> struct selector< grammar::rulename > : std::true_type {};
-
-         template<> struct selector< grammar::quoted_string > : std::true_type
+         template<>
+         struct selector< grammar::quoted_string > : std::true_type
          {
-            static void transform( std::unique_ptr< node >& n )
+            static void transform( node_ptr& n )
             {
                shift( n->m_begin, 1 );
                shift( n->m_end, -1 );
@@ -274,9 +361,10 @@ namespace tao
             }
          };
 
-         template<> struct selector< grammar::case_sensitive_string > : std::true_type
+         template<>
+         struct selector< grammar::case_sensitive_string > : std::true_type
          {
-            static void transform( std::unique_ptr< node >& n )
+            static void transform( node_ptr& n )
             {
                n = std::move( n->children.back() );
                if( n->content().size() == 1 ) {
@@ -288,34 +376,20 @@ namespace tao
             }
          };
 
-         template<> struct selector< grammar::prose_val > : std::true_type {};
-         template<> struct selector< grammar::hex_val::value > : std::true_type {};
-         template<> struct selector< grammar::dec_val::value > : std::true_type {};
-         template<> struct selector< grammar::bin_val::value > : std::true_type {};
-         template<> struct selector< grammar::hex_val::range > : std::true_type {};
-         template<> struct selector< grammar::dec_val::range > : std::true_type {};
-         template<> struct selector< grammar::bin_val::range > : std::true_type {};
-         template<> struct selector< grammar::hex_val::type > : std::true_type {};
-         template<> struct selector< grammar::dec_val::type > : std::true_type {};
-         template<> struct selector< grammar::bin_val::type > : std::true_type {};
-         template<> struct selector< grammar::alternation > : parse_tree::fold_one {};
-         template<> struct selector< grammar::option > : std::true_type {};
-         template<> struct selector< grammar::group > : parse_tree::fold_one {};
-         template<> struct selector< grammar::repeat > : std::true_type {};
-         template<> struct selector< grammar::repetition > : parse_tree::fold_one {};
-         template<> struct selector< grammar::and_predicate > : std::true_type {};
-         template<> struct selector< grammar::not_predicate > : std::true_type {};
-         template<> struct selector< grammar::concatenation > : parse_tree::fold_one {};
-         template<> struct selector< grammar::defined_as_op > : std::true_type {};
-         template<> struct selector< grammar::rule > : std::true_type {};
-         // clang-format on
-
-         std::string to_string( const std::unique_ptr< node >& n );
-         std::string to_string( const std::vector< std::unique_ptr< node > >& v );
+         std::string to_string( const node_ptr& n );
+         std::string to_string( const std::vector< node_ptr >& v );
+
+         std::string to_string_unwrap_seq( const node_ptr& n )
+         {
+            if( n->is< grammar::group >() || n->is< grammar::concatenation >() ) {
+               return to_string( n->children );
+            }
+            return to_string( n );
+         }
 
          namespace
          {
-            std::string get_rulename( const std::unique_ptr< node >& n )
+            std::string get_rulename( const node_ptr& n )
             {
                assert( n->is< grammar::rulename >() );
                std::string v = n->content();
@@ -323,7 +397,7 @@ namespace tao
                return v;
             }
 
-            std::string get_rulename( const std::unique_ptr< node >& n, const bool print_forward_declarations )
+            std::string get_rulename( const node_ptr& n, const bool print_forward_declarations )
             {
                std::string v = get_rulename( n );
                const auto it = find_rule( rules, v );
@@ -331,7 +405,7 @@ namespace tao
                   return *it;
                }
                if( keywords.count( v ) != 0 || v.find( "__" ) != std::string::npos ) {
-                  throw std::runtime_error( to_string( n->begin() ) + ": '" + v + "' is a reserved rulename" );  // NOLINT
+                  throw parse_error( '\'' + n->content() + "' is a reserved rulename", n->begin() );  // NOLINT
                }
                if( print_forward_declarations && find_rule( rules_defined, v ) != rules_defined.rend() ) {
                   std::cout << "struct " << v << ";\n";
@@ -341,7 +415,7 @@ namespace tao
             }
 
             template< typename T >
-            std::string gen_val( const std::unique_ptr< node >& n )
+            std::string gen_val( const node_ptr& n )
             {
                if( n->children.size() == 2 ) {
                   if( n->children.back()->is< T >() ) {
@@ -354,87 +428,78 @@ namespace tao
                return prefix + "string< " + to_string( n->children ) + " >";
             }
 
+            struct ccmp
+            {
+               bool operator()( const std::string& lhs, const std::string& rhs ) const noexcept
+               {
+                  return TAO_PEGTL_STRCASECMP( lhs.c_str(), rhs.c_str() ) < 0;
+               }
+            };
+
+            std::map< std::string, parse_tree::node*, ccmp > previous_rules;  // NOLINT
+
          }  // namespace
 
-         template< typename... States >
-         void node::emplace_back( std::unique_ptr< node > child, States&&... st )
+         template<>
+         struct selector< grammar::rule > : std::true_type
          {
-            // inserting a rule is handled here since we need access to all previously inserted rules
-            if( child->is< grammar::rule >() ) {
-               const auto rname = get_rulename( child->children.front() );
-               assert( child->children.at( 1 )->is< grammar::defined_as_op >() );
-               const auto op = child->children.at( 1 )->content();
+            static void transform( node_ptr& n )
+            {
+               const auto rname = get_rulename( n->children.front() );
+               assert( n->children.at( 1 )->is< grammar::defined_as_op >() );
+               const auto op = n->children.at( 1 )->content();
                // when we insert a normal rule, we need to check for duplicates
                if( op == "=" ) {
-                  for( const auto& n : children ) {
-                     if( TAO_PEGTL_STRCASECMP( rname.c_str(), abnf::get_rulename( n->children.front() ).c_str() ) == 0 ) {
-                        throw std::runtime_error( to_string( child->begin() ) + ": rule '" + rname + "' is already defined" );  // NOLINT
-                     }
+                  if( !previous_rules.insert( { rname, n.get() } ).second ) {
+                     throw parse_error( "rule '" + rname + "' is already defined", n->begin() );  // NOLINT
                   }
                }
                // if it is an "incremental alternation", we need to consolidate the assigned alternations
                else if( op == "=/" ) {
-                  std::size_t i = 0;
-                  while( i < children.size() ) {
-                     if( TAO_PEGTL_STRCASECMP( rname.c_str(), abnf::get_rulename( children.at( i )->children.front() ).c_str() ) == 0 ) {
-                        auto& previous = children.at( i )->children.back();
-
-                        // if the previous rule does not assign an alternation, create an intermediate alternation and move its assignee into it.
-                        if( !previous->is< abnf::grammar::alternation >() ) {
-                           std::unique_ptr< node > s( new node );
-                           s->id = &typeid( abnf::grammar::alternation );
-                           s->source = previous->source;
-                           s->m_begin = previous->m_begin;
-                           s->m_end = previous->m_end;
-                           s->children.emplace_back( std::move( previous ) );
-                           previous = std::move( s );
-                        }
-
-                        // append all new options to the previous rule's assignee (which now always an alternation)
-                        previous->m_end = child->children.back()->m_end;
-
-                        // if the new rule itself contains an alternation, append the individual entries...
-                        if( child->children.back()->is< abnf::grammar::alternation >() ) {
-                           for( auto& n : child->children.back()->children ) {
-                              previous->children.emplace_back( std::move( n ) );
-                           }
-                        }
-                        // ...otherwise add the node itself as another option.
-                        else {
-                           previous->children.emplace_back( std::move( child->children.back() ) );
-                        }
-
-                        // finally, move the previous rule to the current position...
-                        child = std::move( children.at( i ) );
-
-                        // ...and remove the previous rule from the list.
-                        children.erase( children.begin() + i );
-
-                        // all OK now
-                        break;
+                  const auto p = previous_rules.find( rname );
+                  if( p == previous_rules.end() ) {
+                     throw parse_error( "incremental alternation '" + rname + "' without previous rule definition", n->begin() );  // NOLINT
+                  }
+                  auto& previous = p->second->children.back();
+
+                  // if the previous rule does not assign an alternation, create an intermediate alternation and move its assignee into it.
+                  if( !previous->is< abnf::grammar::alternation >() ) {
+                     node_ptr s( new parse_tree::node );
+                     s->id = &typeid( abnf::grammar::alternation );
+                     s->source = previous->source;
+                     s->m_begin = previous->m_begin;
+                     s->m_end = previous->m_end;
+                     s->children.emplace_back( std::move( previous ) );
+                     previous = std::move( s );
+                  }
+
+                  // append all new options to the previous rule's assignee (which always is an alternation now)
+                  previous->m_end = n->children.back()->m_end;
+
+                  // if the new rule itself contains an alternation, append the individual entries...
+                  if( n->children.back()->is< abnf::grammar::alternation >() ) {
+                     for( auto& e : n->children.back()->children ) {
+                        previous->children.emplace_back( std::move( e ) );
                      }
-                     ++i;
                   }
-                  if( i == children.size() ) {
-                     throw std::runtime_error( to_string( child->begin() ) + ": incremental alternation '" + rname + "' without previous rule definition" );  // NOLINT
+                  // ...otherwise add the node itself as another option.
+                  else {
+                     previous->children.emplace_back( std::move( n->children.back() ) );
                   }
+                  n.reset();
                }
                else {
-                  throw std::runtime_error( to_string( child->begin() ) + ": invalid operator '" + op + "', this should not happen!" );  // NOLINT
+                  throw parse_error( "invalid operator '" + op + "', this should not happen!", n->begin() );  // NOLINT
                }
             }
-
-            // perform the normal emplace_back operation by forwarding to the original method
-            tao::TAO_PEGTL_NAMESPACE::parse_tree::basic_node< node >::emplace_back( std::move( child ), st... );
-         }
+         };
 
          struct stringifier
          {
-            using function_t = std::string ( * )( const std::unique_ptr< node >& n );
+            using function_t = std::string ( * )( const node_ptr& n );
             function_t default_ = nullptr;
 
-            using map_t = std::map< const std::type_info*, function_t >;
-            map_t map_;
+            std::map< const std::type_info*, function_t > map_;
 
             template< typename T >
             void add( const function_t& f )
@@ -442,7 +507,7 @@ namespace tao
                map_.insert( { &typeid( T ), f } );
             }
 
-            std::string operator()( const std::unique_ptr< node >& n ) const
+            std::string operator()( const node_ptr& n ) const
             {
                const auto it = map_.find( n->id );
                if( it != map_.end() ) {
@@ -455,17 +520,17 @@ namespace tao
          stringifier make_stringifier()
          {
             stringifier nrv;
-            nrv.default_ = []( const std::unique_ptr< node >& n ) -> std::string {
-               throw std::runtime_error( to_string( n->begin() ) + ": missing to_string() for " + n->name() );  // NOLINT
+            nrv.default_ = []( const node_ptr& n ) -> std::string {
+               throw parse_error( "missing to_string() for " + n->name(), n->begin() );  // NOLINT
             };
 
-            nrv.add< grammar::rulename >( []( const std::unique_ptr< node >& n ) { return get_rulename( n, true ); } );
+            nrv.add< grammar::rulename >( []( const node_ptr& n ) { return get_rulename( n, true ); } );
 
-            nrv.add< grammar::rule >( []( const std::unique_ptr< node >& n ) {
+            nrv.add< grammar::rule >( []( const node_ptr& n ) {
                return "struct " + get_rulename( n->children.front(), false ) + " : " + to_string( n->children.back() ) + " {};";
             } );
 
-            nrv.add< string_tag >( []( const std::unique_ptr< node >& n ) {
+            nrv.add< string_tag >( []( const node_ptr& n ) {
                const std::string content = n->content();
                std::string s;
                for( const auto c : content ) {
@@ -474,7 +539,7 @@ namespace tao
                return prefix + "string< " + s + " >";
             } );
 
-            nrv.add< istring_tag >( []( const std::unique_ptr< node >& n ) {
+            nrv.add< istring_tag >( []( const node_ptr& n ) {
                const std::string content = n->content();
                std::string s;
                for( const auto c : content ) {
@@ -483,7 +548,7 @@ namespace tao
                return prefix + "istring< " + s + " >";
             } );
 
-            nrv.add< one_tag >( []( const std::unique_ptr< node >& n ) {
+            nrv.add< one_tag >( []( const node_ptr& n ) {
                const std::string content = n->content();
                std::string s;
                for( const auto c : content ) {
@@ -492,9 +557,9 @@ namespace tao
                return prefix + "one< " + s + " >";
             } );
 
-            nrv.add< grammar::hex_val::value >( []( const std::unique_ptr< node >& n ) { return "0x" + n->content(); } );
-            nrv.add< grammar::dec_val::value >( []( const std::unique_ptr< node >& n ) { return n->content(); } );
-            nrv.add< grammar::bin_val::value >( []( const std::unique_ptr< node >& n ) {
+            nrv.add< grammar::hex_val::value >( []( const node_ptr& n ) { return "0x" + n->content(); } );
+            nrv.add< grammar::dec_val::value >( []( const node_ptr& n ) { return n->content(); } );
+            nrv.add< grammar::bin_val::value >( []( const node_ptr& n ) {
                unsigned long long v = 0;
                const char* p = n->m_begin.data;
                // TODO: Detect overflow
@@ -507,47 +572,47 @@ namespace tao
                return o.str();
             } );
 
-            nrv.add< grammar::hex_val::type >( []( const std::unique_ptr< node >& n ) { return gen_val< grammar::hex_val::range >( n ); } );
-            nrv.add< grammar::dec_val::type >( []( const std::unique_ptr< node >& n ) { return gen_val< grammar::dec_val::range >( n ); } );
-            nrv.add< grammar::bin_val::type >( []( const std::unique_ptr< node >& n ) { return gen_val< grammar::bin_val::range >( n ); } );
+            nrv.add< grammar::hex_val::type >( []( const node_ptr& n ) { return gen_val< grammar::hex_val::range >( n ); } );
+            nrv.add< grammar::dec_val::type >( []( const node_ptr& n ) { return gen_val< grammar::dec_val::range >( n ); } );
+            nrv.add< grammar::bin_val::type >( []( const node_ptr& n ) { return gen_val< grammar::bin_val::range >( n ); } );
 
-            nrv.add< grammar::alternation >( []( const std::unique_ptr< node >& n ) { return prefix + "sor< " + to_string( n->children ) + " >"; } );
-            nrv.add< grammar::option >( []( const std::unique_ptr< node >& n ) { return prefix + "opt< " + to_string( n->children ) + " >"; } );
-            nrv.add< grammar::group >( []( const std::unique_ptr< node >& n ) { return prefix + "seq< " + to_string( n->children ) + " >"; } );
+            nrv.add< grammar::alternation >( []( const node_ptr& n ) { return prefix + "sor< " + to_string( n->children ) + " >"; } );
+            nrv.add< grammar::option >( []( const node_ptr& n ) { return prefix + "opt< " + to_string( n->children ) + " >"; } );
+            nrv.add< grammar::group >( []( const node_ptr& n ) { return prefix + "seq< " + to_string( n->children ) + " >"; } );
 
-            nrv.add< grammar::prose_val >( []( const std::unique_ptr< node >& n ) { return "/* " + n->content() + " */"; } );
+            nrv.add< grammar::prose_val >( []( const node_ptr& n ) { return "/* " + n->content() + " */"; } );
 
-            nrv.add< grammar::and_predicate >( []( const std::unique_ptr< node >& n ) {
+            nrv.add< grammar::and_predicate >( []( const node_ptr& n ) {
                assert( n->children.size() == 1 );
-               return prefix + "at< " + to_string( n->children.front() ) + " >";
+               return prefix + "at< " + to_string_unwrap_seq( n->children.front() ) + " >";
             } );
 
-            nrv.add< grammar::not_predicate >( []( const std::unique_ptr< node >& n ) {
+            nrv.add< grammar::not_predicate >( []( const node_ptr& n ) {
                assert( n->children.size() == 1 );
-               return prefix + "not_at< " + to_string( n->children.front() ) + " >";
+               return prefix + "not_at< " + to_string_unwrap_seq( n->children.front() ) + " >";
             } );
 
-            nrv.add< grammar::concatenation >( []( const std::unique_ptr< node >& n ) {
+            nrv.add< grammar::concatenation >( []( const node_ptr& n ) {
                assert( !n->children.empty() );
                return prefix + "seq< " + to_string( n->children ) + " >";
             } );
 
-            nrv.add< grammar::repetition >( []( const std::unique_ptr< node >& n ) -> std::string {
+            nrv.add< grammar::repetition >( []( const node_ptr& n ) -> std::string {
                assert( n->children.size() == 2 );
-               const auto content = to_string( n->children.back() );
+               const auto content = to_string_unwrap_seq( n->children.back() );
                const auto rep = n->children.front()->content();
                const auto star = rep.find( '*' );
                if( star == std::string::npos ) {
                   const auto v = remove_leading_zeroes( rep );
                   if( v.empty() ) {
-                     throw std::runtime_error( to_string( n->begin() ) + ": repetition of zero not allowed" );  // NOLINT
+                     throw parse_error( "repetition of zero not allowed", n->begin() );  // NOLINT
                   }
                   return prefix + "rep< " + v + ", " + content + " >";
                }
                const auto min = remove_leading_zeroes( rep.substr( 0, star ) );
                const auto max = remove_leading_zeroes( rep.substr( star + 1 ) );
                if( ( star != rep.size() - 1 ) && max.empty() ) {
-                  throw std::runtime_error( to_string( n->begin() ) + ": repetition maximum of zero not allowed" );  // NOLINT
+                  throw parse_error( "repetition maximum of zero not allowed", n->begin() );  // NOLINT
                }
                if( min.empty() && max.empty() ) {
                   return prefix + "star< " + content + " >";
@@ -575,7 +640,11 @@ namespace tao
                   s >> max_val;
                }
                if( min_val > max_val ) {
-                  throw std::runtime_error( to_string( n->begin() ) + ": repetition minimum which is greater than the repetition maximum not allowed" );  // NOLINT
+                  throw parse_error( "repetition minimum which is greater than the repetition maximum not allowed", n->begin() );  // NOLINT
+               }
+               if( ( min_val == 1 ) && ( max_val == 1 ) ) {
+                  // note: content can not be used here!
+                  return to_string( n->children.back() );
                }
                const auto min_element = ( min_val == 1 ) ? content : ( prefix + "rep< " + min + ", " + content + " >" );
                if( min_val == max_val ) {
@@ -590,13 +659,13 @@ namespace tao
             return nrv;
          }
 
-         std::string to_string( const std::unique_ptr< node >& n )
+         std::string to_string( const node_ptr& n )
          {
             static stringifier s = make_stringifier();
             return s( n );
          }
 
-         std::string to_string( const std::vector< std::unique_ptr< node > >& v )
+         std::string to_string( const std::vector< node_ptr >& v )
          {
             std::string result;
             for( const auto& c : v ) {
@@ -626,7 +695,7 @@ int main( int argc, char** argv )
 
    file_input<> in( argv[ 1 ] );
    try {
-      const auto root = parse_tree::parse< abnf::grammar::rulelist, abnf::node, abnf::selector, abnf::grammar::error_control >( in );
+      const auto root = parse_tree::parse< abnf::grammar::rulelist, abnf::selector, nothing, abnf::grammar::error_control >( in );
 
       for( const auto& rule : root->children ) {
          abnf::rules_defined.push_back( abnf::get_rulename( rule->children.front() ) );
diff --git a/packages/PEGTL/src/example/pegtl/parse_tree.cpp b/packages/PEGTL/src/example/pegtl/parse_tree.cpp
index c5a10c2cd430e66280cbf9a4d3c14990175d2067..424a3b40e860077ac0ffd81842800b290be8191d 100644
--- a/packages/PEGTL/src/example/pegtl/parse_tree.cpp
+++ b/packages/PEGTL/src/example/pegtl/parse_tree.cpp
@@ -33,24 +33,6 @@ namespace example
    struct expression : list_must< product, sor< plus, minus > > {};
 
    struct grammar : seq< expression, eof > {};
-   // clang-format on
-
-   // select which rules in the grammar will produce parse tree nodes:
-
-   // clang-format off
-
-   // by default, nodes are not generated/stored
-   template< typename > struct store : std::false_type {};
-
-   // select which rules in the grammar will produce parse tree nodes:
-   template<> struct store< integer > : std::true_type {};
-   template<> struct store< variable > : std::true_type {};
-
-   template<> struct store< plus > : parse_tree::remove_content {};
-   template<> struct store< minus > : parse_tree::remove_content {};
-   template<> struct store< multiply > : parse_tree::remove_content {};
-   template<> struct store< divide > : parse_tree::remove_content {};
-   // clang-format on
 
    // after a node is stored successfully, you can add an optional transformer like this:
    struct rearrange : std::true_type
@@ -76,6 +58,7 @@ namespace example
             n = std::move( n->children.back() );
          }
          else {
+            n->remove_content();
             auto& c = n->children;
             auto r = std::move( c.back() );
             c.pop_back();
@@ -89,10 +72,22 @@ namespace example
       }
    };
 
-   // clang-format off
-   template<> struct store< product > : rearrange {};
-   template<> struct store< expression > : rearrange {};
-   // clang-format on
+   // select which rules in the grammar will produce parse tree nodes:
+
+   template< typename Rule >
+   using selector = parse_tree::selector<
+      Rule,
+      parse_tree::apply_store_content::to<
+         integer,
+         variable >,
+      parse_tree::apply_remove_content::to<
+         plus,
+         minus,
+         multiply,
+         divide >,
+      parse_tree::apply< rearrange >::to<
+         product,
+         expression > >;
 
    // debugging/show result:
 
@@ -126,7 +121,7 @@ int main( int argc, char** argv )
    for( int i = 1; i < argc; ++i ) {
       try {
          argv_input<> in( argv, i );
-         if( const auto root = parse_tree::parse< example::grammar, example::store >( in ) ) {
+         if( const auto root = parse_tree::parse< example::grammar, example::selector >( in ) ) {
             example::print_node( *root );
          }
          else {
diff --git a/packages/PEGTL/src/test/pegtl/CMakeLists.txt b/packages/PEGTL/src/test/pegtl/CMakeLists.txt
index 763d1e1365bbda9f1b00d453ce05a394740ed8ad..f2c45acd050c4ba8f04b0a232d18e14a86a38cbf 100644
--- a/packages/PEGTL/src/test/pegtl/CMakeLists.txt
+++ b/packages/PEGTL/src/test/pegtl/CMakeLists.txt
@@ -9,6 +9,7 @@ set (test_sources
   ascii_classes.cpp
   ascii_eol.cpp
   ascii_eolf.cpp
+  ascii_forty_two.cpp
   ascii_identifier.cpp
   ascii_istring.cpp
   ascii_keyword.cpp
@@ -18,7 +19,9 @@ set (test_sources
   ascii_two.cpp
   contrib_alphabet.cpp
   contrib_integer.cpp
+  contrib_if_then.cpp
   contrib_json.cpp
+  contrib_parse_tree.cpp
   contrib_raw_string.cpp
   contrib_rep_one_min_max.cpp
   contrib_to_string.cpp
diff --git a/packages/PEGTL/src/test/pegtl/ascii_forty_two.cpp b/packages/PEGTL/src/test/pegtl/ascii_forty_two.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..258feea7bf9f86516045dde18f929d4e873220ac
--- /dev/null
+++ b/packages/PEGTL/src/test/pegtl/ascii_forty_two.cpp
@@ -0,0 +1,42 @@
+// Copyright (c) 2018 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include "test.hpp"
+#include "verify_analyze.hpp"
+#include "verify_rule.hpp"
+
+namespace tao
+{
+   namespace TAO_PEGTL_NAMESPACE
+   {
+      void unit_test()
+      {
+         verify_analyze< forty_two< 'a' > >( __LINE__, __FILE__, true, false );
+         verify_analyze< forty_two< 'a', 'z' > >( __LINE__, __FILE__, true, false );
+
+         for( std::size_t i = 0; i < 42; ++i ) {
+            verify_rule< forty_two< 'a' > >( __LINE__, __FILE__, std::string( i, 'a' ), result_type::LOCAL_FAILURE );
+         }
+         for( std::size_t i = 42; i < 100; ++i ) {
+            verify_rule< forty_two< 'a' > >( __LINE__, __FILE__, std::string( i, 'a' ), result_type::SUCCESS, i - 42 );
+         }
+         for( std::size_t i = 0; i < 42; ++i ) {
+            verify_rule< forty_two< 'a', 'z' > >( __LINE__, __FILE__, std::string( i, 'a' ), result_type::LOCAL_FAILURE );
+         }
+         for( std::size_t i = 42; i < 100; ++i ) {
+            verify_rule< forty_two< 'a', 'z' > >( __LINE__, __FILE__, std::string( i, 'a' ), result_type::SUCCESS, i - 42 );
+         }
+         for( std::size_t i = 0; i < 42; ++i ) {
+            verify_rule< forty_two< 'a', 'z' > >( __LINE__, __FILE__, std::string( i, 'z' ), result_type::LOCAL_FAILURE );
+         }
+         for( std::size_t i = 42; i < 100; ++i ) {
+            verify_rule< forty_two< 'a', 'z' > >( __LINE__, __FILE__, std::string( i, 'z' ), result_type::SUCCESS, i - 42 );
+         }
+         verify_rule< forty_two< 'a', 'z' > >( __LINE__, __FILE__, "azzaazaazaaazzzaaaazzaaazzaazazzzaazzazaza", result_type::SUCCESS );
+      }
+
+   }  // namespace TAO_PEGTL_NAMESPACE
+
+}  // namespace tao
+
+#include "main.hpp"
diff --git a/packages/PEGTL/src/test/pegtl/contrib_if_then.cpp b/packages/PEGTL/src/test/pegtl/contrib_if_then.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8af618797c59c938b7b79fdeb40bffaa4aa5aa98
--- /dev/null
+++ b/packages/PEGTL/src/test/pegtl/contrib_if_then.cpp
@@ -0,0 +1,31 @@
+// Copyright (c) 2018 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include "test.hpp"
+#include "verify_rule.hpp"
+
+#include <tao/pegtl/contrib/if_then.hpp>
+
+namespace tao
+{
+   namespace TAO_PEGTL_NAMESPACE
+   {
+      void unit_test()
+      {
+         // clang-format off
+         using grammar =
+            if_then< one< 'a' >, one< 'b' >, one< 'c' > >::
+            else_if_then< one< 'a' >, one< 'b' > >::
+            else_then< one< 'c' > >;
+
+         verify_rule< grammar >( __LINE__, __FILE__, "abc", result_type::SUCCESS, 0 );
+         verify_rule< grammar >( __LINE__, __FILE__, "abcd", result_type::SUCCESS, 1 );
+         verify_rule< grammar >( __LINE__, __FILE__, "ab", result_type::LOCAL_FAILURE, 2 );
+         verify_rule< grammar >( __LINE__, __FILE__, "c", result_type::SUCCESS, 0 );
+      }
+
+   }  // namespace TAO_PEGTL_NAMESPACE
+
+}  // namespace tao
+
+#include "main.hpp"
diff --git a/packages/PEGTL/src/test/pegtl/contrib_parse_tree.cpp b/packages/PEGTL/src/test/pegtl/contrib_parse_tree.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..984f4506cb9f00edc219a28a67a384a211dcc112
--- /dev/null
+++ b/packages/PEGTL/src/test/pegtl/contrib_parse_tree.cpp
@@ -0,0 +1,60 @@
+// Copyright (c) 2018 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include "test.hpp"
+
+#include <tao/pegtl/contrib/parse_tree.hpp>
+
+namespace tao
+{
+   namespace TAO_PEGTL_NAMESPACE
+   {
+      // clang-format off
+      struct A : one< 'a' > {};
+      struct B : one< 'b' > {};
+      struct C : one< 'c' > {};
+
+      struct D : sor< seq< A, B >, seq< A, C > > {};
+      // clang-format on
+
+      template< typename Rule >
+      struct selector
+         : parse_tree::selector< Rule, parse_tree::apply_store_content::to< A, B, C, D > >
+      {
+      };
+
+      void unit_test()
+      {
+         memory_input<> in( "ac", "input" );
+         const auto r = parse_tree::parse< D, selector >( in );
+         TAO_PEGTL_TEST_ASSERT( r->is_root() );
+         TAO_PEGTL_TEST_ASSERT( !r->has_content() );
+         TAO_PEGTL_TEST_ASSERT( r->children.size() == 1 );
+
+         const auto& d = r->children.front();
+         TAO_PEGTL_TEST_ASSERT( !d->is_root() );
+         TAO_PEGTL_TEST_ASSERT( d->id == &typeid( D ) );
+         TAO_PEGTL_TEST_ASSERT( d->is< D >() );
+#if !defined( _MSC_VER )
+         TAO_PEGTL_TEST_ASSERT( d->name() == "tao::pegtl::D" );
+#endif
+
+         TAO_PEGTL_TEST_ASSERT( d->has_content() );
+         TAO_PEGTL_TEST_ASSERT( d->begin().byte == 0 );
+         TAO_PEGTL_TEST_ASSERT( d->end().byte == 2 );
+         TAO_PEGTL_TEST_ASSERT( d->content() == "ac" );
+
+         TAO_PEGTL_TEST_ASSERT( d->children.size() == 2 );
+         TAO_PEGTL_TEST_ASSERT( d->children.front()->is< A >() );
+         TAO_PEGTL_TEST_ASSERT( d->children.back()->is< C >() );
+
+         memory_input<> in2( "x", "input" );
+         const auto r2 = parse_tree::parse< D, selector >( in2 );
+         TAO_PEGTL_TEST_ASSERT( !r2 );
+      }
+
+   }  // namespace TAO_PEGTL_NAMESPACE
+
+}  // namespace tao
+
+#include "main.hpp"