2
0
mirror of https://github.com/boostorg/parser.git synced 2026-02-21 03:12:08 +00:00

6 Commits

Author SHA1 Message Date
Andreas Buhr
4a200a4074 Add define BOOST_PARSER_DISABLE_TRACE to disable trace mode at compile time.
The trace feature doubles the compile time, even if never used.
This patch introduces the preprocessor define BOOST_PARSER_DISABLE_TRACE
to deactivate this feature at compile time.
2026-02-15 15:18:22 -06:00
Andreas Buhr
1b984e3546 Allow move-only attributes
This tests the usage of move-only attributes.
parser.hpp and printing.hpp are slightly modified to make it work.
2026-02-14 13:45:05 -06:00
Andreas Buhr
316b4921a9 Move values into detail::assign
Code cleanup:
Most of the time, values are std::moved into detail::assign,
but not always. This patch makes usage more consistent to
always use std::move, except for ints, floats, and iterators.
2026-02-14 13:42:09 -06:00
Andreas Buhr
4706f57c8e Avoid creation of temp_result object in seq_parser
The object is never used, only its type is used.
2026-02-14 13:35:49 -06:00
Andreas Buhr
5625f0345e Use std::make_move_iterator in move_back to actually move stuff
The old implementation did not move.
2026-02-14 13:34:29 -06:00
Andreas Buhr
a2df985cc5 fix MacOS CI badge in README.md 2026-02-14 13:32:24 -06:00
12 changed files with 409 additions and 36 deletions

View File

@@ -18,6 +18,13 @@ jobs:
compiler_version: [g++-10, g++-11]
cxx_std: [17, 20]
os: [ubuntu-22.04]
disable_trace: [false]
include:
# Test with trace disabled
- compiler_version: g++-11
cxx_std: 20
os: ubuntu-22.04
disable_trace: true
runs-on: ${{ matrix.os }}
@@ -30,7 +37,11 @@ jobs:
run: |
mkdir build
cd build
cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler_version }} -DCXX_STD=${{ matrix.cxx_std }}
if [ "${{ matrix.disable_trace }}" = "true" ]; then
cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler_version }} -DCXX_STD=${{ matrix.cxx_std }} -DDISABLE_TRACE=true
else
cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler_version }} -DCXX_STD=${{ matrix.cxx_std }}
fi
- name: Build
run: cd build ; make -j4

View File

@@ -17,6 +17,12 @@ jobs:
matrix:
cxx_std: [17, 20, 23]
os: [windows-2022]
disable_trace: [false]
include:
# Test with trace disabled
- cxx_std: 20
os: windows-2022
disable_trace: true
runs-on: ${{ matrix.os }}
@@ -26,7 +32,13 @@ jobs:
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. Visual Studio is a multi-config generator, so we don't use CMAKE_BUILD_TYPE.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B build -DCXX_STD=${{ matrix.cxx_std }}
run: |
if ("${{ matrix.disable_trace }}" -eq "true") {
cmake -B build -DCXX_STD=${{ matrix.cxx_std }} -DDISABLE_TRACE=true
} else {
cmake -B build -DCXX_STD=${{ matrix.cxx_std }}
}
shell: pwsh
- name: Build
working-directory: build

View File

@@ -64,6 +64,12 @@ if (BUILD_WITH_HANA)
add_definitions(-DBOOST_PARSER_USE_HANA_TUPLE)
endif()
set(DISABLE_TRACE false CACHE BOOL
"Disable parser trace functionality (defines BOOST_PARSER_DISABLE_TRACE).")
if (DISABLE_TRACE)
add_definitions(-DBOOST_PARSER_DISABLE_TRACE)
endif()
##################################################
# Dependencies

View File

