mirror of
https://github.com/boostorg/parser.git
synced 2026-01-20 04:42:22 +00:00
Compare commits
14 Commits
gh-pages
...
boost-1.87
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f468d529fe | ||
|
|
b5d4339f2c | ||
|
|
6d7fa6f105 | ||
|
|
c975f57908 | ||
|
|
063291b78c | ||
|
|
3eb827dcd6 | ||
|
|
6d796287b6 | ||
|
|
bb0fb885b8 | ||
|
|
94a9daec40 | ||
|
|
4344dd3f47 | ||
|
|
a7c7470bc1 | ||
|
|
b273133fd2 | ||
|
|
3a7ddcf936 | ||
|
|
d79efb0daa |
@@ -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)
|
||||
|
||||
11
README.md
11
README.md
@@ -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:
|
||||
|
||||
|
||||
@@ -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`.
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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>(),
|
||||
|
||||
@@ -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
10
index.html
Normal 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>
|
||||
@@ -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};
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user