2
0
mirror of https://github.com/boostorg/parser.git synced 2026-01-20 04:42:22 +00:00

14 Commits

Author SHA1 Message Date
Zach Laine
f468d529fe Fix stale comment in doc example. 2024-11-29 16:29:20 -06:00
Zach Laine
b5d4339f2c Fix semicolon-delimited bullet list in parsers table. 2024-11-29 16:29:13 -06:00
Zach Laine
6d7fa6f105 Add missing Docbook tag to fix broken reference in docs. 2024-11-29 16:20:14 -06:00
Mohammad Nejati
c975f57908 Add index.html
This redirects links pointing to the root directory to the documentation
page, such as:
https://www.boost.org/doc/libs/develop/libs/parser/
2024-11-27 20:10:11 -06:00
Zach Laine
063291b78c Correct the parser used in the second half of the "Parse Into a Class"
example.

Fixes #206.
2024-11-24 22:55:21 -06:00
Zach Laine
3eb827dcd6 Fix error in seq_parser::append() that causes AllowBacktracking=false to be treated as =true. 2024-11-14 22:49:51 -06:00
Zach Laine
6d796287b6 Disable the tests for in-Boost builds. 2024-11-13 20:54:34 -06:00
Zach Laine
bb0fb885b8 Doc update for previous symbol table changes.
Related to #183.
2024-10-31 23:26:07 -05:00
Zach Laine
94a9daec40 Change the way that the pending operations are applied to symbol table
parsers.  Instead of trying to find all of them at the start of the top-level
parse, they are recorded in the context, and then applied at the end of the
top-level parse.  The previous technique did not work, simplt because the
top-level parse cannot see all the parser involded -- some are behind rule
firewalls, by design.

Related to #183.
Fixes #204.
2024-10-31 23:07:17 -05:00
Zach Laine
4344dd3f47 Remove mooted TODOs. 2024-10-31 23:07:17 -05:00
Vernon Mauery
a7c7470bc1 Remove unused lambda capture
str is unused in the lambda; remove it from the capture

Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
2024-10-27 14:54:56 -05:00
Zach Laine
b273133fd2 Remove Hana dependency note from README. 2024-10-23 19:35:19 -05:00
Zach Laine
3a7ddcf936 Remove doc link from README. 2024-10-23 19:33:07 -05:00
Marshall Clow
d79efb0daa Update README.md 2024-10-23 19:25:31 -05:00
11 changed files with 320 additions and 152 deletions

View File

@@ -22,12 +22,6 @@ target_link_libraries(boost_parser
Boost::type_index
)
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
endif()
else()
cmake_minimum_required(VERSION 3.14...3.20)

View File

@@ -34,12 +34,7 @@ int main()
}
```
This library is header-only, and has a default dependency on Boost.Hana. The
Boost.Hana dependency can be eliminated, and `std::tuple` will be used instead
of `boost::hana::tuple` throughout the library, if you `#define`
`BOOST_PARSER_DISABLE_HANA_TUPLE`. To try out the lib without mseeing with
dependencies, add its `include/` dir as an include path in your build and
define `BOOST_PARSER_DISABLE_HANA_TUPLE` your build.
This library is header-only, and has no Boost dependencies by default.
Features:
@@ -52,9 +47,7 @@ Features:
- Trace support for debugging your parsers.
- Clever hacks to make compile time errors easier to deal with. (These are totally optional.)
This library targets submission to Boost.
Online docs: https://tzlaine.github.io/parser
This library first appeared in Boost 1.87.0
Master status:

View File

@@ -34,9 +34,9 @@ itself be used as a parser; it must be called. In the table below:
* `a` is a semantic action;
* `r` is an object whose type models `parsable_range`; and
* `r` is an object whose type models `parsable_range`;
* `p`, `p1`, `p2`, ... are parsers.
* `p`, `p1`, `p2`, ... are parsers; and
* `escapes` is a _symbols_t_ object, where `T` is `char` or `char32_t`.

View File