@@ -67,6 +67,6 @@ Develop status:
[![Windows MSVC](https://github.com/tzlaine/parser/actions/workflows/windows.yml/badge.svg?branch=develop)](https://github.com/tzlaine/parser/actions/workflows/windows.yml)
[![macos-13 - Clang 14](https://github.com/tzlaine/parser/actions/workflows/macos-13.yml/badge.svg?branch=develop)](https://github.com/tzlaine/parser/actions/workflows/macos-13.yml)
[![macos-15 - Clang](https://github.com/tzlaine/parser/actions/workflows/macos-15.yml/badge.svg?branch=develop)](https://github.com/tzlaine/parser/actions/workflows/macos-15.yml)
[![License](https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt)

View File

@@ -148,6 +148,7 @@
[def _RULES_ [macroref BOOST_PARSER_DEFINE_RULES `BOOST_PARSER_DEFINE_RULES`]]
[def _AGGR_SIZE_ [macroref BOOST_PARSER_MAX_AGGREGATE_SIZE `BOOST_PARSER_MAX_AGGREGATE_SIZE`]]
[def _SUBRNG_ [macroref BOOST_PARSER_SUBRANGE `BOOST_PARSER_SUBRANGE`]]
[def _DISABLE_TRACE_ [macroref BOOST_PARSER_DISABLE_TRACE `BOOST_PARSER_DISABLE_TRACE`]]
[def __p_ [globalref boost::parser::_p `_p`]]

View File

@@ -3766,6 +3766,22 @@ Some things to be aware of when looking at _Parser_ trace output:
produces that value. In these cases, you'll see the resolved value of the
parse argument.
[heading Compile-time trace disabling]
While trace mode is very useful for debugging, it does have some overhead.
Most parser templates are instantiated twice: Once with tracing enabled,
once with tracing disabled.
If you want to completely disable trace functionality at compile time, you can define
`BOOST_PARSER_DISABLE_TRACE` before including any Boost.Parser headers:
[teletype]``
#define BOOST_PARSER_DISABLE_TRACE
#include <boost/parser/parser.hpp>
``
When this define is set, all trace-related code is compiled out,
reducing the compile time.
[endsect]
[section Memory Allocation]
@@ -3983,7 +3999,8 @@ This defines a RAII trace object that will produce the verbose trace requested
by the user if they passed `_trace_::on` to the top-level parse. It only has
effect if `detail::enable_trace(flags)` is `true`. If trace is enabled, it
will show the state of the parse at the point at which it is defined, and then
again when it goes out of scope.
again when it goes out of scope. By defining `BOOST_PARSER_DISABLE_TRACE`,
the trace feature can be disabled globally at compile time.
[important For the tracing code to work, you must define an overload of
`detail::print_parser` for your new parser type/template. See

View File

@@ -36,6 +36,10 @@
disable the use of concepts, define this macro. */
# define BOOST_PARSER_DISABLE_CONCEPTS
/** Boost.Parser will generate code to trace the execution of each and every
parser by default. To disable all trace code, define this macro. */
# define BOOST_PARSER_DISABLE_TRACE
/** Define this macro to use `boost::hana::tuple` instead of `std::tuple`
throughout Boost.Parser. */
# define BOOST_PARSER_USE_HANA_TUPLE
@@ -92,6 +96,12 @@
# define BOOST_PARSER_USE_CONCEPTS 0
#endif
#if defined(BOOST_PARSER_DISABLE_TRACE)
# define BOOST_PARSER_DO_TRACE 0
#else
# define BOOST_PARSER_DO_TRACE 1
#endif
#if defined(__cpp_lib_ranges) && BOOST_PARSER_USE_CONCEPTS
# define BOOST_PARSER_SUBRANGE std::ranges::subrange
#else

View File

@@ -593,11 +593,14 @@ namespace boost { namespace parser { namespace detail {
}
template<typename Context, typename T>
auto resolve(Context const & context, T const & x);
decltype(auto) resolve(Context const & context, T const & x);
template<typename Context>
auto resolve(Context const &, nope n);
template<typename DependentType, bool DoTraceMacro>
constexpr bool trace_disabled = !DoTraceMacro;
template<
bool DoTrace,
typename Iter,
@@ -606,6 +609,8 @@ namespace boost { namespace parser { namespace detail {
typename Attribute>
struct scoped_trace_t
{
static_assert(!trace_disabled<Iter, BOOST_PARSER_DO_TRACE>);
scoped_trace_t(
std::ostream & os,
Iter & first,
@@ -681,6 +686,9 @@ namespace boost { namespace parser { namespace detail {
flags f,
Attribute const & attr)
{
if constexpr (!BOOST_PARSER_DO_TRACE)
return;
if constexpr (Context::do_trace) {
std::stringstream oss;
detail::print_parser(context, parser, oss);
@@ -695,6 +703,9 @@ namespace boost { namespace parser { namespace detail {
template<typename Context, typename Attribute>
auto final_trace(Context const & context, flags f, Attribute const & attr)
{
if constexpr (!BOOST_PARSER_DO_TRACE)
return;
if (!detail::do_trace(f))
return;

View File

@@ -1020,7 +1020,7 @@ namespace boost { namespace parser {
bool Callable = is_detected_v<callable, T const &, Context const &>>
struct resolve_impl
{
static auto call(Context const &, T const & x) { return x; }
static auto& call(Context const &, T const & x) { return x; }
};
template<typename Context, typename T>
@@ -1033,7 +1033,7 @@ namespace boost { namespace parser {
};
template<typename Context, typename T>
auto resolve(Context const & context, T const & x)
decltype(auto) resolve(Context const & context, T const & x)
{
return resolve_impl<Context, T>::call(context, x);
}
@@ -2168,7 +2168,10 @@ namespace boost { namespace parser {
{
if (!gen_attrs || !x)
return;
c.insert(c.end(), x->begin(), x->end());
c.insert(c.end(),
std::make_move_iterator(x->begin()),
std::make_move_iterator(x->end())
);
}
template<typename Container, typename T>
@@ -3177,6 +3180,7 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this,
first,
@@ -3185,6 +3189,7 @@ namespace boost { namespace parser {
detail::in_apply_parser(flags) ? detail::disable_trace(flags)
: flags,
retval);
#endif
if constexpr (detail::is_optional_v<Attribute>) {
detail::optional_type<Attribute> attr;
@@ -3341,8 +3346,10 @@ namespace boost { namespace parser {
Attribute & retval) const
{
//[ opt_parser_trace
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
//]
//[ opt_parser_skip
@@ -3505,8 +3512,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
use_parser_t<Iter, Sentinel, Context, SkipParser> const use_parser{
first, last, context, skip, flags, success};
@@ -3629,8 +3638,10 @@ namespace boost { namespace parser {
decltype(detail::hl::transform(parsers_, use_parser));
result_t retval{};
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first_, last, context, flags, retval);
#endif
call_impl(
first,
@@ -3665,8 +3676,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first_, last, context, flags, retval);
#endif
Iter first = first_;
use_parser_t<Iter, Sentinel, Context, SkipParser> const use_parser{
@@ -3713,7 +3726,7 @@ namespace boost { namespace parser {
if constexpr (detail::is_struct_compatible_v<
Attribute,
result_t>) {
detail::assign(retval, temp_retval);
detail::assign(retval, std::move(temp_retval));
} else {
detail::assign(
retval,
@@ -4292,12 +4305,13 @@ namespace boost { namespace parser {
{
Iter first = first_;
auto temp_result =
make_temp_result(first, last, context, skip, flags, success);
using temp_result_t =
decltype(make_temp_result(first, last, context, skip, flags, success));
std::decay_t<decltype(parser::get(temp_result, llong<0>{}))>
std::decay_t<decltype(parser::get(std::declval<temp_result_t>(), llong<0>{}))>
retval{};
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this,
first_,
@@ -4306,10 +4320,11 @@ namespace boost { namespace parser {
detail::in_apply_parser(flags) ? detail::disable_trace(flags)
: flags,
retval);
#endif
std::decay_t<decltype(parser::get(temp_result, llong<1>{}))>
std::decay_t<decltype(parser::get(std::declval<temp_result_t>(), llong<1>{}))>
indices;
std::decay_t<decltype(parser::get(temp_result, llong<2>{}))>
std::decay_t<decltype(parser::get(std::declval<temp_result_t>(), llong<2>{}))>
merged;
call_impl(
first,
@@ -4328,7 +4343,7 @@ namespace boost { namespace parser {
// A 1-tuple is converted to a scalar.
if constexpr (detail::hl::size(retval) == llong<1>{}) {
using namespace literals;
return parser::get(retval, 0_c);
return parser::get(std::move(retval), 0_c);
} else {
return retval;
}
@@ -4349,6 +4364,7 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this,
first_,
@@ -4357,16 +4373,17 @@ namespace boost { namespace parser {
detail::in_apply_parser(flags) ? detail::disable_trace(flags)
: flags,
retval);
#endif
Iter first = first_;
auto temp_result =
make_temp_result(first, last, context, skip, flags, success);
using temp_result_t =
decltype(make_temp_result(first, last, context, skip, flags, success));
using temp_result_attr_t =
std::decay_t<decltype(parser::get(temp_result, llong<0>{}))>;
std::decay_t<decltype(parser::get(temp_result, llong<1>{}))>
std::decay_t<decltype(parser::get(std::declval<temp_result_t>(), llong<0>{}))>;
std::decay_t<decltype(parser::get(std::declval<temp_result_t>(), llong<1>{}))>
indices;
std::decay_t<decltype(parser::get(temp_result, llong<2>{}))> merged;
std::decay_t<decltype(parser::get(std::declval<temp_result_t>(), llong<2>{}))> merged;
auto max_ = [](auto result, auto x) {
if constexpr (decltype(result)::value < decltype(x)::value) {
@@ -4703,8 +4720,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
auto const initial_first = first;
auto attr = parser_.call(
@@ -4769,8 +4788,10 @@ namespace boost { namespace parser {
detail::flags flags,
bool & success) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, detail::global_nope);
#endif
auto attr =
parser_.call(first, last, context, skip, flags, success);
if (success && detail::gen_attrs(flags))
@@ -4794,8 +4815,11 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
auto attr =
parser_.call(first, last, context, skip, flags, success);
if (success && detail::gen_attrs(flags))
@@ -4822,8 +4846,10 @@ namespace boost { namespace parser {
detail::flags flags,
bool & success) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, detail::global_nope);
#endif
parser_.call(
first,
@@ -4850,8 +4876,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
parser_.call(
first,
@@ -4901,8 +4929,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
auto const initial_first = first;
parser_.call(
@@ -4966,8 +4996,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
auto const initial_first = first;
parser_.call(
@@ -5042,8 +5074,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
parser_.call(
first,
@@ -5102,8 +5136,10 @@ namespace boost { namespace parser {
auto context = context_;
++context.no_case_depth_;
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
parser_.call(first, last, context, skip, flags, success, retval);
}
@@ -5149,8 +5185,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
if constexpr (detail::is_nope_v<SkipParser>) {
parser_.call(
@@ -5213,8 +5251,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
auto first_copy = first;
parser_.call(
@@ -5380,8 +5420,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
auto [trie, _0] = detail::get_trie(context, ref());
auto const lookup = context.no_case_depth_
@@ -5455,8 +5497,10 @@ namespace boost { namespace parser {
tag_type * const tag_ptr = nullptr;
auto const rule_context = detail::make_rule_context(
context, tag_ptr, retval, locals, params);
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, rule_context, flags, retval);
#endif
bool dont_assign = false;
if constexpr (in_recursion) {
@@ -5485,7 +5529,7 @@ namespace boost { namespace parser {
dont_assign);
if (success && !dont_assign) {
if constexpr (!detail::is_nope_v<decltype(attr)>)
detail::assign(retval, attr);
detail::assign(retval, std::move(attr));
}
}
@@ -5553,8 +5597,10 @@ namespace boost { namespace parser {
auto const rule_context = detail::make_rule_context(
context, tag_ptr, attr, locals, params);
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, rule_context, flags, retval);
#endif
bool dont_assign = false;
parse_rule(
@@ -5580,7 +5626,7 @@ namespace boost { namespace parser {
container<Attribute_> && container<attr_type>) {
detail::move_back(retval, attr, detail::gen_attrs(flags));
} else {
detail::assign(retval, attr);
detail::assign(retval, std::move(attr));
}
}
}
@@ -6744,8 +6790,10 @@ namespace boost { namespace parser {
detail::flags flags,
bool & success) const noexcept
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, detail::global_nope);
#endif
BOOST_PARSER_SUBRANGE const where(first, first);
auto const predicate_context = detail::make_action_context(
context, detail::global_nope, where);
@@ -6772,8 +6820,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
BOOST_PARSER_SUBRANGE const where(first, first);
auto const predicate_context = detail::make_action_context(
context, detail::global_nope, where);
@@ -6823,8 +6873,10 @@ namespace boost { namespace parser {
detail::flags flags,
bool & success) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, detail::global_nope);
#endif
if (first != last)
success = false;
return {};
@@ -6845,8 +6897,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
if (first != last)
success = false;
}
@@ -6875,8 +6929,10 @@ namespace boost { namespace parser {
detail::flags flags,
bool &) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, detail::global_nope);
#endif
return detail::resolve(context, attr_);
}
@@ -6895,8 +6951,10 @@ namespace boost { namespace parser {
bool & success,
Attribute_ & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
if (detail::gen_attrs(flags))
detail::assign_copy(retval, detail::resolve(context, attr_));
}
@@ -6961,8 +7019,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
if (first == last) {
success = false;
@@ -7126,8 +7186,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
if (first == last) {
success = false;
@@ -7277,8 +7339,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
if (first == last) {
success = false;
@@ -7357,8 +7421,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
if (first == last) {
success = false;
@@ -7479,8 +7545,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
if (first == last) {
success = false;
@@ -7643,8 +7711,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
if (first == last) {
success = false;
@@ -7964,8 +8034,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
if (first == last) {
success = false;
@@ -8131,8 +8203,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
auto compare =
[no_case = context.no_case_depth_](char32_t a, char32_t b) {
@@ -8220,8 +8294,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
T attr = 0;
auto const initial = first;
success =
@@ -8361,8 +8437,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
T attr = 0;
auto const initial = first;
success =
@@ -8476,8 +8554,10 @@ namespace boost { namespace parser {
bool & success,
Attribute & retval) const
{
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
T attr = 0;
auto const initial = first;
success = detail::numeric::parse_real(first, last, attr);
@@ -8570,8 +8650,10 @@ namespace boost { namespace parser {
using attr_t = decltype(or_parser_.call(
first, last, context, skip, flags, success));
attr_t attr{};
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ =
detail::scoped_trace(*this, first, last, context, flags, attr);
#endif
attr = or_parser_.call(first, last, context, skip, flags, success);
return attr;
}
@@ -8596,8 +8678,10 @@ namespace boost { namespace parser {
"It looks like you tried to write switch_(val). You need at "
"least one alternative, like: switch_(val)(value_1, "
"parser_1)(value_2, parser_2)..."));
#if BOOST_PARSER_DO_TRACE
[[maybe_unused]] auto _ = detail::scoped_trace(
*this, first, last, context, flags, retval);
#endif
or_parser_.call(first, last, context, skip, flags, success, retval);
}
@@ -9056,8 +9140,13 @@ namespace boost { namespace parser {
"fill in attr above, using the attribute generated by parser. "
"However, parser does not generate an attribute.");
if (trace_mode == trace::on) {
return reset = detail::parse_impl<true>(
first, last, parser, parser.error_handler_, attr);
return reset =
detail::parse_impl<(true && BOOST_PARSER_DO_TRACE)>(
first,
last,
parser,
parser.error_handler_,
attr);
} else {
return reset = detail::parse_impl<false>(
first, last, parser, parser.error_handler_, attr);
@@ -9074,8 +9163,9 @@ namespace boost { namespace parser {
"fill in attr above, using the attribute generated by parser. "
"However, parser does not generate an attribute.");
if (trace_mode == trace::on) {
return reset = detail::parse_impl<true>(
f, l, parser, parser.error_handler_, attr);
return reset =
detail::parse_impl<(true && BOOST_PARSER_DO_TRACE)>(
f, l, parser, parser.error_handler_, attr);
} else {
return reset = detail::parse_impl<false>(
f, l, parser, parser.error_handler_, attr);
@@ -9178,7 +9268,7 @@ namespace boost { namespace parser {
{
if constexpr (!detail::is_char8_iter_v<I>) {
if (trace_mode == trace::on) {
return detail::parse_impl<true>(
return detail::parse_impl<(true && BOOST_PARSER_DO_TRACE)>(
first, last, parser, parser.error_handler_);
} else {
return detail::parse_impl<false>(
@@ -9191,7 +9281,7 @@ namespace boost { namespace parser {
auto const l = r.end();
auto _ = detail::scoped_base_assign(first, f);
if (trace_mode == trace::on) {
return detail::parse_impl<true>(
return detail::parse_impl<(true && BOOST_PARSER_DO_TRACE)>(
f, l, parser, parser.error_handler_);
} else {
return detail::parse_impl<false>(
@@ -9297,7 +9387,8 @@ namespace boost { namespace parser {
"fill in attr above, using the attribute generated by parser. "
"However, parser does not generate an attribute.");
if (trace_mode == trace::on) {
return reset = detail::skip_parse_impl<true>(
return reset = detail::skip_parse_impl<(
true && BOOST_PARSER_DO_TRACE)>(
first,
last,
parser,
@@ -9325,7 +9416,8 @@ namespace boost { namespace parser {
"fill in attr above, using the attribute generated by parser. "
"However, parser does not generate an attribute.");
if (trace_mode == trace::on) {
return reset = detail::skip_parse_impl<true>(
return reset = detail::skip_parse_impl<(
true && BOOST_PARSER_DO_TRACE)>(
f, l, parser, skip, parser.error_handler_, attr);
} else {
return reset = detail::skip_parse_impl<false>(
@@ -9430,7 +9522,7 @@ namespace boost { namespace parser {
{
if constexpr (!detail::is_char8_iter_v<I>) {
if (trace_mode == trace::on) {
return detail::skip_parse_impl<true>(
return detail::skip_parse_impl<(true && BOOST_PARSER_DO_TRACE)>(
first, last, parser, skip, parser.error_handler_);
} else {
return detail::skip_parse_impl<false>(
@@ -9443,7 +9535,7 @@ namespace boost { namespace parser {
auto const l = r.end();
auto _ = detail::scoped_base_assign(first, f);
if (trace_mode == trace::on) {
return detail::skip_parse_impl<true>(
return detail::skip_parse_impl<(true && BOOST_PARSER_DO_TRACE)>(
f, l, parser, skip, parser.error_handler_);
} else {
return detail::skip_parse_impl<false>(
@@ -9547,7 +9639,8 @@ namespace boost { namespace parser {
{
if constexpr (!detail::is_char8_iter_v<I>) {
if (trace_mode == trace::on) {
return detail::callback_parse_impl<true>(
return detail::callback_parse_impl<(
true && BOOST_PARSER_DO_TRACE)>(
first, last, parser, parser.error_handler_, callbacks);
} else {
return detail::callback_parse_impl<false>(
@@ -9560,7 +9653,8 @@ namespace boost { namespace parser {
auto const l = r.end();
auto _ = detail::scoped_base_assign(first, f);
if (trace_mode == trace::on) {
return detail::callback_parse_impl<true>(
return detail::callback_parse_impl<(
true && BOOST_PARSER_DO_TRACE)>(
f, l, parser, parser.error_handler_, callbacks);
} else {
return detail::callback_parse_impl<false>(
@@ -9672,7 +9766,8 @@ namespace boost { namespace parser {
{
if constexpr (!detail::is_char8_iter_v<I>) {
if (trace_mode == trace::on) {
return detail::callback_skip_parse_impl<true>(
return detail::callback_skip_parse_impl<(
true && BOOST_PARSER_DO_TRACE)>(
first,
last,
parser,
@@ -9695,7 +9790,8 @@ namespace boost { namespace parser {
auto const l = r.end();
auto _ = detail::scoped_base_assign(first, f);
if (trace_mode == trace::on) {
return detail::callback_skip_parse_impl<true>(
return detail::callback_skip_parse_impl<(
true && BOOST_PARSER_DO_TRACE)>(
f, l, parser, skip, parser.error_handler_, callbacks);
} else {
return detail::callback_skip_parse_impl<false>(

View File

@@ -82,6 +82,7 @@ add_test_executable(parser_seq_permutations_1)
add_test_executable(parser_seq_permutations_2)
add_test_executable(parser_or_permutations_1)
add_test_executable(parser_or_permutations_2)
add_test_executable(disable_trace)
if (MSVC)
add_executable(vs_output_tracing tracing.cpp)

27
test/disable_trace.cpp Normal file
View File

@@ -0,0 +1,27 @@
/**
* Copyright (C) 2025
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
#define BOOST_PARSER_DISABLE_TRACE
#include <boost/core/lightweight_test.hpp>
#include <boost/parser/parser.hpp>
int main()
{
namespace bp = boost::parser;
{
auto const parser =
bp::string("FOO") >> -(bp::string("bar") | bp::string("foo"));
auto result = bp::parse("FOOfoo", parser);
BOOST_TEST(result);
BOOST_TEST(bp::get(*result, bp::llong<0>{}) == std::string("FOO"));
BOOST_TEST(bp::get(*result, bp::llong<1>{}) == std::string("foo"));
}
return boost::report_errors();
}

View File

@@ -597,6 +597,186 @@ void github_pr_297()
}
}
namespace github_issue_312_ {
/*
* Recursive descent parser for expressions.
* Supports addition (+), multiplication (*) and
* parethesized expressions, nothing else.
*
* Creates a tree of "evaluatable" objects which
* own their downstream objects in a unique_ptr
*/
// base class for all tree nodes
struct evaluatable
{
virtual double evaluate() = 0;
virtual ~evaluatable() = default;
};
namespace bp = boost::parser;
// top level parser
constexpr bp::rule<struct expression_tag, std::unique_ptr<evaluatable>> expression_parser = "expression_parser";
/*
* LITERAL EXPRESSION
*/
struct literal_evaluatable : evaluatable
{
explicit literal_evaluatable(double v) : value_(v) {}
double evaluate() override
{
return value_;
}
double value_;
};
constexpr bp::rule<struct literal_tag, std::unique_ptr<evaluatable>> literal_parser = "literal_parser";
constexpr auto literal_parser_action = [](auto& ctx) {
std::unique_ptr<evaluatable>& val = _val(ctx);
double& parsed_value = _attr(ctx);
val = std::make_unique<literal_evaluatable>(parsed_value);
};
constexpr auto literal_parser_def =
bp::double_[literal_parser_action];
/*
* PARENTHESIZED EXPRESSION
*/
struct parenthesized_evaluatable : evaluatable
{
explicit parenthesized_evaluatable(std::unique_ptr<evaluatable>&& e) : evaluatable_(std::move(e)) {}
double evaluate() override
{
return evaluatable_->evaluate();
}
std::unique_ptr<evaluatable> evaluatable_;
};
constexpr bp::rule<struct parenthesized_tag, std::unique_ptr<evaluatable>> parenthesized_parser = "parenthesized_parser";
constexpr auto parenthesized_action = [](auto& ctx) {
std::unique_ptr<evaluatable>& val = _val(ctx);
std::unique_ptr<evaluatable>& attr = _attr(ctx);
val = std::make_unique<parenthesized_evaluatable>(std::move(attr));
};
constexpr auto parenthesized_parser_def =
(
bp::lit('(') > expression_parser > bp::lit(')')
)[parenthesized_action];
/*
* ATOM EXPRESSION
*/
struct atom_evaluatable : evaluatable
{
explicit atom_evaluatable(std::unique_ptr<evaluatable>&& e) : evaluatable_(std::move(e)) {}
double evaluate() override
{
return evaluatable_->evaluate();
}
std::unique_ptr<evaluatable> evaluatable_;
};
constexpr bp::rule<struct atom_tag, std::unique_ptr<evaluatable>> atom_parser = "atom_parser";
constexpr auto atom_action = [](auto& ctx) {
std::unique_ptr<evaluatable>& val = _val(ctx);
std::unique_ptr<evaluatable>& attr = _attr(ctx);
val = std::make_unique<atom_evaluatable>(std::move(attr));
};
constexpr auto atom_parser_def =
(
parenthesized_parser
|
literal_parser
)[atom_action];
/*
* MULTIPLICATION EXPRESSION
*/
struct multiplication_evaluatable : evaluatable
{
multiplication_evaluatable(std::vector<std::unique_ptr<evaluatable>>&& e)
: evaluatables_(std::move(e))
{}
double evaluate() override
{
double result = 1;
for (const auto& e : evaluatables_) {
result *= e->evaluate();
}
return result;
}
std::vector<std::unique_ptr<evaluatable>> evaluatables_;
};
constexpr bp::rule<struct mult_tag, std::unique_ptr<evaluatable>> mult_parser = "mult_parser";
constexpr auto mult_parser_action = [](auto& ctx) {
std::unique_ptr<evaluatable>& val = _val(ctx);
std::vector<std::unique_ptr<evaluatable>>& operands = _attr(ctx);
val = std::make_unique<multiplication_evaluatable>(std::move(operands));
};
constexpr auto mult_parser_def =
(atom_parser % bp::lit('*'))[mult_parser_action];
/*
* ADDITION EXPRESSION
*/
struct addition_evaluatable : evaluatable
{
addition_evaluatable(std::vector<std::unique_ptr<evaluatable>>&& e)
: evaluatables_(std::move(e))
{}
double evaluate() override
{
double result = 0;
for (const auto& e : evaluatables_) {
result += e->evaluate();
}
return result;
}
std::vector<std::unique_ptr<evaluatable>> evaluatables_;
};
constexpr bp::rule<struct add_tag, std::unique_ptr<evaluatable>> add_parser = "add_parser";
constexpr auto add_parser_action = [](auto& ctx) {
std::unique_ptr<evaluatable>& val = _val(ctx);
std::vector<std::unique_ptr<evaluatable>>& operands = _attr(ctx);
val = std::make_unique<addition_evaluatable>(std::move(operands));
};
constexpr auto add_parser_def =
(mult_parser % bp::lit('+'))[add_parser_action];
constexpr auto expression_parser_action = [](auto& ctx) {
std::unique_ptr<evaluatable>& val = _val(ctx);
std::unique_ptr<evaluatable>& attr = _attr(ctx);
val = std::move(attr);
};
/*
* EXPRESSION
*/
constexpr auto expression_parser_def =
add_parser[expression_parser_action];
BOOST_PARSER_DEFINE_RULES(
literal_parser,
mult_parser,
add_parser,
expression_parser,
parenthesized_parser,
atom_parser);
}
void github_issue_312()
{
namespace bp = boost::parser;
using namespace github_issue_312_;
auto result = bp::parse("(2 + 3) + 3.1415 * 2", expression_parser, bp::blank);
BOOST_TEST(result);
BOOST_TEST(result.value()->evaluate() == (2 + 3) + 3.1415 * 2);
result = bp::parse("((2*0.1) + 33.) * (2 + 3) + 3.1415 * 2", expression_parser, bp::blank);
BOOST_TEST(result);
BOOST_TEST(result.value()->evaluate() == ((2*0.1) + 33.) * (2 + 3) + 3.1415 * 2);
}
int main()
{
@@ -615,5 +795,6 @@ int main()
github_pr_290();
github_issue_294();
github_pr_297();
github_issue_312();
return boost::report_errors();
}