diff --git a/doc/tables.qbk b/doc/tables.qbk index c5e27f41..a3bea4ea 100644 --- a/doc/tables.qbk +++ b/doc/tables.qbk @@ -330,7 +330,7 @@ the input they match unless otherwise stated in the table below.] [[ _symbols_t_ ] [ _symbols_ is an associative container of key, value pairs. Each key is a _std_str_ and each value has type `T`. In the Unicode parsing path, the strings are considered to be UTF-8 encoded; in the non-Unicode path, no encoding is assumed. _symbols_ matches the longest prefix `pre` of the input that is equal to one of the keys `k`. If the length `len` of `pre` is zero, and there is no zero-length key, it does not match the input. If `len` is positive, the generated attribute is the value associated with `k`.] [ `T` ] - [ Unlike the other entries in this table, _symbols_ is a type, not an object. ]] + [ Unlike the other entries in this table, _symbols_ is a type, not an object. Inside of skippers, all _symbols_ will appear empty. ]] [[ _quot_str_ ] [ Matches `'"'`, followed by zero or more characters, followed by `'"'`. ] diff --git a/include/boost/parser/parser.hpp b/include/boost/parser/parser.hpp index cf547d86..5c58df3c 100644 --- a/include/boost/parser/parser.hpp +++ b/include/boost/parser/parser.hpp @@ -472,6 +472,37 @@ namespace boost { namespace parser { nope_or_pointer_t where_{}; int no_case_depth_ = 0; + // These exist in order to provide an address, if requested, for + // either kind of symbol table struct. The nonstatic member + // pointers for these will be null if this context was created + // inside of detail::skip(), but nothing prevents the user from + // trying to use a symbol_parser anyway. So, we have these. + static std::optional + empty_symbol_table_tries_; + static std::optional + empty_pending_symbol_table_operations_; + + symbol_table_tries_t & get_symbol_table_tries() const + { + if (symbol_table_tries_) + return *symbol_table_tries_; + if (!empty_symbol_table_tries_) + empty_symbol_table_tries_ = symbol_table_tries_t(); + return *empty_symbol_table_tries_; + } + + pending_symbol_table_operations_t & + get_pending_symbol_table_operations() const + { + if (pending_symbol_table_operations_) + return *pending_symbol_table_operations_; + if (!empty_pending_symbol_table_operations_) { + empty_pending_symbol_table_operations_ = + pending_symbol_table_operations_t(); + } + return *empty_pending_symbol_table_operations_; + } + template static auto nope_or_address(T & x) { @@ -648,6 +679,64 @@ namespace boost { namespace parser { {} }; + template< + bool DoTrace, + bool UseCallbacks, + typename I, + typename S, + typename ErrorHandler, + typename GlobalState, + typename Callbacks, + typename Attr, + typename Val, + typename RuleTag, + typename RuleLocals, + typename RuleParams, + typename Where> + std::optional parse_context< + DoTrace, + UseCallbacks, + I, + S, + ErrorHandler, + GlobalState, + Callbacks, + Attr, + Val, + RuleTag, + RuleLocals, + RuleParams, + Where>::empty_symbol_table_tries_; + + template< + bool DoTrace, + bool UseCallbacks, + typename I, + typename S, + typename ErrorHandler, + typename GlobalState, + typename Callbacks, + typename Attr, + typename Val, + typename RuleTag, + typename RuleLocals, + typename RuleParams, + typename Where> + std::optional parse_context< + DoTrace, + UseCallbacks, + I, + S, + ErrorHandler, + GlobalState, + Callbacks, + Attr, + Val, + RuleTag, + RuleLocals, + RuleParams, + Where>::empty_pending_symbol_table_operations_; + template< bool DoTrace, bool UseCallbacks, @@ -1734,7 +1823,7 @@ namespace boost { namespace parser { using trie_t = text::trie_map, T>; using result_type = std::pair; symbol_table_tries_t & symbol_table_tries = - *context.symbol_table_tries_; + context.get_symbol_table_tries(); auto & [any, has_case_folded] = symbol_table_tries[(void *)&sym_parser.ref()]; @@ -1773,7 +1862,7 @@ namespace boost { namespace parser { Context const & context, symbol_parser const & sym_parser) { void const * ptr = static_cast(&sym_parser); - auto & entry = (*context.pending_symbol_table_operations_)[ptr]; + auto & entry = (context.get_pending_symbol_table_operations())[ptr]; std::vector> * retval = nullptr; if (entry.visit_) { retval = std::any_cast<