@@ -351,7 +351,7 @@ so this directive is only available in C++20 and later.
namespace bp = boost::parser;
auto int_parser = bp::int_ % ','; // ATTR(int_parser) is std::vector<int>
auto sv_parser = bp::string_view[int_parser]; // ATTR(subrange_parser) is a string_view
auto sv_parser = bp::string_view[int_parser]; // ATTR(sv_parser) is a string_view
auto const str = std::string("1, 2, 3, 4, a, b, c");
auto first = str.begin();
@@ -1126,24 +1126,12 @@ the second `'X'` is recognized by the symbol table parser. However:
If we parse again, we find that `"X"` did not stay in the symbol table. The
fact that `symbols` was declared const might have given you a hint that this
would happen. Also, notice that the call to `insert()` in the semantic action
uses the parse context; that's where all the symbol table changes are stored
during the parse.
would happen.
The full program:
[self_filling_symbol_table_example]
[tip _symbols_ also has a call operator that does exactly what
`.insert_for_next_parse()` does. This allows you to chain additions with a
convenient syntax, like this:
```
symbols<int> roman_numerals;
roman_numerals.insert_for_next_parse("I", 1)("V", 5)("X", 10);
```
]
[important _symbols_ stores all its strings in UTF-32 internally. If you do
Unicode or ASCII parsing, this will not matter to you at all. If you do
non-Unicode parsing of a character encoding that is not a subset of Unicode
@@ -1163,6 +1151,11 @@ erase and clear for the current parse, and another that applies only to
subsequent parses. The full set of operations can be found in the _symbols_
API docs.
[mpte There are two versions of each of the _symbols_ `*_for_next_parse()`
functions _emdash_ one that takes a context, and one that does not. The one
with the context is meant to be used within a semantic action. The one
without the context is for use outside of any parse.]
[endsect]
[section The Parsers And Their Uses]

View File

@@ -33,7 +33,7 @@ int main()
std::cout << input << "\n";
//[ parsing_into_a_class_vec_of_strs
constexpr auto uint_string = bp::uint_ >> bp::char_ >> bp::char_;
constexpr auto uint_string = bp::uint_ >> +bp::char_;
std::vector<std::string> vector_from_parse;
if (parse(input, uint_string, bp::ws, vector_from_parse)) {
std::cout << "That yields this vector of strings:\n";

View File

@@ -31,9 +31,11 @@ namespace boost { namespace parser {
std::forward_iterator<T> && code_unit<std::iter_value_t<T>>;
//[ parsable_range_like_concept
//[ parsable_range_concept
template<typename T>
concept parsable_range = std::ranges::forward_range<T> &&
code_unit<std::ranges::range_value_t<T>>;
//]
template<typename T>
concept parsable_pointer = std::is_pointer_v<std::remove_cvref_t<T>> &&
@@ -58,7 +60,8 @@ namespace boost { namespace parser {
std::declval<int &>(),
std::declval<ErrorHandler const &>(),
std::declval<detail::nope &>(),
std::declval<detail::symbol_table_tries_t &>()));
std::declval<detail::symbol_table_tries_t &>(),
std::declval<detail::pending_symbol_table_operations_t &>()));
template<typename T, typename I, typename S, typename GlobalState>
concept error_handler =

View File

@@ -457,6 +457,8 @@ namespace boost { namespace parser {
bool * pass_ = nullptr;
int * trace_indent_ = nullptr;
symbol_table_tries_t * symbol_table_tries_ = nullptr;
pending_symbol_table_operations_t *
pending_symbol_table_operations_ = nullptr;
ErrorHandler const * error_handler_ = nullptr;
nope_or_pointer_t<GlobalState> globals_{};
nope_or_pointer_t<Callbacks, true> callbacks_{};
@@ -494,12 +496,16 @@ namespace boost { namespace parser {
int & indent,
ErrorHandler const & error_handler,
GlobalState & globals,
symbol_table_tries_t & symbol_table_tries) :
symbol_table_tries_t & symbol_table_tries,
pending_symbol_table_operations_t &
pending_symbol_table_operations) :
first_(first),
last_(last),
pass_(std::addressof(success)),
trace_indent_(std::addressof(indent)),
symbol_table_tries_(std::addressof(symbol_table_tries)),
pending_symbol_table_operations_(
std::addressof(pending_symbol_table_operations)),
error_handler_(std::addressof(error_handler)),
globals_(nope_or_address(globals))
{}
@@ -515,12 +521,16 @@ namespace boost { namespace parser {
ErrorHandler const & error_handler,
Callbacks const & callbacks,
GlobalState & globals,
symbol_table_tries_t & symbol_table_tries) :
symbol_table_tries_t & symbol_table_tries,
pending_symbol_table_operations_t &
pending_symbol_table_operations) :
first_(first),
last_(last),
pass_(std::addressof(success)),
trace_indent_(std::addressof(indent)),
symbol_table_tries_(std::addressof(symbol_table_tries)),
pending_symbol_table_operations_(
std::addressof(pending_symbol_table_operations)),
error_handler_(std::addressof(error_handler)),
globals_(nope_or_address(globals)),
callbacks_(std::addressof(callbacks))
@@ -559,6 +569,8 @@ namespace boost { namespace parser {
pass_(other.pass_),
trace_indent_(other.trace_indent_),
symbol_table_tries_(other.symbol_table_tries_),
pending_symbol_table_operations_(
other.pending_symbol_table_operations_),
error_handler_(other.error_handler_),
globals_(other.globals_),
callbacks_(other.callbacks_),
@@ -602,6 +614,8 @@ namespace boost { namespace parser {
pass_(other.pass_),
trace_indent_(other.trace_indent_),
symbol_table_tries_(other.symbol_table_tries_),
pending_symbol_table_operations_(
other.pending_symbol_table_operations_),
error_handler_(other.error_handler_),
globals_(other.globals_),
callbacks_(other.callbacks_),
@@ -734,7 +748,9 @@ namespace boost { namespace parser {
int & indent,
ErrorHandler const & error_handler,
nope & n,
symbol_table_tries_t & symbol_table_tries) noexcept
symbol_table_tries_t & symbol_table_tries,
pending_symbol_table_operations_t &
pending_symbol_table_operations) noexcept
{
return parse_context(
std::bool_constant<DoTrace>{},
@@ -745,7 +761,8 @@ namespace boost { namespace parser {
indent,
error_handler,
n,
symbol_table_tries);
symbol_table_tries,
pending_symbol_table_operations);
}
template<
@@ -762,7 +779,9 @@ namespace boost { namespace parser {
int & indent,
ErrorHandler const & error_handler,
GlobalState & globals,
symbol_table_tries_t & symbol_table_tries) noexcept
symbol_table_tries_t & symbol_table_tries,
pending_symbol_table_operations_t &
pending_symbol_table_operations) noexcept
{
return parse_context(
std::bool_constant<DoTrace>{},
@@ -773,7 +792,8 @@ namespace boost { namespace parser {
indent,
error_handler,
globals,
symbol_table_tries);
symbol_table_tries,
pending_symbol_table_operations);
}
template<
@@ -791,7 +811,9 @@ namespace boost { namespace parser {
ErrorHandler const & error_handler,
Callbacks const & callbacks,
nope & n,
symbol_table_tries_t & symbol_table_tries) noexcept
symbol_table_tries_t & symbol_table_tries,
pending_symbol_table_operations_t &
pending_symbol_table_operations) noexcept
{
return parse_context(
std::bool_constant<DoTrace>{},
@@ -803,7 +825,8 @@ namespace boost { namespace parser {
error_handler,
callbacks,
n,
symbol_table_tries);
symbol_table_tries,
pending_symbol_table_operations);
}
template<
@@ -822,7 +845,9 @@ namespace boost { namespace parser {
ErrorHandler const & error_handler,
Callbacks const & callbacks,
GlobalState & globals,
symbol_table_tries_t & symbol_table_tries) noexcept
symbol_table_tries_t & symbol_table_tries,
pending_symbol_table_operations_t &
pending_symbol_table_operations) noexcept
{
return parse_context(
std::bool_constant<DoTrace>{},
@@ -834,7 +859,8 @@ namespace boost { namespace parser {
error_handler,
callbacks,
globals,
symbol_table_tries);
symbol_table_tries,
pending_symbol_table_operations);
}
@@ -1494,8 +1520,16 @@ namespace boost { namespace parser {
rethrow_error_handler eh;
nope n;
symbol_table_tries_t symbol_table_tries;
pending_symbol_table_operations_t pending_symbol_table_operations;
auto const context = detail::make_context<false, false>(
first, last, success, indent, eh, n, symbol_table_tries);
first,
last,
success,
indent,
eh,
n,
symbol_table_tries,
pending_symbol_table_operations);
while (success) {
skip_(
first,
@@ -1629,7 +1663,7 @@ namespace boost { namespace parser {
initial_elements.begin(),
initial_elements.end(),
str,
[&str](auto const & a, auto b) {
[](auto const & a, auto b) {
return a.first < b;
});
};
@@ -1667,7 +1701,7 @@ namespace boost { namespace parser {
symbol_table_tries_t & symbol_table_tries =
*context.symbol_table_tries_;
auto & [any, has_case_folded, pending_ops] =
auto & [any, has_case_folded] =
symbol_table_tries[(void *)&sym_parser.ref()];
bool const needs_case_folded = context.no_case_depth_;
@@ -1676,12 +1710,6 @@ namespace boost { namespace parser {
any = trie_t{};
has_case_folded = false;
trie_t & trie = *std::any_cast<trie_t>(&any);
if (pending_ops) {
detail::apply_symbol_table_operations(
sym_parser.initial_elements(),
sym_parser.pending_operations());
pending_ops = false;
}
for (auto const & e : sym_parser.initial_elements()) {
trie.insert(e.first | text::as_utf32, e.second);
if (needs_case_folded) {
@@ -1705,6 +1733,30 @@ namespace boost { namespace parser {
}
}
template<typename Context, typename T>
decltype(auto) get_pending_symtab_ops(
Context const & context, symbol_parser<T> const & sym_parser)
{
void const * ptr = static_cast<void const *>(&sym_parser);
auto & entry = (*context.pending_symbol_table_operations_)[ptr];
std::vector<detail::symbol_table_operation<T>> * retval = nullptr;
if (entry.visit_) {
retval = std::any_cast<
std::vector<detail::symbol_table_operation<T>>>(
&entry.ops_);
} else {
entry.ops_ = std::vector<detail::symbol_table_operation<T>>{};
retval = std::any_cast<
std::vector<detail::symbol_table_operation<T>>>(
&entry.ops_);
entry.visit_ = [&sym_parser, ops_ptr = retval] {
detail::apply_symbol_table_operations(
sym_parser.initial_elements_, *ops_ptr);
};
}
return *retval;
}
template<>
struct char_subranges<hex_digit_subranges>
{
@@ -2222,52 +2274,22 @@ namespace boost { namespace parser {
constexpr bool has_parsers_data_member_v =
is_detected_v<has_parsers_data_member_expr, Parser>;
template<typename Context, typename Parser>
void visit_symbol_table_parsers_impl(
Context & context, Parser const & p);
template<typename Context, typename Parser>
void visit_symbol_table_parser(Context & context, Parser const & p)
struct scoped_apply_pending_symbol_table_operations
{
if constexpr (has_parser_data_member_v<Parser>) {
detail::visit_symbol_table_parsers_impl(context, p.parser_);
scoped_apply_pending_symbol_table_operations(
pending_symbol_table_operations_t & pending_ops) :
pending_ops_(pending_ops)
{}
~scoped_apply_pending_symbol_table_operations()
{
for (auto & [_, entry] : pending_ops_) {
entry.visit_();
}
}
}
template<typename Context, typename T>
void visit_symbol_table_parser(
Context & context, symbol_parser<T> const & p)
{
auto & [_, has_case_folded, pending_ops] =
(*context.symbol_table_tries_)[(void *)&p.ref()];
has_case_folded = false;
pending_ops = !p.pending_operations().empty();
}
template<typename Context, typename Parser>
void visit_symbol_table_parsers_impl(
Context & context, Parser const & p)
{
if constexpr (has_parsers_data_member_v<Parser>) {
auto visit = [&context](auto & parser) {
detail::visit_symbol_table_parsers_impl(context, parser);
};
detail::hl::for_each(p.parsers_, visit);
} else {
detail::visit_symbol_table_parser(context, p);
}
}
template<
typename Context,
typename Parser,
typename GlobalState,
typename ErrorHandler>
void visit_symbol_table_parsers(
Context & context,
parser_interface<Parser, GlobalState, ErrorHandler> const & p)
{
detail::visit_symbol_table_parsers_impl(context, p.parser_);
}
pending_symbol_table_operations_t & pending_ops_;
};
template<
bool Debug,
@@ -2287,6 +2309,9 @@ namespace boost { namespace parser {
bool success = true;
int trace_indent = 0;
detail::symbol_table_tries_t symbol_table_tries;
pending_symbol_table_operations_t pending_symbol_table_operations;
scoped_apply_pending_symbol_table_operations apply_pending(
pending_symbol_table_operations);
auto context = detail::make_context<Debug, false>(
first,
last,
@@ -2294,8 +2319,8 @@ namespace boost { namespace parser {
trace_indent,
error_handler,
parser.globals_,
symbol_table_tries);
detail::visit_symbol_table_parsers(context, parser);
symbol_table_tries,
pending_symbol_table_operations);
auto const flags =
Debug ? detail::enable_trace(detail::flags::gen_attrs)
: detail::flags::gen_attrs;
@@ -2336,6 +2361,9 @@ namespace boost { namespace parser {
bool success = true;
int trace_indent = 0;
detail::symbol_table_tries_t symbol_table_tries;
pending_symbol_table_operations_t pending_symbol_table_operations;
scoped_apply_pending_symbol_table_operations apply_pending(
pending_symbol_table_operations);
auto context = detail::make_context<Debug, false>(
first,
last,
@@ -2343,8 +2371,8 @@ namespace boost { namespace parser {
trace_indent,
error_handler,
parser.globals_,
symbol_table_tries);
detail::visit_symbol_table_parsers(context, parser);
symbol_table_tries,
pending_symbol_table_operations);
auto const flags =
Debug ? detail::enable_trace(detail::flags::gen_attrs)
: detail::flags::gen_attrs;
@@ -2390,6 +2418,9 @@ namespace boost { namespace parser {
bool success = true;
int trace_indent = 0;
detail::symbol_table_tries_t symbol_table_tries;
pending_symbol_table_operations_t pending_symbol_table_operations;
scoped_apply_pending_symbol_table_operations apply_pending(
pending_symbol_table_operations);
auto context = detail::make_context<Debug, true>(
first,
last,
@@ -2398,8 +2429,8 @@ namespace boost { namespace parser {
error_handler,
callbacks,
parser.globals_,
symbol_table_tries);
detail::visit_symbol_table_parsers(context, parser);
symbol_table_tries,
pending_symbol_table_operations);
auto const flags =
Debug ? detail::enable_trace(detail::flags::gen_attrs)
: detail::flags::gen_attrs;
@@ -2443,6 +2474,9 @@ namespace boost { namespace parser {
bool success = true;
int trace_indent = 0;
detail::symbol_table_tries_t symbol_table_tries;
pending_symbol_table_operations_t pending_symbol_table_operations;
scoped_apply_pending_symbol_table_operations apply_pending(
pending_symbol_table_operations);
auto context = detail::make_context<Debug, false>(
first,
last,
@@ -2450,8 +2484,8 @@ namespace boost { namespace parser {
trace_indent,
error_handler,
parser.globals_,
symbol_table_tries);
detail::visit_symbol_table_parsers(context, parser);
symbol_table_tries,
pending_symbol_table_operations);
auto const flags =
Debug ? detail::enable_trace(detail::default_flags())
: detail::default_flags();
@@ -2489,6 +2523,9 @@ namespace boost { namespace parser {
bool success = true;
int trace_indent = 0;
detail::symbol_table_tries_t symbol_table_tries;
pending_symbol_table_operations_t pending_symbol_table_operations;
scoped_apply_pending_symbol_table_operations apply_pending(
pending_symbol_table_operations);
auto context = detail::make_context<Debug, false>(
first,
last,
@@ -2496,8 +2533,8 @@ namespace boost { namespace parser {
trace_indent,
error_handler,
parser.globals_,
symbol_table_tries);
detail::visit_symbol_table_parsers(context, parser);
symbol_table_tries,
pending_symbol_table_operations);
auto const flags =
Debug ? detail::enable_trace(detail::default_flags())
: detail::default_flags();
@@ -2542,6 +2579,9 @@ namespace boost { namespace parser {
bool success = true;
int trace_indent = 0;
detail::symbol_table_tries_t symbol_table_tries;
pending_symbol_table_operations_t pending_symbol_table_operations;
scoped_apply_pending_symbol_table_operations apply_pending(
pending_symbol_table_operations);
auto context = detail::make_context<Debug, true>(
first,
last,
@@ -2550,8 +2590,8 @@ namespace boost { namespace parser {
error_handler,
callbacks,
parser.globals_,
symbol_table_tries);
detail::visit_symbol_table_parsers(context, parser);
symbol_table_tries,
pending_symbol_table_operations);
auto const flags =
Debug ? detail::enable_trace(detail::default_flags())
: detail::default_flags();
@@ -5051,6 +5091,48 @@ namespace boost { namespace parser {
diagnostic_text_(other.diagnostic_text_)
{}
/** Inserts an entry consisting of a UTF-8 string `str` to match, and
an associated attribute `x`, to `*this`. The entry is added for
use in all subsequent top-level parses. Subsequent lookups during
the current top-level parse will not necessarily match `str`. */
template<typename Context>
void insert_for_next_parse(
Context const & context, std::string_view str, T x)
{
auto & pending_ops =
detail::get_pending_symtab_ops(context, ref());
pending_ops.push_back(detail::symbol_table_operation<T>{
std::string(str),
std::move(x),
detail::symbol_table_op::insert});
}
/** Erases the entry whose UTF-8 match string is `str`, from `*this`.
The entry will no longer be available for use in all subsequent
top-level parses. `str` will not be removed from the symbols
matched in the current top-level parse. */
template<typename Context>
void erase_for_next_parse(Context const & context, std::string_view str)
{
auto & pending_ops =
detail::get_pending_symtab_ops(context, ref());
pending_ops.push_back(detail::symbol_table_operation<T>{
std::string(str),
std::nullopt,
detail::symbol_table_op::erase});
}
/** Erases all the entries from the copy of the symbol table inside
the parse context `context`. */
template<typename Context>
void clear_for_next_parse(Context const & context)
{
auto & pending_ops =
detail::get_pending_symtab_ops(context, ref());
pending_ops.push_back(detail::symbol_table_operation<T>{
{}, std::nullopt, detail::symbol_table_op::clear});
}
/** Uses UTF-8 string `str` to look up an attribute in the table
during parsing, returning it as an optional reference. The lookup
is done on the copy of the symbol table inside the parse context
@@ -5157,8 +5239,6 @@ namespace boost { namespace parser {
}
mutable std::vector<std::pair<std::string, T>> initial_elements_;
mutable std::vector<detail::symbol_table_operation<T>>
pending_operations_;
symbol_parser const * copied_from_;
symbol_parser const & ref() const noexcept
@@ -5172,11 +5252,6 @@ namespace boost { namespace parser {
{
return ref().initial_elements_;
}
std::vector<detail::symbol_table_operation<T>> &
pending_operations() const noexcept
{
return ref().pending_operations_;
}
std::string_view diagnostic_text_;
};
@@ -5751,20 +5826,14 @@ namespace boost { namespace parser {
this->parser_.initial_elements_.begin());
}
using parser_interface<symbol_parser<T>>::operator();
/** Inserts an entry consisting of a UTF-8 string `str` to match, and
an associated attribute `x`, to `*this`. The entry is added for
use in all subsequent top-level parses. Subsequent lookups during
the current top-level parse will not necessarily match `str`. */
symbols & insert_for_next_parse(std::string_view str, T x)
void insert_for_next_parse(std::string_view str, T x)
{
this->parser_.pending_operations().push_back(
detail::symbol_table_operation<T>{
std::string(str),
std::move(x),
detail::symbol_table_op::insert});
return *this;
this->parser_.initial_elements_.push_back(
std::pair(std::string(str), std::move(x)));
}
/** Erases the entry whose UTF-8 match string is `str`, from `*this`.
@@ -5773,26 +5842,44 @@ namespace boost { namespace parser {
matched in the current top-level parse. */
void erase_for_next_parse(std::string_view str)
{
this->parser_.pending_operations().push_back(
detail::symbol_table_operation<T>{
std::string(str),
std::nullopt,
detail::symbol_table_op::erase});
auto it = std::find_if(
this->parser_.initial_elements_.begin(),
this->parser_.initial_elements_.end(),
[str](auto const & x) { return x.first == str; });
this->parser_.initial_elements_.erase(it);
}
/** Erases all the entries from the copy of the symbol table inside
the parse context `context`. */
void clear_for_next_parse()
void clear_for_next_parse() { this->parser_.initial_elements_.clear(); }
/** Inserts an entry consisting of a UTF-8 string `str` to match, and
an associated attribute `x`, to `*this`. The entry is added for
use in all subsequent top-level parses. Subsequent lookups during
the current top-level parse will not necessarily match `str`. */
template<typename Context>
void insert_for_next_parse(
Context const & context, std::string_view str, T x)
{
this->parser_.pending_operations().push_back(
detail::symbol_table_operation<T>{
{}, std::nullopt, detail::symbol_table_op::clear});
this->parser_.insert_for_next_parse(context, str, std::move(x));
}
/** Equivalent to `insert_for_next_parse(str, std::move(x))`. */
symbols & operator()(std::string_view str, T x)
/** Erases the entry whose UTF-8 match string is `str`, from `*this`.
The entry will no longer be available for use in all subsequent
top-level parses. `str` will not be removed from the symbols
matched in the current top-level parse. */
template<typename Context>
void erase_for_next_parse(Context const & context, std::string_view str)
{
return insert_for_next_parse(str, std::move(x));
this->parser_.erase_for_next_parse(context, str);
}
/** Erases all the entries from the copy of the symbol table inside
the parse context `context`. */
template<typename Context>
void clear_for_next_parse(Context const & context)
{
this->parser_.clear_for_next_parse(context);
}
/** Uses UTF-8 string `str` to look up an attribute in the table
@@ -5975,7 +6062,7 @@ namespace boost { namespace parser {
parser(first, last, context, skip, flags, success, retval); \
} \
}
//]
//]
#endif
@@ -6114,8 +6201,11 @@ namespace boost { namespace parser {
typename Parser::combining_groups>;
using final_combining_groups = detail::
combined_combining_t<combining_groups, parser_combining_groups>;
using rhs_backtracking = decltype(detail::hl::prepend(
detail::hl::drop_front(typename Parser::backtracking{}),
std::bool_constant<AllowBacktracking>{}));
using backtracking = decltype(detail::hl::concat(
BacktrackingTuple{}, typename Parser::backtracking{}));
BacktrackingTuple{}, rhs_backtracking{}));
using parser_t = seq_parser<
decltype(detail::hl::concat(parsers_, parser.parser_.parsers_)),
backtracking,
@@ -9327,7 +9417,8 @@ namespace boost { namespace parser {
std::declval<int &>(),
std::declval<error_handler_type>(),
std::declval<global_state_type &>(),
std::declval<detail::symbol_table_tries_t &>()));
std::declval<detail::symbol_table_tries_t &>(),
std::declval<detail::pending_symbol_table_operations_t &>()));
using type = decltype(std::declval<Parser>()(
std::declval<iterator &>(),
std::declval<sentinel>(),

View File

@@ -11,6 +11,7 @@
#include <any>
#include <cstdint>
#include <functional>
#include <map>
#include <memory>
#include <optional>
@@ -84,12 +85,24 @@ namespace boost { namespace parser {
{
std::any trie_;
bool has_case_folded_;
bool pending_operations_;
};
using symbol_table_tries_t =
std::map<void *, symbol_table_trie_element, std::less<void *>>;
using pending_symtab_ops_visitor = std::function<void()>;
struct pending_symtab_ops_entry
{
pending_symtab_ops_visitor visit_;
// Contains std::vector<detail::symbol_table_operation<T>> (T is
// known to visit_).
std::any ops_;
};
using pending_symbol_table_operations_t = std::map<
void const *,
pending_symtab_ops_entry,
std::less<void const *>>;
template<
bool DoTrace,
bool UseCallbacks,
@@ -103,7 +116,9 @@ namespace boost { namespace parser {
int & indent,
ErrorHandler const & error_handler,
nope &,
symbol_table_tries_t & symbol_table_tries) noexcept;
symbol_table_tries_t & symbol_table_tries,
pending_symbol_table_operations_t &
pending_symbol_table_operations) noexcept;
struct skip_skipper;

10
index.html Normal file
View File

@@ -0,0 +1,10 @@
<html>
<head>
<title>Boost.Parser</title>
<meta http-equiv="refresh" content="0; URL=../../doc/html/parser.html">
</head>
<body>
Automatic redirection failed, please go to
<a href="../../doc/html/parser.html">../../doc/html/parser.html</a>
</body>
</html>

View File

@@ -228,7 +228,9 @@ constexpr auto double_s = u8"sS"; // U+0073 U+0073
// with mutation
{
symbols<int> roman_numerals;
roman_numerals.insert_for_next_parse("I", 1)("V", 5)("X", 10);
roman_numerals.insert_for_next_parse("I", 1);
roman_numerals.insert_for_next_parse("V", 5);
roman_numerals.insert_for_next_parse("X", 10);
auto const add_numeral = [&roman_numerals](auto & context) {
using namespace boost::parser::literals;
char chars[2] = {get(_attr(context), 0_c), 0};

View File

@@ -10,6 +10,12 @@
using namespace boost::parser;
rule<class symbol_rule, std::string_view> const symrule = "symbols";
symbols<std::string_view> rule_symbols;
auto const fwd_attr = [](auto & ctx) { _val(ctx) = _attr(ctx); };
auto symrule_def = rule_symbols[fwd_attr];
BOOST_PARSER_DEFINE_RULES(symrule);
int main()
{
// symbols_empty
@@ -137,7 +143,9 @@ int main()
// symbols_mutating
{
symbols<int> roman_numerals;
roman_numerals.insert_for_next_parse("I", 1)("V", 5)("X", 10);
roman_numerals.insert_for_next_parse("I", 1);
roman_numerals.insert_for_next_parse("V", 5);
roman_numerals.insert_for_next_parse("X", 10);
auto const add_numeral = [&roman_numerals](auto & context) {
using namespace boost::parser::literals;
char chars[2] = {get(_attr(context), 0_c), 0};
@@ -166,7 +174,9 @@ int main()
// insert/erase/clear
{
symbols<int> roman_numerals;
roman_numerals.insert_for_next_parse("I", 1)("V", 5)("X", 10);
roman_numerals.insert_for_next_parse("I", 1);
roman_numerals.insert_for_next_parse("V", 5);
roman_numerals.insert_for_next_parse("X", 10);
auto const insert_numeral = [&roman_numerals](auto & context) {
using namespace boost::parser::literals;
@@ -189,15 +199,16 @@ int main()
auto const next_insert_numeral = [&roman_numerals](auto & context) {
using namespace boost::parser::literals;
char chars[2] = {get(_attr(context), 0_c), 0};
roman_numerals.insert_for_next_parse(chars, get(_attr(context), 1_c));
roman_numerals.insert_for_next_parse(
context, chars, get(_attr(context), 1_c));
};
auto const next_erase_numeral = [&roman_numerals](auto & context) {
using namespace boost::parser::literals;
char chars[2] = {_attr(context), 0};
roman_numerals.erase_for_next_parse(chars);
roman_numerals.erase_for_next_parse(context, chars);
};
auto const next_clear_numerals = [&roman_numerals](auto &) {
roman_numerals.clear_for_next_parse();
auto const next_clear_numerals = [&roman_numerals](auto & context) {
roman_numerals.clear_for_next_parse(context);
};
auto const next_add_parser =
@@ -217,7 +228,7 @@ int main()
{
// add only for the next parse
auto result = parse("next-addL50L", next_add_parser >> roman_numerals);
BOOST_TEST(!result); // TODO
BOOST_TEST(!result);
result = parse("L", roman_numerals);
BOOST_TEST(result);
@@ -273,8 +284,8 @@ int main()
BOOST_TEST(*parse("V", roman_numerals) == 5);
auto result = parse("next-delVV", next_delete_parser >> roman_numerals);
BOOST_TEST(result); // TODO
BOOST_TEST(*result == 5); // TODO
BOOST_TEST(result);
BOOST_TEST(*result == 5);
result = parse("V", roman_numerals);
BOOST_TEST(!result);
@@ -326,12 +337,68 @@ int main()
BOOST_TEST(*parse("L", roman_numerals) == 50);
auto result = parse("next-clearI", next_clear_parser >> roman_numerals);
BOOST_TEST(result); // TODO
BOOST_TEST(*result == 1); // TODO
BOOST_TEST(result);
BOOST_TEST(*result == 1);
BOOST_TEST(!parse("I", roman_numerals));
BOOST_TEST(!parse("L", roman_numerals));
}
{
// parse using symbols directly -- not using the table within a rule
rule_symbols.clear_for_next_parse();
rule_symbols.insert_for_next_parse("I", "one");
rule_symbols.insert_for_next_parse("L", "50");
auto result = parse("I", rule_symbols);
BOOST_TEST(result);
BOOST_TEST(*result == "one");
result = parse("L", rule_symbols);
BOOST_TEST(result);
BOOST_TEST(*result == "50");
BOOST_TEST(!parse("X", rule_symbols));
}
{
// symbols within a rule
rule_symbols.clear_for_next_parse();
rule_symbols.insert_for_next_parse("foo", "foofie");
rule_symbols.insert_for_next_parse("bar", "barrie");
auto result = parse("foo", symrule);
BOOST_TEST(result);
BOOST_TEST(*result == "foofie");
result = parse("bar", symrule);
BOOST_TEST(result);
BOOST_TEST(*result == "barrie");
BOOST_TEST(!parse("X", symrule));
BOOST_TEST(!parse("I", symrule));
}
{
// symbols within a rule w/error handler
rule_symbols.clear_for_next_parse();
rule_symbols.insert_for_next_parse("foo", "foofie");
rule_symbols.insert_for_next_parse("bar", "barrie");
callback_error_handler error_handler(
[](std::string_view m) { std::cout << m << "\n"; });
auto parser = with_error_handler(symrule, error_handler);
auto result = parse("foo", parser);
BOOST_TEST(result);
BOOST_TEST(*result == "foofie");
result = parse("bar", parser);
BOOST_TEST(result);
BOOST_TEST(*result == "barrie");
BOOST_TEST(!parse("baz", parser));
}
}
return boost::report_errors();