mirror of
https://github.com/boostorg/parser.git
synced 2026-01-20 04:42:22 +00:00
Compare commits
73 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c54307b95c | ||
|
|
5b3f122aa7 | ||
|
|
6db68bc7f7 | ||
|
|
00fe33d2f3 | ||
|
|
bb183cf5ee | ||
|
|
885595f7bd | ||
|
|
6826f957a1 | ||
|
|
647cec6683 | ||
|
|
c2ddd6e116 | ||
|
|
f7246de9db | ||
|
|
703a8afafe | ||
|
|
0eacce6080 | ||
|
|
5e61ba4e9e | ||
|
|
dc6144eeb4 | ||
|
|
d873d7ea80 | ||
|
|
1f5303c756 | ||
|
|
41e891dc95 | ||
|
|
159472ac6e | ||
|
|
bfa3e33372 | ||
|
|
8d7a64f7fe | ||
|
|
8c23054e07 | ||
|
|
11a5d9a872 | ||
|
|
d241bd7853 | ||
|
|
086241cbd9 | ||
|
|
e3a3cc8bf2 | ||
|
|
f789199743 | ||
|
|
f20c4cfb02 | ||
|
|
fcbc53ddce | ||
|
|
fed0a883ad | ||
|
|
bfc61fa963 | ||
|
|
68c306bf66 | ||
|
|
d5d080b9f2 | ||
|
|
03341ba32d | ||
|
|
7e69b27d7c | ||
|
|
17d76bc158 | ||
|
|
050b9ba800 | ||
|
|
125f12407b | ||
|
|
e4ba7c7a17 | ||
|
|
9a138a20f6 | ||
|
|
c32d594d64 | ||
|
|
c674e94c3d | ||
|
|
84ee288b02 | ||
|
|
39faa9ddbe | ||
|
|
b2927abc6c | ||
|
|
5d6d2f7b84 | ||
|
|
fd6c56df1b | ||
|
|
af41e6a7c2 | ||
|
|
0b93a586f1 | ||
|
|
ed9a06123b | ||
|
|
8ff46f394a | ||
|
|
8c9ad7bdb3 | ||
|
|
d8abe8f29e | ||
|
|
810adb43f6 | ||
|
|
5788fb6967 | ||
|
|
ec7df8a0af | ||
|
|
a93a1d2647 | ||
|
|
927f35f115 | ||
|
|
87617fdec0 | ||
|
|
ead639e630 | ||
|
|
a3ca1193b2 | ||
|
|
07153117ff | ||
|
|
6414f99e04 | ||
|
|
78bc141d5f | ||
|
|
b253d9ca53 | ||
|
|
0a34acc42a | ||
|
|
56c81c0b57 | ||
|
|
821d1d4c08 | ||
|
|
57cdd78210 | ||
|
|
3993efb692 | ||
|
|
74bc8fc1bb | ||
|
|
b42b052df4 | ||
|
|
42c9d82419 | ||
|
|
958ac38256 |
@@ -1,4 +1,4 @@
|
|||||||
name: macos-13 - Clang 14
|
name: macos-15 - Clang
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -14,9 +14,9 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
cxx_std: [17]
|
cxx_std: [17, 20]
|
||||||
|
|
||||||
runs-on: macos-13
|
runs-on: macos-15
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
4
.github/workflows/ubuntu.yml
vendored
4
.github/workflows/ubuntu.yml
vendored
@@ -18,10 +18,6 @@ jobs:
|
|||||||
compiler_version: [g++-10, g++-11]
|
compiler_version: [g++-10, g++-11]
|
||||||
cxx_std: [17, 20]
|
cxx_std: [17, 20]
|
||||||
os: [ubuntu-22.04]
|
os: [ubuntu-22.04]
|
||||||
include:
|
|
||||||
- compiler_version: g++-9
|
|
||||||
cxx_std: 17
|
|
||||||
os: ubuntu-20.04
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ Master status:
|
|||||||
|
|
||||||
[](https://github.com/tzlaine/parser/actions/workflows/windows.yml)
|
[](https://github.com/tzlaine/parser/actions/workflows/windows.yml)
|
||||||
|
|
||||||
[](https://github.com/tzlaine/parser/actions/workflows/macos-12.yml)
|
[](https://github.com/tzlaine/parser/actions/workflows/macos-13.yml)
|
||||||
|
|
||||||
Develop status:
|
Develop status:
|
||||||
|
|
||||||
@@ -67,6 +67,6 @@ Develop status:
|
|||||||
|
|
||||||
[](https://github.com/tzlaine/parser/actions/workflows/windows.yml)
|
[](https://github.com/tzlaine/parser/actions/workflows/windows.yml)
|
||||||
|
|
||||||
[](https://github.com/tzlaine/parser/actions/workflows/macos-12.yml)
|
[](https://github.com/tzlaine/parser/actions/workflows/macos-13.yml)
|
||||||
|
|
||||||
[](LICENSE_1_0.txt)
|
[](LICENSE_1_0.txt)
|
||||||
|
|||||||
24
build.jam
Normal file
24
build.jam
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Copyright René Ferdinand Rivera Morell 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)
|
||||||
|
|
||||||
|
require-b2 5.2 ;
|
||||||
|
|
||||||
|
constant boost_dependencies :
|
||||||
|
/boost/assert//boost_assert
|
||||||
|
/boost/charconv//boost_charconv
|
||||||
|
/boost/hana//boost_hana
|
||||||
|
/boost/type_index//boost_type_index ;
|
||||||
|
|
||||||
|
project /boost/parser
|
||||||
|
;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
[ alias boost_parser : : :
|
||||||
|
: <library>$(boost_dependencies) <include>include ]
|
||||||
|
[ alias all : boost_parser test ]
|
||||||
|
;
|
||||||
|
|
||||||
|
call-if : boost-library parser
|
||||||
|
;
|
||||||
@@ -39,7 +39,7 @@ rule run_doxygen ( files * : name : expand ? )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
run_doxygen [ glob $(here)/../../../boost/parser/*.hpp : $(here)/../../../boost/parser/concepts.hpp ] : "Headers" ;
|
run_doxygen [ glob $(here)/../include/boost/parser/*.hpp : $(here)/../include/boost/parser/concepts.hpp ] : "Headers" ;
|
||||||
|
|
||||||
install images_standalone : [ glob *.png ] : <location>html/parser/img ;
|
install images_standalone : [ glob *.png ] : <location>html/parser/img ;
|
||||||
explicit images_standalone ;
|
explicit images_standalone ;
|
||||||
|
|||||||
@@ -110,6 +110,7 @@
|
|||||||
|
|
||||||
|
|
||||||
[def _std_str_ `std::string`]
|
[def _std_str_ `std::string`]
|
||||||
|
[def _std_strs_ `std::string`s]
|
||||||
[def _std_vec_char_ `std::vector<char>`]
|
[def _std_vec_char_ `std::vector<char>`]
|
||||||
[def _std_vec_char32_ `std::vector<char32_t>`]
|
[def _std_vec_char32_ `std::vector<char32_t>`]
|
||||||
|
|
||||||
@@ -201,6 +202,7 @@
|
|||||||
[def _merge_ [globalref boost::parser::merge `merge[]`]]
|
[def _merge_ [globalref boost::parser::merge `merge[]`]]
|
||||||
[def _sep_ [globalref boost::parser::separate `separate[]`]]
|
[def _sep_ [globalref boost::parser::separate `separate[]`]]
|
||||||
[def _transform_ [globalref boost::parser::transform `transform(f)[]`]]
|
[def _transform_ [globalref boost::parser::transform `transform(f)[]`]]
|
||||||
|
[def _delimiter_ [globalref boost::parser::delimiter `delimiter(p)[]`]]
|
||||||
|
|
||||||
[def _omit_np_ [globalref boost::parser::omit `omit`]]
|
[def _omit_np_ [globalref boost::parser::omit `omit`]]
|
||||||
[def _raw_np_ [globalref boost::parser::raw `raw`]]
|
[def _raw_np_ [globalref boost::parser::raw `raw`]]
|
||||||
@@ -211,11 +213,13 @@
|
|||||||
[def _merge_np_ [globalref boost::parser::merge `merge`]]
|
[def _merge_np_ [globalref boost::parser::merge `merge`]]
|
||||||
[def _sep_np_ [globalref boost::parser::separate `separate`]]
|
[def _sep_np_ [globalref boost::parser::separate `separate`]]
|
||||||
[def _transform_np_ [globalref boost::parser::transform `transform`]]
|
[def _transform_np_ [globalref boost::parser::transform `transform`]]
|
||||||
|
[def _delimiter_np_ [globalref boost::parser::delimiter `delimiter`]]
|
||||||
|
|
||||||
[def _blank_ [globalref boost::parser::blank `blank`]]
|
[def _blank_ [globalref boost::parser::blank `blank`]]
|
||||||
[def _control_ [globalref boost::parser::control `control`]]
|
[def _control_ [globalref boost::parser::control `control`]]
|
||||||
[def _digit_ [globalref boost::parser::digit `digit`]]
|
[def _digit_ [globalref boost::parser::digit `digit`]]
|
||||||
[def _punct_ [globalref boost::parser::punct `punct`]]
|
[def _punct_ [globalref boost::parser::punct `punct`]]
|
||||||
|
[def _symb_ [globalref boost::parser::symb `symb`]]
|
||||||
[def _hex_digit_ [globalref boost::parser::hex_digit `hex_digit`]]
|
[def _hex_digit_ [globalref boost::parser::hex_digit `hex_digit`]]
|
||||||
[def _lower_ [globalref boost::parser::lower `lower`]]
|
[def _lower_ [globalref boost::parser::lower `lower`]]
|
||||||
[def _upper_ [globalref boost::parser::upper `upper`]]
|
[def _upper_ [globalref boost::parser::upper `upper`]]
|
||||||
@@ -239,6 +243,7 @@
|
|||||||
[def _more_about_rules_ [link boost_parser.tutorial.more_about_rules More About Rules]]
|
[def _more_about_rules_ [link boost_parser.tutorial.more_about_rules More About Rules]]
|
||||||
[def _unicode_ [link boost_parser.tutorial.unicode_support Unicode Support]]
|
[def _unicode_ [link boost_parser.tutorial.unicode_support Unicode Support]]
|
||||||
[def _concepts_ [link boost_parser.concepts Concepts]]
|
[def _concepts_ [link boost_parser.concepts Concepts]]
|
||||||
|
[def _seq_parser_example_ [link boost_parser.tutorial.attribute_generation.a_sequence_parser_attribute_example A sequence parser attribute example]]
|
||||||
[def _ex_json_ [link boost_parser.extended_examples.parsing_json Parsing JSON]]
|
[def _ex_json_ [link boost_parser.extended_examples.parsing_json Parsing JSON]]
|
||||||
[def _ex_cb_json_ [link boost_parser.extended_examples.parsing_json_with_callbacks Parsing JSON With Callbacks]]
|
[def _ex_cb_json_ [link boost_parser.extended_examples.parsing_json_with_callbacks Parsing JSON With Callbacks]]
|
||||||
[def _rationale_ [link boost_parser.rationale Rationale]]
|
[def _rationale_ [link boost_parser.rationale Rationale]]
|
||||||
|
|||||||
2145
doc/parser_reference.xml
Normal file
2145
doc/parser_reference.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -202,7 +202,7 @@ It has a different API, and other code that operates on text expects a string
|
|||||||
instead of some other container. Arrays of characters are already considered
|
instead of some other container. Arrays of characters are already considered
|
||||||
special by the standard library and common practice in C++.
|
special by the standard library and common practice in C++.
|
||||||
|
|
||||||
Second, When you write a parser that parses multiple characters in a row, you
|
Second, when you write a parser that parses multiple characters in a row, you
|
||||||
are typically trying to produce a string attribute, rather than a few
|
are typically trying to produce a string attribute, rather than a few
|
||||||
individual character values. When you use multiple non-character parsers in a
|
individual character values. When you use multiple non-character parsers in a
|
||||||
row, you are typically trying to produce multiple values. For instance:
|
row, you are typically trying to produce multiple values. For instance:
|
||||||
@@ -217,7 +217,7 @@ I've rarely written a parser like `parser_2` and wanted a
|
|||||||
`std::vector<std::string>`.
|
`std::vector<std::string>`.
|
||||||
|
|
||||||
_Parser_ therefore makes the common case the default behavior, and provides
|
_Parser_ therefore makes the common case the default behavior, and provides
|
||||||
you with the _merge_ and _sep_ directives to let you opt-in to generating the
|
you with the _merge_ and _sep_ directives to let you opt in to generating the
|
||||||
less-common attributes.
|
less-common attributes.
|
||||||
|
|
||||||
[heading Attribute compatibility rules are more strict than in Spirit]
|
[heading Attribute compatibility rules are more strict than in Spirit]
|
||||||
@@ -261,13 +261,12 @@ Also, Spirit-style looseness is more complicated than `parser` above
|
|||||||
indicates. Remember, `int_ | eps` and `-int_` are supposed to be semantically
|
indicates. Remember, `int_ | eps` and `-int_` are supposed to be semantically
|
||||||
equivalent. To do otherwise this would be a profound violation of the
|
equivalent. To do otherwise this would be a profound violation of the
|
||||||
principle of least surprise. So, if they're equivalent, we would need to
|
principle of least surprise. So, if they're equivalent, we would need to
|
||||||
apply the same rule to `int_ | eps`. Also, we would probably need to apply it
|
apply the same rule to `int_ | eps`. This is a lot to remember, and this is
|
||||||
to `if_(cond)[int_]`, which is also a `std::optional<int>`. This is a lot to
|
complicated to implement and maintain.
|
||||||
remember, and this is complicated to implement and maintain.
|
|
||||||
|
|
||||||
I've been using Spirit 1 and later Spirit 2 since they were released. I did
|
I've been using Spirit 1 and later Spirit 2 since they were released. I did
|
||||||
not know about the particular looseness discussed here; a user pointed it out
|
not know about the particular looseness discussed here; a user pointed it out
|
||||||
on Github. In many years of using these libraries, I never fully learned all
|
on GitHub. In many years of using these libraries, I never fully learned all
|
||||||
the attribute-compatibility rules, and was often surprised by them.
|
the attribute-compatibility rules, and was often surprised by them.
|
||||||
|
|
||||||
Having a small set of rules that the user can internalize is vital; if the
|
Having a small set of rules that the user can internalize is vital; if the
|
||||||
@@ -299,7 +298,7 @@ that it succeeds (if it had failed, it would have cleared its attribute). It
|
|||||||
does not know that there is nothing after it that could continue the parse,
|
does not know that there is nothing after it that could continue the parse,
|
||||||
nor that it is being used in to do a full parse. So, the over-all parse
|
nor that it is being used in to do a full parse. So, the over-all parse
|
||||||
fails, but the part of the parse that fills in the out-param attribute does
|
fails, but the part of the parse that fills in the out-param attribute does
|
||||||
not know do clear its attribute.
|
not know to clear its attribute.
|
||||||
|
|
||||||
This is why the explicit clearing behavior happens at the end of _p_. This is
|
This is why the explicit clearing behavior happens at the end of _p_. This is
|
||||||
not without its downsides, though. Consider this.
|
not without its downsides, though. Consider this.
|
||||||
@@ -315,7 +314,7 @@ not without its downsides, though. Consider this.
|
|||||||
Here, the explicit clearing replaces the previous value of `3`, even though
|
Here, the explicit clearing replaces the previous value of `3`, even though
|
||||||
the parser never touched the value! Destroying users' variables' state
|
the parser never touched the value! Destroying users' variables' state
|
||||||
without need may seem like a bad idea, but consider the alternative _emdash_
|
without need may seem like a bad idea, but consider the alternative _emdash_
|
||||||
In the previous example, we had spurious values left in the out-param
|
in the previous example, we had spurious values left in the out-param
|
||||||
attribute. Here, without clearing, we would have had a value left in the
|
attribute. Here, without clearing, we would have had a value left in the
|
||||||
out-param attribute, not because it was a partial result of the parse, but
|
out-param attribute, not because it was a partial result of the parse, but
|
||||||
because the parse never touched it. This is certain to be confusing, or at
|
because the parse never touched it. This is certain to be confusing, or at
|
||||||
@@ -325,4 +324,24 @@ always equal to `A()` if the parser fails. It is equal to whatever the parser
|
|||||||
sets it to _emdash_ or its previous value, if the parser does not mutate it
|
sets it to _emdash_ or its previous value, if the parser does not mutate it
|
||||||
_emdash_ if the parse succeeds.
|
_emdash_ if the parse succeeds.
|
||||||
|
|
||||||
|
[heading There are no _Spirit_-style character class parsers]
|
||||||
|
|
||||||
|
_Spirit_ has these character class parsers that recognize the same set of
|
||||||
|
characters as the C standard library's character class functions. For
|
||||||
|
instance, _Spirit_'s `alnum` recognizes the characters recognized by
|
||||||
|
`std::isalnum()`, its `punct` recognizes the characters recognized by
|
||||||
|
`std::ispunct()`, etc.
|
||||||
|
|
||||||
|
The problem with this is that those `std::is*()` functions are badly broken.
|
||||||
|
They do not even work correctly for ASCII values. This is because they use
|
||||||
|
the C standard library's locale mechanism, which can be set to anything the
|
||||||
|
current platform supports, and can be set by any code anywhere in your
|
||||||
|
program; the locale is mutable global state. So, even if you use the default
|
||||||
|
C locale in your program, if you link against a library that sets the locale
|
||||||
|
to something that breaks ASCII character recognition (an EBCDIC locale, for
|
||||||
|
instance), your program is now incorrect, regardless of the code you wrote.
|
||||||
|
|
||||||
|
For this reason, I firmly believe that no one, anywhere, should use those C
|
||||||
|
functions in production code, and I am not supporting their use via _Parser_.
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ the input they match unless otherwise stated in the table below.]
|
|||||||
[[ _attr_np_`(arg0)` ]
|
[[ _attr_np_`(arg0)` ]
|
||||||
[ Always matches, and consumes no input. Generates the attribute `_RES_np_(arg0)`. ]
|
[ Always matches, and consumes no input. Generates the attribute `_RES_np_(arg0)`. ]
|
||||||
[ `decltype(_RES_np_(arg0))`. ]
|
[ `decltype(_RES_np_(arg0))`. ]
|
||||||
[ An important use case for `_attr_` is to provide a default attribute value as a trailing alternative. For instance, an *optional* comma-delmited list is: `int_ % ',' | attr(std::vector<int>)`. Without the "`| attr(...)`", at least one `int_` match would be required. ]]
|
[ An important use case for `_attr_` is to provide a default attribute value as a trailing alternative. For instance, an *optional* comma-delimited list is: `int_ % ',' | attr(std::vector<int>)`. Without the "`| attr(...)`", at least one `int_` match would be required. ]]
|
||||||
|
|
||||||
[[ _ch_ ]
|
[[ _ch_ ]
|
||||||
[ Matches any single code point. ]
|
[ Matches any single code point. ]
|
||||||
@@ -132,8 +132,13 @@ the input they match unless otherwise stated in the table below.]
|
|||||||
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
|
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
|
||||||
[]]
|
[]]
|
||||||
|
|
||||||
|
[[ `_symb_` ]
|
||||||
|
[ Matches a single symbol code point. ]
|
||||||
|
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
|
||||||
|
[]]
|
||||||
|
|
||||||
[[ `_hex_digit_` ]
|
[[ `_hex_digit_` ]
|
||||||
[ Matches a single hexidecimal digit code point. ]
|
[ Matches a single hexadecimal digit code point. ]
|
||||||
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
|
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
|
||||||
[]]
|
[]]
|
||||||
|
|
||||||
@@ -225,7 +230,7 @@ the input they match unless otherwise stated in the table below.]
|
|||||||
[[ _ui_ ]
|
[[ _ui_ ]
|
||||||
[ Matches an unsigned integral value. ]
|
[ Matches an unsigned integral value. ]
|
||||||
[ `unsigned int` ]
|
[ `unsigned int` ]
|
||||||
[]]
|
[ To specify a base/radix of `N`, use _ui_`.base<N>()`. To specify exactly `D` digits, use _ui_`.digits<D>()`. To specify a minimum of `LO` digits and a maximum of `HI` digits, use _ui_`.digits<LO, HI>()`. These calls can be chained, as in _ui_`.base<2>().digits<8>()`. ]]
|
||||||
|
|
||||||
[[ `_ui_(arg0)` ]
|
[[ `_ui_(arg0)` ]
|
||||||
[ Matches exactly the unsigned integral value `_RES_np_(arg0)`. ]
|
[ Matches exactly the unsigned integral value `_RES_np_(arg0)`. ]
|
||||||
@@ -265,7 +270,7 @@ the input they match unless otherwise stated in the table below.]
|
|||||||
[[ _i_ ]
|
[[ _i_ ]
|
||||||
[ Matches a signed integral value. ]
|
[ Matches a signed integral value. ]
|
||||||
[ `int` ]
|
[ `int` ]
|
||||||
[]]
|
[ To specify a base/radix of `N`, use _i_`.base<N>()`. To specify exactly `D` digits, use _i_`.digits<D>()`. To specify a minimum of `LO` digits and a maximum of `HI` digits, use _i_`.digits<LO, HI>()`. These calls can be chained, as in _i_`.base<2>().digits<8>()`. ]]
|
||||||
|
|
||||||
[[ `_i_(arg0)` ]
|
[[ `_i_(arg0)` ]
|
||||||
[ Matches exactly the signed integral value `_RES_np_(arg0)`. ]
|
[ Matches exactly the signed integral value `_RES_np_(arg0)`. ]
|
||||||
@@ -314,7 +319,7 @@ the input they match unless otherwise stated in the table below.]
|
|||||||
|
|
||||||
[[ `_if_np_(pred)[p]` ]
|
[[ `_if_np_(pred)[p]` ]
|
||||||
[ Equivalent to `_e_(pred) >> p`. ]
|
[ Equivalent to `_e_(pred) >> p`. ]
|
||||||
[ `std::optional<_ATTR_np_(p)>` ]
|
[ `_ATTR_np_(p)` ]
|
||||||
[ It is an error to write `_if_np_(pred)`. That is, it is an error to omit the conditionally matched parser `p`. ]]
|
[ It is an error to write `_if_np_(pred)`. That is, it is an error to omit the conditionally matched parser `p`. ]]
|
||||||
|
|
||||||
[[ `_sw_np_(arg0)(arg1, p1)(arg2, p2) ...` ]
|
[[ `_sw_np_(arg0)(arg1, p1)(arg2, p2) ...` ]
|
||||||
@@ -323,9 +328,9 @@ the input they match unless otherwise stated in the table below.]
|
|||||||
[ It is an error to write `_sw_np_(arg0)`. That is, it is an error to omit the conditionally matched parsers `p1`, `p2`, .... ]]
|
[ It is an error to write `_sw_np_(arg0)`. That is, it is an error to omit the conditionally matched parsers `p1`, `p2`, .... ]]
|
||||||
|
|
||||||
[[ _symbols_t_ ]
|
[[ _symbols_t_ ]
|
||||||
[ _symbols_ is an associative container of key, value pairs. Each key is a _std_str_ and each value has type `T`. In the Unicode parsing path, the strings are considered to be UTF-8 encoded; in the non-Unicode path, no encoding is assumed. _symbols_ Matches the longest prefix `pre` of the input that is equal to one of the keys `k`. If the length `len` of `pre` is zero, and there is no zero-length key, it does not match the input. If `len` is positive, the generated attribute is the value associated with `k`.]
|
[ _symbols_ is an associative container of key, value pairs. Each key is a _std_str_ and each value has type `T`. In the Unicode parsing path, the strings are considered to be UTF-8 encoded; in the non-Unicode path, no encoding is assumed. _symbols_ matches the longest prefix `pre` of the input that is equal to one of the keys `k`. If the length `len` of `pre` is zero, and there is no zero-length key, it does not match the input. If `len` is positive, the generated attribute is the value associated with `k`.]
|
||||||
[ `T` ]
|
[ `T` ]
|
||||||
[ Unlike the other entries in this table, _symbols_ is a type, not an object. ]]
|
[ Unlike the other entries in this table, _symbols_ is a type, not an object. Inside of skippers, all _symbols_ will appear empty. ]]
|
||||||
|
|
||||||
[[ _quot_str_ ]
|
[[ _quot_str_ ]
|
||||||
[ Matches `'"'`, followed by zero or more characters, followed by `'"'`. ]
|
[ Matches `'"'`, followed by zero or more characters, followed by `'"'`. ]
|
||||||
@@ -363,7 +368,7 @@ character type (or use _attr_ to do so).]
|
|||||||
]
|
]
|
||||||
|
|
||||||
[template table_combining_operations
|
[template table_combining_operations
|
||||||
Here are all the operator overloaded for parsers. In the tables below:
|
Here are all the operators overloaded for parsers. In the tables below:
|
||||||
|
|
||||||
* `c` is a character of type `char` or `char32_t`;
|
* `c` is a character of type `char` or `char32_t`;
|
||||||
|
|
||||||
@@ -385,16 +390,16 @@ consume the input they match unless otherwise stated in the table below.]
|
|||||||
[[`*p`] [ Parses using `p` repeatedly until `p` no longer matches; always matches. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`] [ Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `*_e_` (this applies to unconditional _e_ only). ]]
|
[[`*p`] [ Parses using `p` repeatedly until `p` no longer matches; always matches. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`] [ Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `*_e_` (this applies to unconditional _e_ only). ]]
|
||||||
[[`+p`] [ Parses using `p` repeatedly until `p` no longer matches; matches iff `p` matches at least once. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`] [ Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `+_e_` (this applies to unconditional _e_ only). ]]
|
[[`+p`] [ Parses using `p` repeatedly until `p` no longer matches; matches iff `p` matches at least once. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`] [ Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `+_e_` (this applies to unconditional _e_ only). ]]
|
||||||
[[`-p`] [ Equivalent to `p | _e_`. ] [`std::optional<_ATTR_np_(p)>`] []]
|
[[`-p`] [ Equivalent to `p | _e_`. ] [`std::optional<_ATTR_np_(p)>`] []]
|
||||||
[[`p1 >> p2`] [ Matches iff `p1` matches and then `p2` matches. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `>>` is associative; `p1 >> p2 >> p3`, `(p1 >> p2) >> p3`, and `p1 >> (p2 >> p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes; see _attr_gen_ for the full rules. ]]
|
[[`p1 >> p2`] [ Matches iff `p1` matches and then `p2` matches. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `>>` is associative; `p1 >> p2 >> p3`, `(p1 >> p2) >> p3`, and `p1 >> (p2 >> p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes; see _attr_gen_ for the full rules. Differs in precedence from `operator>`. ]]
|
||||||
[[`p >> c`] [ Equivalent to `p >> lit(c)`. ] [`_ATTR_np_(p)`] []]
|
[[`p >> c`] [ Equivalent to `p >> lit(c)`. ] [`_ATTR_np_(p)`] []]
|
||||||
[[`p >> r`] [ Equivalent to `p >> lit(r)`. ] [`_ATTR_np_(p)`] []]
|
[[`p >> r`] [ Equivalent to `p >> lit(r)`. ] [`_ATTR_np_(p)`] []]
|
||||||
[[`p1 > p2`] [ Matches iff `p1` matches and then `p2` matches. No back-tracking is allowed after `p1` matches; if `p1` matches but then `p2` does not, the top-level parse fails. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `>` is associative; `p1 > p2 > p3`, `(p1 > p2) > p3`, and `p1 > (p2 > p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes; see _attr_gen_ for the full rules. ]]
|
[[`p1 > p2`] [ Matches iff `p1` matches and then `p2` matches. No back-tracking is allowed after `p1` matches; if `p1` matches but then `p2` does not, the top-level parse fails. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `>` is associative; `p1 > p2 > p3`, `(p1 > p2) > p3`, and `p1 > (p2 > p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes; see _attr_gen_ for the full rules. Differs in precedence from `operator>>`. ]]
|
||||||
[[`p > c`] [ Equivalent to `p > lit(c)`. ] [`_ATTR_np_(p)`] []]
|
[[`p > c`] [ Equivalent to `p > lit(c)`. ] [`_ATTR_np_(p)`] []]
|
||||||
[[`p > r`] [ Equivalent to `p > lit(r)`. ] [`_ATTR_np_(p)`] []]
|
[[`p > r`] [ Equivalent to `p > lit(r)`. ] [`_ATTR_np_(p)`] []]
|
||||||
[[`p1 | p2`] [ Matches iff either `p1` matches or `p2` matches. ] [`std::variant<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `|` is associative; `p1 | p2 | p3`, `(p1 | p2) | p3`, and `p1 | (p2 | p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes, and where the attribute types are different; see _attr_gen_ for the full rules. ]]
|
[[`p1 | p2`] [ Matches iff either `p1` matches or `p2` matches. ] [`std::variant<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `|` is associative; `p1 | p2 | p3`, `(p1 | p2) | p3`, and `p1 | (p2 | p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes, and where the attribute types are different; see _attr_gen_ for the full rules. ]]
|
||||||
[[`p | c`] [ Equivalent to `p | lit(c)`. ] [`_ATTR_np_(p)`] []]
|
[[`p | c`] [ Equivalent to `p | lit(c)`. ] [`_ATTR_np_(p)`] []]
|
||||||
[[`p | r`] [ Equivalent to `p | lit(r)`. ] [`_ATTR_np_(p)`] []]
|
[[`p | r`] [ Equivalent to `p | lit(r)`. ] [`_ATTR_np_(p)`] []]
|
||||||
[[`p1 || p2`] [ Matches iff `p1` matches and `p2` matches, regardless of the order they match in. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`] [ `||` is associative; `p1 || p2 || p3`, `(p1 || p2) || p3`, and `p1 || (p2 || p3)` are all equivalent. It is an error to include a _e_ (conditional or non-conditional) in an `operator||` expression. Though the parsers are matched in any order, the attribute elements are always in the order written in the `operator||` expression. ]]
|
[[`p1 || p2`] [ Matches iff `p1` matches and `p2` matches, regardless of the order they match in. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`] [ `||` is associative; `p1 || p2 || p3`, `(p1 || p2) || p3`, and `p1 || (p2 || p3)` are all equivalent. It is an error to include an _e_ (conditional or non-conditional) in an `operator||` expression. Though the parsers are matched in any order, the attribute elements are always in the order written in the `operator||` expression. ]]
|
||||||
[[`p1 - p2`] [ Equivalent to `!p2 >> p1`. ] [`_ATTR_np_(p1)`] []]
|
[[`p1 - p2`] [ Equivalent to `!p2 >> p1`. ] [`_ATTR_np_(p1)`] []]
|
||||||
[[`p - c`] [ Equivalent to `p - lit(c)`. ] [`_ATTR_np_(p)`] []]
|
[[`p - c`] [ Equivalent to `p - lit(c)`. ] [`_ATTR_np_(p)`] []]
|
||||||
[[`p - r`] [ Equivalent to `p - lit(r)`. ] [`_ATTR_np_(p)`] []]
|
[[`p - r`] [ Equivalent to `p - lit(r)`. ] [`_ATTR_np_(p)`] []]
|
||||||
@@ -424,6 +429,15 @@ because, for any parser `p`, `_e_ | p` is equivalent to _e_, since _e_ always
|
|||||||
matches. This is not true for _e_ parameterized with a condition. For any
|
matches. This is not true for _e_ parameterized with a condition. For any
|
||||||
condition `cond`, `_e_(cond)` is allowed to appear anywhere within an
|
condition `cond`, `_e_(cond)` is allowed to appear anywhere within an
|
||||||
alternative parser.
|
alternative parser.
|
||||||
|
|
||||||
|
[important The C++ operators `>` and `>>` have different precedences. This
|
||||||
|
will sometimes come up in warnings from your compiler. No matter how you do
|
||||||
|
or do not parenthesize chains of parsers separated by `>` and `>>`, the
|
||||||
|
resulting expression evaluates the same. Feel free to add parentheses if your
|
||||||
|
compiler complains. More broadly, keep the C++ operator precedence rules in
|
||||||
|
mind when writing your parsers _emdash_ the simplest thing to write may not
|
||||||
|
have your intended semantics. ]
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[template table_attribute_generation
|
[template table_attribute_generation
|
||||||
@@ -491,7 +505,7 @@ attribute type is `char32_t`:
|
|||||||
static_assert(std::is_same_v<decltype(result), std::optional<char32_t>>));
|
static_assert(std::is_same_v<decltype(result), std::optional<char32_t>>));
|
||||||
|
|
||||||
The good news is that usually you don't parse characters individually. When
|
The good news is that usually you don't parse characters individually. When
|
||||||
you parse with _ch_, you usually parse repetition of then, which will produce
|
you parse with _ch_, you usually parse repetition of them, which will produce
|
||||||
a _std_str_, regardless of whether you're in Unicode parsing mode or not. If
|
a _std_str_, regardless of whether you're in Unicode parsing mode or not. If
|
||||||
you do need to parse individual characters, and want to lock down their
|
you do need to parse individual characters, and want to lock down their
|
||||||
attribute type, you can use _cp_ and/or _cu_ to enforce a non-polymorphic
|
attribute type, you can use _cp_ and/or _cu_ to enforce a non-polymorphic
|
||||||
@@ -537,13 +551,13 @@ tables below:
|
|||||||
[[`p1 || p2`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`]]
|
[[`p1 || p2`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`]]
|
||||||
[[`p1 || p2 || p3`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
|
[[`p1 || p2 || p3`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
|
||||||
|
|
||||||
[[`p1 % p2`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p1)>`]]
|
[[`p1 % p2`] [`std::string` if `_ATTR_np_(p1)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p1)>`]]
|
||||||
|
|
||||||
[[`p[a]`] [None.]]
|
[[`p[a]`] [None.]]
|
||||||
|
|
||||||
[[`_rpt_np_(arg0)[p]`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
|
[[`_rpt_np_(arg0)[p]`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
|
||||||
[[`_rpt_np_(arg0, arg1)[p]`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
|
[[`_rpt_np_(arg0, arg1)[p]`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
|
||||||
[[`_if_np_(pred)[p]`] [`std::optional<_ATTR_np_(p)>`]]
|
[[`_if_np_(pred)[p]`] [`_ATTR_np_(p)`]]
|
||||||
[[`_sw_np_(arg0)(arg1, p1)(arg2, p2)...`]
|
[[`_sw_np_(arg0)(arg1, p1)(arg2, p2)...`]
|
||||||
[`std::variant<_ATTR_np_(p1), _ATTR_np_(p2), ...>`]]
|
[`std::variant<_ATTR_np_(p1), _ATTR_np_(p2), ...>`]]
|
||||||
]
|
]
|
||||||
|
|||||||
271
doc/tutorial.qbk
271
doc/tutorial.qbk
@@ -13,7 +13,7 @@ A /semantic action/ is an arbitrary bit of logic associated with a parser,
|
|||||||
that is only executed when the parser matches.
|
that is only executed when the parser matches.
|
||||||
|
|
||||||
Simpler parsers can be combined to form more complex parsers. Given some
|
Simpler parsers can be combined to form more complex parsers. Given some
|
||||||
combining operation `C`, and parsers `P0`, `P1`, ... `PN`, `C(P0, P1, ... PN)`
|
combining operation `C`, and parsers `P0`, `P1`, ..., `PN`, `C(P0, P1, ..., PN)`
|
||||||
creates a new parser `Q`. This creates a /parse tree/. `Q` is the parent of
|
creates a new parser `Q`. This creates a /parse tree/. `Q` is the parent of
|
||||||
`P1`, `P2` is the child of `Q`, etc. The parsers are applied in the top-down
|
`P1`, `P2` is the child of `Q`, etc. The parsers are applied in the top-down
|
||||||
fashion implied by this topology. When you use `Q` to parse a string, it
|
fashion implied by this topology. When you use `Q` to parse a string, it
|
||||||
@@ -65,7 +65,7 @@ subparsers does.
|
|||||||
|
|
||||||
Finally, there is a /permutation parser/; it is created using `operator||`,
|
Finally, there is a /permutation parser/; it is created using `operator||`,
|
||||||
as in `p1 || p2 || p3`. A permutation parser tries to match all of its
|
as in `p1 || p2 || p3`. A permutation parser tries to match all of its
|
||||||
subparsers to the input, in any order. So the parser `p1 || p2 || p3` is equivalent to `(p1 >> p2 >> p3) | (p1 >> p3 >> p2) | (p2 >> p1 >> p3) | (p2 >> p3 >> p1) | (p3 >> p1 >> p2) | (p3 >> p2 >> p1)`. Hopefully its terseness is self-explanatory. It matches the
|
subparsers to the input, in any order. So the parser `p1 || p2 || p3` is equivalent to `(p1 >> p2 >> p3) | (p1 >> p3 >> p2) | (p2 >> p1 >> p3) | (p2 >> p3 >> p1) | (p3 >> p1 >> p2) | (p3 >> p2 >> p1)`. Hopefully the advantage of its terseness is self-explanatory. It matches the
|
||||||
input iff all of its subparsers do, regardless of the order they match in.
|
input iff all of its subparsers do, regardless of the order they match in.
|
||||||
|
|
||||||
_Parser_ parsers each have an /attribute/ associated with them, or explicitly
|
_Parser_ parsers each have an /attribute/ associated with them, or explicitly
|
||||||
@@ -113,7 +113,7 @@ Also, just ignore for now the fact that _Parser_ somehow figured out that the
|
|||||||
result type of the `*bp::char_` parser is a _std_str_. There are clear rules
|
result type of the `*bp::char_` parser is a _std_str_. There are clear rules
|
||||||
for this that we'll cover later.
|
for this that we'll cover later.
|
||||||
|
|
||||||
The effects of this call to _p_ is not very interesting _emdash_ since the
|
The effects of this call to _p_ are not very interesting _emdash_ since the
|
||||||
parser we gave it cannot ever fail, and because we're placing the output in
|
parser we gave it cannot ever fail, and because we're placing the output in
|
||||||
the same type as the input, it just copies the contents of `input` to
|
the same type as the input, it just copies the contents of `input` to
|
||||||
`result`.
|
`result`.
|
||||||
@@ -403,7 +403,7 @@ Copying the entire context when mutating the context is therefore fast. The
|
|||||||
context does no memory allocation.
|
context does no memory allocation.
|
||||||
|
|
||||||
[tip All these functions that take the parse context as their first parameter
|
[tip All these functions that take the parse context as their first parameter
|
||||||
will find by found by Argument-Dependent Lookup. You will probably never need
|
will be found by Argument-Dependent Lookup. You will probably never need
|
||||||
to qualify them with `boost::parser::`.]
|
to qualify them with `boost::parser::`.]
|
||||||
|
|
||||||
[heading Accessors for data that are always available]
|
[heading Accessors for data that are always available]
|
||||||
@@ -414,7 +414,7 @@ underscore.
|
|||||||
|
|
||||||
[heading _pass_]
|
[heading _pass_]
|
||||||
|
|
||||||
_pass_ returns a reference to a `bool` indicating the success of failure of
|
_pass_ returns a reference to a `bool` indicating the success or failure of
|
||||||
the current parse. This can be used to force the current parse to pass or
|
the current parse. This can be used to force the current parse to pass or
|
||||||
fail:
|
fail:
|
||||||
|
|
||||||
@@ -584,7 +584,7 @@ things:
|
|||||||
|
|
||||||
* This rule object itself is called `doubles`.
|
* This rule object itself is called `doubles`.
|
||||||
|
|
||||||
* We've given `doubles` the diagnstic text `"doubles"` so that _Parser_ knows
|
* We've given `doubles` the diagnostic text `"doubles"` so that _Parser_ knows
|
||||||
how to refer to it when producing a trace of the parser during debugging.
|
how to refer to it when producing a trace of the parser during debugging.
|
||||||
|
|
||||||
Ok, so if `doubles` is a parser, what does it do? We define the rule's
|
Ok, so if `doubles` is a parser, what does it do? We define the rule's
|
||||||
@@ -632,7 +632,7 @@ All this is intended to introduce the notion of _rs_. It still may be a bit
|
|||||||
unclear why you would want to use _rs_. The use cases for, and lots of detail
|
unclear why you would want to use _rs_. The use cases for, and lots of detail
|
||||||
about, _rs_ is in a later section, _more_about_rules_.
|
about, _rs_ is in a later section, _more_about_rules_.
|
||||||
|
|
||||||
[note The existence of _rs_ means that will probably never have to write a
|
[note The existence of _rs_ means that you will probably never have to write a
|
||||||
low-level parser. You can just put existing parsers together into _rs_
|
low-level parser. You can just put existing parsers together into _rs_
|
||||||
instead.]
|
instead.]
|
||||||
|
|
||||||
@@ -828,7 +828,7 @@ the same character must be used on both sides.
|
|||||||
[quoted_string_example_4]
|
[quoted_string_example_4]
|
||||||
|
|
||||||
Another common thing to do in a quoted string parser is to recognize escape
|
Another common thing to do in a quoted string parser is to recognize escape
|
||||||
sequences. If you have simple escape sequencecs that do not require any real
|
sequences. If you have simple escape sequences that do not require any real
|
||||||
parsing, like say the simple escape sequences from C++, you can provide a
|
parsing, like say the simple escape sequences from C++, you can provide a
|
||||||
_symbols_ object as well. The template parameter `T` to _symbols_t_ must be
|
_symbols_ object as well. The template parameter `T` to _symbols_t_ must be
|
||||||
`char` or `char32_t`. You don't need to include the escaped backslash or the
|
`char` or `char32_t`. You don't need to include the escaped backslash or the
|
||||||
@@ -836,6 +836,14 @@ escaped quote character, since those always work.
|
|||||||
|
|
||||||
[quoted_string_example_5]
|
[quoted_string_example_5]
|
||||||
|
|
||||||
|
Additionally, with each of the forms shown above, you can optionally provide a
|
||||||
|
parser as a final argument, which will be used to parse each character inside
|
||||||
|
the quotes. You have to provide an actual full parser here; you cannot
|
||||||
|
provide a character or string literal. If you do not provide a character
|
||||||
|
parser, _ch_ is used.
|
||||||
|
|
||||||
|
[quoted_string_example_6]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Parsing In Detail]
|
[section Parsing In Detail]
|
||||||
@@ -893,7 +901,7 @@ all parser in its sequence. It then produces its attribute, a
|
|||||||
`bp::parse()`.
|
`bp::parse()`.
|
||||||
|
|
||||||
Something to take note of between Steps #3 and #4: at the beginning of #4, the
|
Something to take note of between Steps #3 and #4: at the beginning of #4, the
|
||||||
input position had returned to where is was at the beginning of #3. This kind
|
input position had returned to where it was at the beginning of #3. This kind
|
||||||
of backtracking happens in alternative parsers when an alternative fails. The
|
of backtracking happens in alternative parsers when an alternative fails. The
|
||||||
next page has more details on the semantics of backtracking.
|
next page has more details on the semantics of backtracking.
|
||||||
|
|
||||||
@@ -1151,7 +1159,7 @@ 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_
|
subsequent parses. The full set of operations can be found in the _symbols_
|
||||||
API docs.
|
API docs.
|
||||||
|
|
||||||
[mpte There are two versions of each of the _symbols_ `*_for_next_parse()`
|
[note 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
|
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
|
with the context is meant to be used within a semantic action. The one
|
||||||
without the context is for use outside of any parse.]
|
without the context is for use outside of any parse.]
|
||||||
@@ -1240,22 +1248,25 @@ these parsers is in a subsequent section. The attributes are repeated here so
|
|||||||
you can use see all the properties of the parsers in one place.]
|
you can use see all the properties of the parsers in one place.]
|
||||||
|
|
||||||
If you have an integral type `IntType` that is not covered by any of the
|
If you have an integral type `IntType` that is not covered by any of the
|
||||||
_Parser_ parsers, you can use a more verbose declaration to declare a parser
|
_Parser_ parsers, you can explicitly specify a base/radix or bounds on the
|
||||||
for `IntType`. If `IntType` were unsigned, you would use `uint_parser`. If
|
number of digits. You do this by calling the `base()` and `digits()` member
|
||||||
it were signed, you would use `int_parser`. For example:
|
functions on an existing parser of the right integral type. So if `IntType`
|
||||||
|
were unsigned, you would use `uint_`. If it were signed, you would use
|
||||||
|
`int_`. For example:
|
||||||
|
|
||||||
constexpr parser_interface<int_parser<IntType>> hex_int;
|
constexpr auto hex_int = bp::uint_.base<16>();
|
||||||
|
|
||||||
`uint_parser` and `int_parser` accept three more non-type template parameters
|
You simply chain together the constraints you want to use, like
|
||||||
after the type parameter. They are `Radix`, `MinDigits`, and `MaxDigits`.
|
`.base<16>().digits<2>()` or `.digits<4>().base<8>()`.
|
||||||
`Radix` defaults to `10`, `MinDigits` to `1`, and `MaxDigits` to `-1`, which
|
|
||||||
is a sentinel value meaning that there is no max number of digits.
|
|
||||||
|
|
||||||
So, if you wanted to parse exactly eight hexadecimal digits in a row in order
|
So, if you wanted to parse exactly eight hexadecimal digits in a row in order
|
||||||
to recognize Unicode character literals like C++ has (e.g. `\Udeadbeef`), you
|
to recognize Unicode character literals like C++ has (e.g. `\Udeadbeef`), you
|
||||||
could use this parser for the digits at the end:
|
could use this parser for the digits at the end:
|
||||||
|
|
||||||
constexpr parser_interface<uint_parser<unsigned int, 16, 8, 8>> hex_int;
|
constexpr auto hex_4_def = bp::uint_.base<16>().digits<8>();
|
||||||
|
|
||||||
|
If you want to specify an acceptable range of digits, use `.digits<LO, HI>()`.
|
||||||
|
Both `HI` and `LO` are inclusive bounds.
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
@@ -1275,7 +1286,7 @@ parsers; we won't say much about them here.
|
|||||||
[heading Interaction with sequence, alternative, and permutation parsers]
|
[heading Interaction with sequence, alternative, and permutation parsers]
|
||||||
|
|
||||||
Sequence, alternative, and permutation parsers do not nest in most cases.
|
Sequence, alternative, and permutation parsers do not nest in most cases.
|
||||||
(Let's consider just sequence parsers to keep thinkgs simple, but most of this
|
(Let's consider just sequence parsers to keep things simple, but most of this
|
||||||
logic applies to alternative parsers as well.) `a >> b >> c` is the same as
|
logic applies to alternative parsers as well.) `a >> b >> c` is the same as
|
||||||
`(a >> b) >> c` and `a >> (b >> c)`, and they are each represented by a single
|
`(a >> b) >> c` and `a >> (b >> c)`, and they are each represented by a single
|
||||||
_seq_p_ with three subparsers, `a`, `b`, and `c`. However, if something
|
_seq_p_ with three subparsers, `a`, `b`, and `c`. However, if something
|
||||||
@@ -1285,7 +1296,7 @@ instance, `lexeme[a >> b] >> c` is a _seq_p_ containing two parsers, `lexeme[a
|
|||||||
in a _lex_p_. This in turn turns off the sequence parser combining logic,
|
in a _lex_p_. This in turn turns off the sequence parser combining logic,
|
||||||
since both sides of the second `operator>>` in `lexeme[a >> b] >> c` are not
|
since both sides of the second `operator>>` in `lexeme[a >> b] >> c` are not
|
||||||
_seq_ps_. Sequence parsers have several rules that govern what the overall
|
_seq_ps_. Sequence parsers have several rules that govern what the overall
|
||||||
attribute type of the parser is, based on the positions and attributes of it
|
attribute type of the parser is, based on the positions and attributes of its
|
||||||
subparsers (see _attr_gen_). Therefore, it's important to know which
|
subparsers (see _attr_gen_). Therefore, it's important to know which
|
||||||
directives create a new parser (and what kind), and which ones do not; this is
|
directives create a new parser (and what kind), and which ones do not; this is
|
||||||
indicated for each directive below.
|
indicated for each directive below.
|
||||||
@@ -1317,7 +1328,7 @@ Creates an _omt_p_.
|
|||||||
|
|
||||||
[heading _raw_]
|
[heading _raw_]
|
||||||
|
|
||||||
`_raw_np_[p]` changes the attribute from `_ATTR_np_(p)` to to a view that
|
`_raw_np_[p]` changes the attribute from `_ATTR_np_(p)` to a view that
|
||||||
delimits the subrange of the input that was matched by `p`. The type of the
|
delimits the subrange of the input that was matched by `p`. The type of the
|
||||||
view is `_v_<I>`, where `I` is the type of the iterator used within the parse.
|
view is `_v_<I>`, where `I` is the type of the iterator used within the parse.
|
||||||
Note that this may not be the same as the iterator type passed to _p_. For
|
Note that this may not be the same as the iterator type passed to _p_. For
|
||||||
@@ -1383,7 +1394,7 @@ need to support the multi-expanding code points, use the other overload, like:
|
|||||||
and if you do it to two bits of text `A` and `B`, then you can compare them
|
and if you do it to two bits of text `A` and `B`, then you can compare them
|
||||||
bitwise to see if they are the same, except of case. Case folding may
|
bitwise to see if they are the same, except of case. Case folding may
|
||||||
sometimes expand a code point into multiple code points (e.g. case folding
|
sometimes expand a code point into multiple code points (e.g. case folding
|
||||||
`"ẞ"` yields `"ss"`. When such a multi-code point expansion occurs, the
|
`"ẞ"` yields `"ss"`). When such a multi-code point expansion occurs, the
|
||||||
expanded code points are in the NFKC normalization form.]
|
expanded code points are in the NFKC normalization form.]
|
||||||
|
|
||||||
Creates a _noc_p_.
|
Creates a _noc_p_.
|
||||||
@@ -1442,6 +1453,24 @@ _merge_ and _sep_ create a copy of the given _seq_p_.
|
|||||||
|
|
||||||
_transform_ creates a _xfm_p_.
|
_transform_ creates a _xfm_p_.
|
||||||
|
|
||||||
|
[heading _delimiter_]
|
||||||
|
|
||||||
|
The _delimiter_np_ directive enables the use of a delimiter within a
|
||||||
|
permutation parser. It *only* applies to permutation parsers, just as _merge_
|
||||||
|
and _sep_ only apply to sequence parsers. Consider this permutation parser.
|
||||||
|
|
||||||
|
constexpr auto parser = bp::int_ || bp::string("foo") || bp::char_('g');
|
||||||
|
|
||||||
|
This will match all of: an integer, `"foo"`, and `'g'`, in any order (for
|
||||||
|
example, `"foo g 42"`). If you also want for those three elements to be
|
||||||
|
delimited by commas, you could write this parser instead.
|
||||||
|
|
||||||
|
constexpr auto delimited_parser =
|
||||||
|
bp::delimiter(bp::lit(','))[bp::int_ || bp::string("foo") || bp::char_('g')];
|
||||||
|
|
||||||
|
`delimited_parser` will parse the same elements as `parser`, but will also
|
||||||
|
require commas between the elements (as in `"foo, g, 42"`).
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Combining Operations]
|
[section Combining Operations]
|
||||||
@@ -1481,7 +1510,7 @@ pretty useless. You should never see this type in practice. Within semantic
|
|||||||
actions, asking for the attribute of a non-attribute-producing parser (using
|
actions, asking for the attribute of a non-attribute-producing parser (using
|
||||||
`_attr(ctx)`) will yield a value of the special type `boost::parser::none`.
|
`_attr(ctx)`) will yield a value of the special type `boost::parser::none`.
|
||||||
When calling _p_ in a form that returns the attribute parsed, when there is no
|
When calling _p_ in a form that returns the attribute parsed, when there is no
|
||||||
attribute, simply returns `bool`; this indicates the success of failure of the
|
attribute, simply returns `bool`; this indicates the success or failure of the
|
||||||
parse.]
|
parse.]
|
||||||
|
|
||||||
[warning _Parser_ assumes that all attributes are semi-regular (see
|
[warning _Parser_ assumes that all attributes are semi-regular (see
|
||||||
@@ -1590,9 +1619,74 @@ attribute becomes `T`.
|
|||||||
[container_concept]
|
[container_concept]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[heading A sequence parser attribute example]
|
||||||
|
|
||||||
|
Note that the application of `OP` is done in the style of a left-fold, and
|
||||||
|
is therefore greedy. This can lead to some non-obvious results. For example,
|
||||||
|
consider this program. Thanks to Duncan Paterson for this very nice example!
|
||||||
|
|
||||||
|
#include <boost/parser/parser.hpp>
|
||||||
|
#include <print>
|
||||||
|
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
int main() {
|
||||||
|
const auto id_set_action = [](auto &ctx) {
|
||||||
|
const auto& [left, right] = _attr(ctx);
|
||||||
|
std::println("{} = {}", left, right);
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto id_parser = bp::char_('a', 'z') > *bp::char_('a', 'z');
|
||||||
|
|
||||||
|
const auto id_set = (id_parser >> '=' >> id_parser)[id_set_action];
|
||||||
|
bp::parse("left=right", id_set);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Perhaps surprisingly, this program prints `leftr = ight`! Why is this? This
|
||||||
|
happens because `id_parser` seems to impose structure, but does not. `id_set`
|
||||||
|
is exactly equivalent to this (comments added to clarify which parts are which
|
||||||
|
below).
|
||||||
|
|
||||||
|
const auto id_set = (
|
||||||
|
/*A*/ bp::char_('a', 'z') > /*B*/ *bp::char_('a', 'z') >>
|
||||||
|
/*C*/ '=' >>
|
||||||
|
/*D*/ bp::char_('a', 'z') > /*E*/ *bp::char_('a', 'z')
|
||||||
|
)[id_set_action];
|
||||||
|
|
||||||
|
As _Parser_ applies `OP` to this sequence parser, the individual steps are:
|
||||||
|
`A` and `B` get merged into a single _std_str_; `C` is ignored, since it
|
||||||
|
produces no attribute; and `D` gets merged into the _std_str_ formed earlier
|
||||||
|
by `A` and `B`; finally, we have `E`. `E` does not combine with `D`, as `D`
|
||||||
|
was already consumed. `E` also does not combine with the _std_str_ we formed
|
||||||
|
from `A`, `B`, and `D`, since we don't combine adjacent containers. In the
|
||||||
|
end, we have a 2-tuple of _std_strs_, in which the first element contains all
|
||||||
|
the characters parsed by `A`, `B`, and `D`, and in which the second element
|
||||||
|
contains all the characters parsed by `E`.
|
||||||
|
|
||||||
|
That's clearly not what we wanted here, though. How do we get a top-level
|
||||||
|
parser that would print `left = right`? We use a _r_. The parser used inside
|
||||||
|
a _r_ can never combine with any parser(s) outside the _r_. Instances of a
|
||||||
|
rule are inherently separate from all parsers with which they are used,
|
||||||
|
whether those parsers are _rs_ or non-_r_ parsers. So, consider a _r_
|
||||||
|
equivalent to the previous `id_parser` above.
|
||||||
|
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
bp::rule<struct id_parser_tag, std::string> id_parser = "identifier";
|
||||||
|
auto const id_parser_def = bp::char_('a', 'z') > *bp::char_('a', 'z');
|
||||||
|
BOOST_PARSER_DEFINE_RULES(id_parser);
|
||||||
|
|
||||||
|
Later, we can use it just as we used the previous non-rule version.
|
||||||
|
|
||||||
|
const auto id_set = (id_parser >> '=' >> id_parser)[id_set_action];
|
||||||
|
|
||||||
|
This produces the results you might expect, since only the `bp::char_('a',
|
||||||
|
'z') > *bp::char_('a', 'z')` parser inside the `id_parser` _r_ is ever
|
||||||
|
eligible for combining via `OP`.
|
||||||
|
|
||||||
|
|
||||||
[heading Alternative parser attribute rules]
|
[heading Alternative parser attribute rules]
|
||||||
|
|
||||||
The rules for alternative parsers are much simpler. For an alternative parer
|
The rules for alternative parsers are much simpler. For an alternative parser
|
||||||
`p`, let the list of attribute types for the subparsers of `p` be `a0, a1, a2,
|
`p`, let the list of attribute types for the subparsers of `p` be `a0, a1, a2,
|
||||||
..., an`. The attribute of `p` is `std::variant<a0, a1, a2, ..., an>`, with
|
..., an`. The attribute of `p` is `std::variant<a0, a1, a2, ..., an>`, with
|
||||||
the following steps applied:
|
the following steps applied:
|
||||||
@@ -1600,8 +1694,8 @@ the following steps applied:
|
|||||||
* all the `none` attributes are left out, and if any are, the attribute is
|
* all the `none` attributes are left out, and if any are, the attribute is
|
||||||
wrapped in a `std::optional`, like `std::optional<std::variant</*...*/>>`;
|
wrapped in a `std::optional`, like `std::optional<std::variant</*...*/>>`;
|
||||||
|
|
||||||
* duplicates in the `std::variant` template parameters `<T1, T2, ... Tn>` are
|
* duplicates in the `std::variant` template parameters `<T1, T2, ..., Tn>` are
|
||||||
removed; every type that appears does so exacly once;
|
removed; every type that appears does so exactly once;
|
||||||
|
|
||||||
* if the attribute is `std::variant<T>` or `std::optional<std::variant<T>>`,
|
* if the attribute is `std::variant<T>` or `std::optional<std::variant<T>>`,
|
||||||
the attribute becomes instead `T` or `std::optional<T>`, respectively; and
|
the attribute becomes instead `T` or `std::optional<T>`, respectively; and
|
||||||
@@ -1696,7 +1790,7 @@ subparsers in the sequence parser to use the same variable for their
|
|||||||
attribute.
|
attribute.
|
||||||
|
|
||||||
Another directive, _sep_, also applies only to sequence parsers, but does the
|
Another directive, _sep_, also applies only to sequence parsers, but does the
|
||||||
opposite of _merge_. If forces all the attributes produced by the subparsers
|
opposite of _merge_. It forces all the attributes produced by the subparsers
|
||||||
of the sequence parser to stay separate, even if they would have combined.
|
of the sequence parser to stay separate, even if they would have combined.
|
||||||
For instance, consider this parser.
|
For instance, consider this parser.
|
||||||
|
|
||||||
@@ -1750,7 +1844,7 @@ and _sep_ do not. Since they operate only on sequence parsers, all they do is
|
|||||||
create a copy of the sequence parser they are given. The _seq_p_ template has
|
create a copy of the sequence parser they are given. The _seq_p_ template has
|
||||||
a template parameter `CombiningGroups`, and all _merge_ and _sep_ do is take a
|
a template parameter `CombiningGroups`, and all _merge_ and _sep_ do is take a
|
||||||
given _seq_p_ and create a copy of it with a different `CombiningGroups`
|
given _seq_p_ and create a copy of it with a different `CombiningGroups`
|
||||||
template parameter. This means that _merge_ and _sep_ are can be ignored in
|
template parameter. This means that _merge_ and _sep_ can be ignored in
|
||||||
`operator>>` expressions much like parentheses are. Consider an example.
|
`operator>>` expressions much like parentheses are. Consider an example.
|
||||||
|
|
||||||
namespace bp = boost::parser;
|
namespace bp = boost::parser;
|
||||||
@@ -1773,7 +1867,7 @@ given function `f`. For example:
|
|||||||
|
|
||||||
Here, we have a function `str_sum` that we use for `f`. It assumes each
|
Here, we have a function `str_sum` that we use for `f`. It assumes each
|
||||||
character in the given _std_str_ `s` is a digit, and returns the sum of all
|
character in the given _std_str_ `s` is a digit, and returns the sum of all
|
||||||
the digits in `s`. Out parser `parser` would normally return a _std_str_.
|
the digits in `s`. Our parser `parser` would normally return a _std_str_.
|
||||||
However, since `str_sum` returns a different type _emdash_ `int` _emdash_ that
|
However, since `str_sum` returns a different type _emdash_ `int` _emdash_ that
|
||||||
is the attribute type of the full parser,
|
is the attribute type of the full parser,
|
||||||
`bp::transform(by_value_str_sum)[parser]`, as you can see from the
|
`bp::transform(by_value_str_sum)[parser]`, as you can see from the
|
||||||
@@ -1806,7 +1900,7 @@ common:
|
|||||||
* They each return a value contextually convertible to `bool`.
|
* They each return a value contextually convertible to `bool`.
|
||||||
|
|
||||||
* They each take at least a range to parse and a parser. The "range to parse"
|
* They each take at least a range to parse and a parser. The "range to parse"
|
||||||
may be an iterator/sentinel pair or an single range object.
|
may be an iterator/sentinel pair or a single range object.
|
||||||
|
|
||||||
* They each require forward iterability of the range to parse.
|
* They each require forward iterability of the range to parse.
|
||||||
|
|
||||||
@@ -2147,7 +2241,7 @@ encoding. Here is how it deduces which case the call falls under:
|
|||||||
|
|
||||||
* Otherwise, the input is in a UTF encoding.
|
* Otherwise, the input is in a UTF encoding.
|
||||||
|
|
||||||
[tip if you want to want to parse in ASCII-only mode, or in some other
|
[tip If you want to parse in ASCII-only mode, or in some other
|
||||||
non-Unicode encoding, use only sequences of `char`, like _std_str_ or `char
|
non-Unicode encoding, use only sequences of `char`, like _std_str_ or `char
|
||||||
const *`.]
|
const *`.]
|
||||||
|
|
||||||
@@ -2171,7 +2265,7 @@ _eh_debugging_ section of the tutorial for details.
|
|||||||
[heading Globals and error handlers]
|
[heading Globals and error handlers]
|
||||||
|
|
||||||
Each call to _p_ can optionally have a globals object associated with it. To
|
Each call to _p_ can optionally have a globals object associated with it. To
|
||||||
use a particular globals object with you parser, you call _w_glb_ to create a
|
use a particular globals object with your parser, you call _w_glb_ to create a
|
||||||
new parser with the globals object in it:
|
new parser with the globals object in it:
|
||||||
|
|
||||||
struct globals_t
|
struct globals_t
|
||||||
@@ -2211,6 +2305,8 @@ common use cases for _rs_. Use a _r_ if you want to:
|
|||||||
* fix the attribute type produced by a parser to something other than the
|
* fix the attribute type produced by a parser to something other than the
|
||||||
default;
|
default;
|
||||||
|
|
||||||
|
* control the attributes generated by adjacent sequence parsers;
|
||||||
|
|
||||||
* create a parser that produces useful diagnostic text;
|
* create a parser that produces useful diagnostic text;
|
||||||
|
|
||||||
* create a recursive rule (more on this below);
|
* create a recursive rule (more on this below);
|
||||||
@@ -2351,6 +2447,10 @@ action if:
|
|||||||
|
|
||||||
The notion of "compatible" is defined in _p_api_.
|
The notion of "compatible" is defined in _p_api_.
|
||||||
|
|
||||||
|
[heading Controlling the attributes generated]
|
||||||
|
|
||||||
|
See the _seq_parser_example_ in the _attr_gen_ section for details.
|
||||||
|
|
||||||
[heading Creating a parser for better diagnostics]
|
[heading Creating a parser for better diagnostics]
|
||||||
|
|
||||||
Each _r_ has associated diagnostic text that _Parser_ can use for failures of
|
Each _r_ has associated diagnostic text that _Parser_ can use for failures of
|
||||||
@@ -2369,11 +2469,12 @@ defined somewhere.
|
|||||||
BOOST_PARSER_DEFINE_RULES(value);
|
BOOST_PARSER_DEFINE_RULES(value);
|
||||||
|
|
||||||
Notice the two expectation points. One before `(value % ',')`, one before the
|
Notice the two expectation points. One before `(value % ',')`, one before the
|
||||||
final `'}'`. Later, you call parse in some input:
|
final `'}'`. Later, you parse in some input:
|
||||||
|
|
||||||
bp::parse("{ 4, 5 a", value, bp::ws);
|
bp::parse("{ 4, 5 a", value, bp::ws);
|
||||||
|
|
||||||
This runs should of the second expectation point, and produces output like this:
|
This runs afoul of the second expectation point, and produces output like
|
||||||
|
this:
|
||||||
|
|
||||||
[pre
|
[pre
|
||||||
1:7: error: Expected '}' here:
|
1:7: error: Expected '}' here:
|
||||||
@@ -2393,8 +2494,8 @@ the earlier expectation:
|
|||||||
]
|
]
|
||||||
|
|
||||||
Not nearly as nice. The problem is that the expectation is on `(value %
|
Not nearly as nice. The problem is that the expectation is on `(value %
|
||||||
',')`. So, even thought we gave `value` reasonable dianostic text, we put the
|
',')`. So, even though we gave `value` reasonable diagnostic text, we put the
|
||||||
text on the wrong thing. We can introduce a new rule to put the diagnstic
|
text on the wrong thing. We can introduce a new rule to put the diagnostic
|
||||||
text in the right place.
|
text in the right place.
|
||||||
|
|
||||||
namespace bp = boost::parser;
|
namespace bp = boost::parser;
|
||||||
@@ -2420,7 +2521,7 @@ message:
|
|||||||
]
|
]
|
||||||
|
|
||||||
The _r_ `value` might be useful elsewhere in our code, perhaps in another
|
The _r_ `value` might be useful elsewhere in our code, perhaps in another
|
||||||
parser. It's diagnostic text is appropriate for those other potential uses.
|
parser. Its diagnostic text is appropriate for those other potential uses.
|
||||||
|
|
||||||
[heading Recursive rules]
|
[heading Recursive rules]
|
||||||
|
|
||||||
@@ -2471,7 +2572,7 @@ of a recursive _r_. This is because each instance of the rule needs a place
|
|||||||
to put the attribute it generates from its parse. However, we only want a
|
to put the attribute it generates from its parse. However, we only want a
|
||||||
single return value for the uppermost rule; if each instance had a separate
|
single return value for the uppermost rule; if each instance had a separate
|
||||||
value in `_val(ctx)`, then it would be impossible to build up the result of a
|
value in `_val(ctx)`, then it would be impossible to build up the result of a
|
||||||
recursive rule step by step during in the evaluation of the recursive
|
recursive rule step by step during the evaluation of the recursive
|
||||||
instantiations.
|
instantiations.
|
||||||
|
|
||||||
Also, consider this rule:
|
Also, consider this rule:
|
||||||
@@ -2480,7 +2581,7 @@ Also, consider this rule:
|
|||||||
bp::rule<struct ints_tag, std::vector<int>> ints = "ints";
|
bp::rule<struct ints_tag, std::vector<int>> ints = "ints";
|
||||||
auto const ints_def = bp::int_ >> ints | bp::eps;
|
auto const ints_def = bp::int_ >> ints | bp::eps;
|
||||||
|
|
||||||
What is the default attribute type for ints_def? It sure looks like
|
What is the default attribute type for `ints_def`? It sure looks like
|
||||||
`std::optional<std::vector<int>>`. Inside the evaluation of `ints`, _Parser_
|
`std::optional<std::vector<int>>`. Inside the evaluation of `ints`, _Parser_
|
||||||
must evaluate `ints_def`, and then produce a `std::vector<int>` _emdash_ the
|
must evaluate `ints_def`, and then produce a `std::vector<int>` _emdash_ the
|
||||||
return type of `ints` _emdash_ from it. How? How do you turn a
|
return type of `ints` _emdash_ from it. How? How do you turn a
|
||||||
@@ -2488,7 +2589,7 @@ return type of `ints` _emdash_ from it. How? How do you turn a
|
|||||||
seems obvious, but the metaprogramming that properly handles this simple
|
seems obvious, but the metaprogramming that properly handles this simple
|
||||||
example and the general case is certainly beyond me.
|
example and the general case is certainly beyond me.
|
||||||
|
|
||||||
_Parser_ has a specific semantic for what consitutes a recursive rule. Each
|
_Parser_ has a specific semantic for what constitutes a recursive rule. Each
|
||||||
rule has a tag type associated with it, and if _Parser_ enters a rule with a
|
rule has a tag type associated with it, and if _Parser_ enters a rule with a
|
||||||
certain tag `Tag`, and the currently-evaluating rule (if there is one) also
|
certain tag `Tag`, and the currently-evaluating rule (if there is one) also
|
||||||
has the tag `Tag`, then rule instance being entered is considered to be a
|
has the tag `Tag`, then rule instance being entered is considered to be a
|
||||||
@@ -2523,7 +2624,7 @@ use each other without introducing cycles:
|
|||||||
|
|
||||||
BOOST_PARSER_DEFINE_RULES(string, object_element, object, array, value);
|
BOOST_PARSER_DEFINE_RULES(string, object_element, object, array, value);
|
||||||
|
|
||||||
Here we have a parser for a Javascript-value-like type `value_type`.
|
Here we have a parser for a JavaScript-value-like type `value_type`.
|
||||||
`value_type` may be an array, which itself may contain other arrays, objects,
|
`value_type` may be an array, which itself may contain other arrays, objects,
|
||||||
strings, etc. Since we need to be able to parse objects within arrays and
|
strings, etc. Since we need to be able to parse objects within arrays and
|
||||||
vice versa, we need each of those two parsers to be able to refer to each
|
vice versa, we need each of those two parsers to be able to refer to each
|
||||||
@@ -2561,8 +2662,8 @@ semantics, is a lot easier to read, and is a lot less code.]
|
|||||||
[heading Locals]
|
[heading Locals]
|
||||||
|
|
||||||
The _r_ template takes another template parameter we have not discussed yet.
|
The _r_ template takes another template parameter we have not discussed yet.
|
||||||
You can pass a third parameter `LocalState` to _r_, which will be defaulted
|
You can pass a third parameter `LocalState` to _r_, which will be default
|
||||||
csontructed by the _r_, and made available within semantic actions used in the
|
constructed by the _r_, and made available within semantic actions used in the
|
||||||
rule as `_locals_np_(ctx)`. This gives your rule some local state, if it
|
rule as `_locals_np_(ctx)`. This gives your rule some local state, if it
|
||||||
needs it. The type of `LocalState` can be anything regular. It could be a
|
needs it. The type of `LocalState` can be anything regular. It could be a
|
||||||
single value, a struct containing multiple values, or a tuple, among others.
|
single value, a struct containing multiple values, or a tuple, among others.
|
||||||
@@ -2673,7 +2774,7 @@ rewritten as:
|
|||||||
|
|
||||||
auto const foo_def = bp::repeat(bp::_p<0>)[' '_l];
|
auto const foo_def = bp::repeat(bp::_p<0>)[' '_l];
|
||||||
|
|
||||||
Using __p_ can prevent you from having to write a bunch of lambdas that get
|
Using __p_ can prevent you from having to write a bunch of lambdas that
|
||||||
each get an argument out of the parse context using `_params_np_(ctx)[0_c]` or
|
each get an argument out of the parse context using `_params_np_(ctx)[0_c]` or
|
||||||
similar.
|
similar.
|
||||||
|
|
||||||
@@ -3060,7 +3161,7 @@ worrying if the input is Unicode or not because, under the covers, what takes
|
|||||||
place is a simple comparison of two integral values.
|
place is a simple comparison of two integral values.
|
||||||
|
|
||||||
[note _Parser_ actually promotes any two values to a common type using
|
[note _Parser_ actually promotes any two values to a common type using
|
||||||
`std::common_type` before comparing them. This is almost always works because
|
`std::common_type` before comparing them. This almost always works because
|
||||||
the input and any parameter passed to _ch_ must be character types. ]
|
the input and any parameter passed to _ch_ must be character types. ]
|
||||||
|
|
||||||
Since matches are always done at a code point level (remember, a "code point"
|
Since matches are always done at a code point level (remember, a "code point"
|
||||||
@@ -3302,9 +3403,9 @@ _w_eh_ (see _p_api_). If you do not set one, _default_eh_ will be used.
|
|||||||
[heading How diagnostics are generated]
|
[heading How diagnostics are generated]
|
||||||
|
|
||||||
_Parser_ only generates error messages like the ones in this page at failed
|
_Parser_ only generates error messages like the ones in this page at failed
|
||||||
expectation points, like `a > b`, where you have successfully parsed `a`, but
|
expectation points (like `a > b`, where you have successfully parsed `a`, but
|
||||||
then cannot successfully parse `b`. This may seem limited to you. It's
|
then cannot successfully parse `b`), and at an unexpected end of input. This
|
||||||
actually the best that we can do.
|
may seem limited to you. It's actually the best that we can do.
|
||||||
|
|
||||||
In order for error handling to happen other than at expectation points, we
|
In order for error handling to happen other than at expectation points, we
|
||||||
have to know that there is no further processing that might take place. This
|
have to know that there is no further processing that might take place. This
|
||||||
@@ -3312,21 +3413,26 @@ is true because _Parser_ has `P1 | P2 | ... | Pn` parsers ("`or_parser`s").
|
|||||||
If any one of these parsers `Pi` fails to match, it is not allowed to fail the
|
If any one of these parsers `Pi` fails to match, it is not allowed to fail the
|
||||||
parse _emdash_ the next one (`Pi+1`) might match. If we get to the end of the
|
parse _emdash_ the next one (`Pi+1`) might match. If we get to the end of the
|
||||||
alternatives of the or_parser and `Pn` fails, we still cannot fail the
|
alternatives of the or_parser and `Pn` fails, we still cannot fail the
|
||||||
top-level parse, because the `or_parser` might be a subparser within a parent
|
top-level parse, because this `or_parser` might be a subparser within a parent
|
||||||
`or_parser`.
|
`or_parser`. The only exception to this is when: we have finished the
|
||||||
|
top-level parse; the top-level parse is *not* a prefix parse; and there is
|
||||||
|
still a part of the input range that is left over. In that case, there is an
|
||||||
|
implicit expectation that the end of the parse and the end of input are the
|
||||||
|
same location, and this implicit expectation has just been violated.
|
||||||
|
|
||||||
Ok, so what might we do? Perhaps we could at least indicate when we ran into
|
Note that we cannot fail the top-level parse when we run into end-of-input.
|
||||||
end-of-input. But we cannot, for exactly the same reason already stated. For
|
We cannot for exactly the same reason already stated. For any parser `P`,
|
||||||
any parser `P`, reaching end-of-input is a failure for `P`, but not
|
reaching end-of-input is a failure for `P`, but not necessarily for the whole
|
||||||
necessarily for the whole parse.
|
parse.
|
||||||
|
|
||||||
Perhaps we could record the farthest point ever reached during the parse, and
|
Ok, so what other kinds of error reporting might we do? Perhaps we could
|
||||||
report that at the top level, if the top level parser fails. That would be
|
record the farthest point ever reached during the parse, and report that at
|
||||||
little help without knowing which parser was active when we reached that
|
the top level, if the top level parser fails. That would be little help
|
||||||
point. This would require some sort of repeated memory allocation, since in
|
without knowing which parser was active when we reached that point. This
|
||||||
_Parser_ the progress point of the parser is stored exclusively on the stack
|
would require some sort of repeated memory allocation, since in _Parser_ the
|
||||||
_emdash_ by the time we fail the top-level parse, all those far-reaching stack
|
progress point of the parser is stored exclusively on the stack _emdash_ by
|
||||||
frames are long gone. Not the best.
|
the time we fail the top-level parse, all those far-reaching stack frames are
|
||||||
|
long gone. Not the best.
|
||||||
|
|
||||||
Worse still, knowing how far you got in the parse and which parser was active
|
Worse still, knowing how far you got in the parse and which parser was active
|
||||||
is not very useful. Consider this.
|
is not very useful. Consider this.
|
||||||
@@ -3336,22 +3442,23 @@ is not very useful. Consider this.
|
|||||||
auto c_b = bp::char_('c') >> bp::char_('b');
|
auto c_b = bp::char_('c') >> bp::char_('b');
|
||||||
auto result = bp::parse("acb", a_b | c_b);
|
auto result = bp::parse("acb", a_b | c_b);
|
||||||
|
|
||||||
If we reported the farthest-reaching parser and it's position, it would be the
|
If we reported the farthest-reaching parser and its position, it would be the
|
||||||
`a_b` parser, at position `"bc"` in the input. Is this really enlightening?
|
`a_b` parser, at position `"bc"` in the input. Is this really enlightening?
|
||||||
Was the error in the input putting the `'a'` at the beginning or putting the
|
Was the error in the input putting the `'a'` at the beginning or putting the
|
||||||
`'c'` in the middle? If you point the user at `a_b` as the parser that
|
`'c'` in the middle? If you point the user at `a_b` as the parser that
|
||||||
failed, and never mention `c_b`, you are potentially just steering them in the
|
failed, and never mention `c_b`, you are potentially just steering them in the
|
||||||
wrong direction.
|
wrong direction.
|
||||||
|
|
||||||
All error messages must come from failed expectation points. Consider parsing
|
All error messages must come from failed expectation points (or unexpected end
|
||||||
JSON. If you open a list with `'['`, you know that you're parsing a list, and
|
of input). Consider parsing JSON. If you open a list with `'['`, you know
|
||||||
if the list is ill-formed, you'll get an error message saying so. If you open
|
that you're parsing a list, and if the list is ill-formed, you'll get an error
|
||||||
an object with `'{'`, the same thing is possible _emdash_ when missing the
|
message saying so. If you open an object with `'{'`, the same thing is
|
||||||
matching `'}'`, you can tell the user, "That's not an object", and this is
|
possible _emdash_ when missing the matching `'}'`, you can tell the user,
|
||||||
useful feedback. The same thing with a partially parsed number, etc. If the
|
"That's not an object", and this is useful feedback. The same thing with a
|
||||||
JSON parser does not build in expectations like matched braces and brackets,
|
partially parsed number, etc. If the JSON parser does not build in
|
||||||
how can _Parser_ know that a missing `'}'` is really a problem, and that no
|
expectations like matched braces and brackets, how can _Parser_ know that a
|
||||||
later parser will match the input even without the `'}'`?
|
missing `'}'` is really a problem, and that no later parser will match the
|
||||||
|
input even without the `'}'`?
|
||||||
|
|
||||||
[important The bottom line is that you should build expectation points into
|
[important The bottom line is that you should build expectation points into
|
||||||
your parsers using `operator>` as much as possible.]
|
your parsers using `operator>` as much as possible.]
|
||||||
@@ -3454,7 +3561,7 @@ We just define a `logging_error_handler`, and pass it by reference to _w_eh_,
|
|||||||
which decorates the top-level parser with the error handler. We *could not*
|
which decorates the top-level parser with the error handler. We *could not*
|
||||||
have written `bp::with_error_handler(parser,
|
have written `bp::with_error_handler(parser,
|
||||||
logging_error_handler("parse.log"))`, because _w_eh_ does not accept rvalues.
|
logging_error_handler("parse.log"))`, because _w_eh_ does not accept rvalues.
|
||||||
This is becuse the error handler eventually goes into the parse context. The
|
This is because the error handler eventually goes into the parse context. The
|
||||||
parse context only stores pointers and iterators, keeping it cheap to copy.
|
parse context only stores pointers and iterators, keeping it cheap to copy.
|
||||||
|
|
||||||
If we run the example and give it the input `"1,"`, this shows up in the log
|
If we run the example and give it the input `"1,"`, this shows up in the log
|
||||||
@@ -3502,9 +3609,9 @@ to `_trace_::off`.
|
|||||||
|
|
||||||
If we trace a substantial parser, we will see a *lot* of output. Each code
|
If we trace a substantial parser, we will see a *lot* of output. Each code
|
||||||
point of the input must be considered, one at a time, to see if a certain rule
|
point of the input must be considered, one at a time, to see if a certain rule
|
||||||
matches. An an example, let's trace a parse using the JSON parser from
|
matches. As an example, let's trace a parse using the JSON parser from
|
||||||
_ex_json_. The input is `"null"`. `null` is one of the types that a
|
_ex_json_. The input is `"null"`. `null` is one of the types that a
|
||||||
Javascript value can have; the top-level parser in the JSON parser example is:
|
JavaScript value can have; the top-level parser in the JSON parser example is:
|
||||||
|
|
||||||
auto const value_p_def =
|
auto const value_p_def =
|
||||||
number | bp::bool_ | null | string | array_p | object_p;
|
number | bp::bool_ | null | string | array_p | object_p;
|
||||||
@@ -3689,10 +3796,10 @@ _Parser_ seldom allocates memory. The exceptions to this are:
|
|||||||
which implies allocation. You can avoid this allocation by explicitly using
|
which implies allocation. You can avoid this allocation by explicitly using
|
||||||
a different sequence container for the attribute that does not allocate.
|
a different sequence container for the attribute that does not allocate.
|
||||||
`boost::container::static_vector` or C++26's `std::inplace_vector` may be
|
`boost::container::static_vector` or C++26's `std::inplace_vector` may be
|
||||||
useful as such replacements.
|
useful for such replacements.
|
||||||
|
|
||||||
With the exception of allocating the name of the parser that was expected in a
|
With the exception of allocating the name of the parser that was expected in a
|
||||||
failed expectation situation, _Parser_ does not does not allocate unless you
|
failed expectation situation, _Parser_ does not allocate unless you
|
||||||
tell it to, by using _symbols_, using a particular error_handler, turning on
|
tell it to, by using _symbols_, using a particular error_handler, turning on
|
||||||
trace, or parsing into attributes that allocate.
|
trace, or parsing into attributes that allocate.
|
||||||
|
|
||||||
@@ -3700,7 +3807,7 @@ trace, or parsing into attributes that allocate.
|
|||||||
|
|
||||||
[section Best Practices]
|
[section Best Practices]
|
||||||
|
|
||||||
[heading Parse unicode from the start]
|
[heading Parse Unicode from the start]
|
||||||
|
|
||||||
If you want to parse ASCII, using the Unicode parsing API will not actually
|
If you want to parse ASCII, using the Unicode parsing API will not actually
|
||||||
cost you anything. Your input will be parsed, `char` by `char`, and compared
|
cost you anything. Your input will be parsed, `char` by `char`, and compared
|
||||||
@@ -3766,9 +3873,9 @@ Some things to note:
|
|||||||
want to know how to fix their input. For either rule, the fix is the same:
|
want to know how to fix their input. For either rule, the fix is the same:
|
||||||
put a hexadecimal escape sequence there.
|
put a hexadecimal escape sequence there.
|
||||||
|
|
||||||
- `single_escaped_char` has a terrible-looking name. However, it's not really
|
- `single_escaped_char` has a terrible-looking name. However, it's not
|
||||||
used as a name anywhere per se. In error messages, it works nicely, though.
|
actually used as a name. In error messages, it works nicely, though. The
|
||||||
The error will be "Expected '"', '\', '/', 'b', 'f', 'n', 'r', or 't' here",
|
error will be "Expected '"', '\', '/', 'b', 'f', 'n', 'r', or 't' here",
|
||||||
which is pretty helpful.
|
which is pretty helpful.
|
||||||
|
|
||||||
[heading Have a simple test that you can run to find ill-formed-code-as-asserts]
|
[heading Have a simple test that you can run to find ill-formed-code-as-asserts]
|
||||||
@@ -3847,7 +3954,7 @@ First, let's look at the template and function parameters.
|
|||||||
`true` if the parse succeeds, and `false` otherwise.
|
`true` if the parse succeeds, and `false` otherwise.
|
||||||
|
|
||||||
Now the body of the function. Notice that it just dispatches to the other
|
Now the body of the function. Notice that it just dispatches to the other
|
||||||
`call()` overload. This is really common, since both overloads need to to the
|
`call()` overload. This is really common, since both overloads need to do the
|
||||||
same parsing; only the attribute may differ. The first line of the body
|
same parsing; only the attribute may differ. The first line of the body
|
||||||
defines `attr_t`, the default attribute type of our wrapped parser `parser_`.
|
defines `attr_t`, the default attribute type of our wrapped parser `parser_`.
|
||||||
It does this by getting the `decltype()` of a use of `parser_.call()`. (This
|
It does this by getting the `decltype()` of a use of `parser_.call()`. (This
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ namespace json {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bp::parser_interface<bp::uint_parser<uint32_t, 16, 4, 4>> const hex_4_def;
|
auto const hex_4_def = boost::parser::uint_.base<16>().digits<4>();
|
||||||
|
|
||||||
auto const escape_seq_def = "\\u" > hex_4;
|
auto const escape_seq_def = "\\u" > hex_4;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//[ extended_json_example
|
//[ extended_json_example
|
||||||
// This header includes a type called json::value that acts as a
|
// This header includes a type called json::value that acts as a
|
||||||
// Javascript-like polymorphic value type.
|
// JavaScript-like polymorphic value type.
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
|
|
||||||
#include <boost/parser/parser.hpp>
|
#include <boost/parser/parser.hpp>
|
||||||
@@ -151,12 +151,10 @@ namespace json {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is the verbose form of declaration for the integer and unsigned
|
// We don't want to use boost::parser::hex directly, since it has a
|
||||||
// integer parsers int_parser and uint_parser. In this case, we don't
|
// variable number of digits. We want to match exactly 4 digits, and this
|
||||||
// want to use boost::parser::hex directly, since it has a variable number
|
// is how we declare a hexadecimal parser that matches exactly 4.
|
||||||
// of digits. We want to match exactly 4 digits, and this is how we
|
auto const hex_4_def = boost::parser::uint_.base<16>().digits<4>();
|
||||||
// declare a hexadecimal parser that matches exactly 4.
|
|
||||||
bp::parser_interface<bp::uint_parser<uint32_t, 16, 4, 4>> const hex_4_def;
|
|
||||||
|
|
||||||
// We use > here instead of >>, because once we see \u, we know that
|
// We use > here instead of >>, because once we see \u, we know that
|
||||||
// exactly four hex digits must follow -- no other production rule starts
|
// exactly four hex digits must follow -- no other production rule starts
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace boost { namespace parser {
|
|||||||
std::declval<bool &>(),
|
std::declval<bool &>(),
|
||||||
std::declval<int &>(),
|
std::declval<int &>(),
|
||||||
std::declval<ErrorHandler const &>(),
|
std::declval<ErrorHandler const &>(),
|
||||||
std::declval<detail::nope &>(),
|
std::declval<detail::nope const &>(),
|
||||||
std::declval<detail::symbol_table_tries_t &>(),
|
std::declval<detail::symbol_table_tries_t &>(),
|
||||||
std::declval<detail::pending_symbol_table_operations_t &>()));
|
std::declval<detail::pending_symbol_table_operations_t &>()));
|
||||||
|
|
||||||
|
|||||||
@@ -16,19 +16,19 @@
|
|||||||
|
|
||||||
/** Boost.Parser uses assertions (`BOOST_ASSERT()`) in several places to
|
/** Boost.Parser uses assertions (`BOOST_ASSERT()`) in several places to
|
||||||
indicate that your use of the library has an error in it. All of those
|
indicate that your use of the library has an error in it. All of those
|
||||||
places could heve instead been ill-formed code, caught at compile time.
|
places could have instead been ill-formed code, caught at compile time.
|
||||||
It is far quicker and easier to determine exactly where in your code such
|
It is far quicker and easier to determine exactly where in your code such
|
||||||
an error is located if this is a runtime failure; you can just look at the
|
an error is located if this is a runtime failure; you can just look at the
|
||||||
stack in your favorite debugger. However, if you want to make thes kinds
|
stack in your favorite debugger. However, if you want to make these kinds
|
||||||
of errors always ill-formed code, define this macro. */
|
of errors always ill-formed code, define this macro. */
|
||||||
# define BOOST_PARSER_NO_RUNTIME_ASSERTIONS
|
# define BOOST_PARSER_NO_RUNTIME_ASSERTIONS
|
||||||
|
|
||||||
/** Asserts that the given condition is true. If
|
/** Asserts that the given condition is true. If
|
||||||
`BOOST_PARSER_NO_RUNTIME_ASSERTIONS` macro is defined by the user,
|
`BOOST_PARSER_NO_RUNTIME_ASSERTIONS` macro is defined by the user,
|
||||||
`BOOST_PARSER_ASSERT` expends to a compile-time `static_assert()`.
|
`BOOST_PARSER_ASSERT` expands to a compile-time `static_assert()`.
|
||||||
Otherwise, it expands to a run-time `BOOST_ASSERT()`. Note that defining
|
Otherwise, it expands to a run-time `BOOST_ASSERT()`. Note that defining
|
||||||
`BOOST_DISABLE_ASSERTS` disables the use of C `assert`, even when
|
`BOOST_DISABLE_ASSERTS` disables the use of C `assert`, even when
|
||||||
`BOOST_ASSERT` is unavailble. */
|
`BOOST_ASSERT` is unavailable. */
|
||||||
# define BOOST_PARSER_ASSERT(condition)
|
# define BOOST_PARSER_ASSERT(condition)
|
||||||
|
|
||||||
/** Boost.Parser will automatically use concepts to constrain templates when
|
/** Boost.Parser will automatically use concepts to constrain templates when
|
||||||
@@ -73,6 +73,12 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Follows logic in boost/config/detail/select_compiler_config.hpp.
|
||||||
|
#if defined(__clang__) && !defined(__ibmxl__) && !defined(__CODEGEARC__)
|
||||||
|
#elif defined(__GNUC__) && !defined(__ibmxl__)
|
||||||
|
#define BOOST_PARSER_GCC
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__cpp_lib_constexpr_algorithms)
|
#if defined(__cpp_lib_constexpr_algorithms)
|
||||||
# define BOOST_PARSER_ALGO_CONSTEXPR constexpr
|
# define BOOST_PARSER_ALGO_CONSTEXPR constexpr
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -47,7 +47,10 @@ namespace boost::parser::detail {
|
|||||||
// One-byte fast path.
|
// One-byte fast path.
|
||||||
if (cp < 0x100) {
|
if (cp < 0x100) {
|
||||||
// ASCII letter fast path.
|
// ASCII letter fast path.
|
||||||
if (0x41 <= cp && cp < 0x5a) {
|
if (0x61 <= cp && cp <= 0x7a) {
|
||||||
|
*out++ = cp;
|
||||||
|
return out;
|
||||||
|
} else if (0x41 <= cp && cp <= 0x5a) {
|
||||||
*out++ = cp + 0x20;
|
*out++ = cp + 0x20;
|
||||||
return out;
|
return out;
|
||||||
} else if (cp == 0x00DF) {
|
} else if (cp == 0x00DF) {
|
||||||
|
|||||||
@@ -52,118 +52,110 @@ namespace boost { namespace parser { namespace detail {
|
|||||||
typename Parser,
|
typename Parser,
|
||||||
typename DelimiterParser,
|
typename DelimiterParser,
|
||||||
typename MinType,
|
typename MinType,
|
||||||
typename MaxType,
|
typename MaxType>
|
||||||
typename ParserMods>
|
void print_parser(
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
Context const & context,
|
||||||
repeat_parser<
|
repeat_parser<Parser, DelimiterParser, MinType, MaxType> const & parser,
|
||||||
Parser,
|
|
||||||
DelimiterParser,
|
|
||||||
MinType,
|
|
||||||
MaxType,
|
|
||||||
ParserMods> const & parser,
|
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename Parser, typename ParserMods>
|
template<typename Context, typename Parser>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
opt_parser<Parser, ParserMods> const & parser,
|
opt_parser<Parser> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename ParserTuple, typename ParserMods>
|
template<typename Context, typename ParserTuple>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
or_parser<ParserTuple, ParserMods> const & parser,
|
or_parser<ParserTuple> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename ParserTuple, typename ParserMods>
|
template<typename Context, typename ParserTuple, typename DelimiterParser>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
perm_parser<ParserTuple, ParserMods> const & parser,
|
perm_parser<ParserTuple, DelimiterParser> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename Context,
|
typename Context,
|
||||||
typename ParserTuple,
|
typename ParserTuple,
|
||||||
typename BacktrackingTuple,
|
typename BacktrackingTuple,
|
||||||
typename CombiningGroups,
|
typename CombiningGroups>
|
||||||
typename ParserMods>
|
void print_parser(
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
Context const & context,
|
||||||
seq_parser<
|
seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups> const &
|
||||||
ParserTuple,
|
parser,
|
||||||
BacktrackingTuple,
|
|
||||||
CombiningGroups,
|
|
||||||
ParserMods> const & parser,
|
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<
|
template<typename Context, typename Parser, typename Action>
|
||||||
typename Context,
|
void print_parser(
|
||||||
typename Parser,
|
|
||||||
typename Action,
|
|
||||||
typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
Context const & context,
|
||||||
action_parser<Parser, Action, ParserMods> const & parser,
|
action_parser<Parser, Action> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename Parser, typename F, typename ParserMods>
|
template<typename Context, typename Parser, typename F>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
transform_parser<Parser, F, ParserMods> const & parser,
|
transform_parser<Parser, F> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename Parser, typename ParserMods>
|
template<typename Context, typename Parser>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
raw_parser<Parser, ParserMods> const & parser,
|
omit_parser<Parser> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
|
template<typename Context, typename Parser>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
raw_parser<Parser> const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
#if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS
|
#if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS
|
||||||
template<typename Context, typename Parser, typename ParserMods>
|
template<typename Context, typename Parser>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
string_view_parser<Parser, ParserMods> const & parser,
|
string_view_parser<Parser> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename Context, typename Parser, typename ParserMods>
|
template<typename Context, typename Parser>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
lexeme_parser<Parser, ParserMods> const & parser,
|
lexeme_parser<Parser> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<
|
template<typename Context, typename Parser>
|
||||||
typename Context,
|
void print_parser(
|
||||||
typename Parser,
|
|
||||||
typename SkipParser,
|
|
||||||
typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
Context const & context,
|
||||||
skip_parser<Parser, SkipParser, ParserMods> const & parser,
|
no_case_parser<Parser> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<
|
template<typename Context, typename Parser, typename SkipParser>
|
||||||
typename Context,
|
void print_parser(
|
||||||
typename Parser,
|
|
||||||
expect_match_t ExpectMatch,
|
|
||||||
typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
Context const & context,
|
||||||
expect_parser<Parser, ExpectMatch, ParserMods> const & parser,
|
skip_parser<Parser, SkipParser> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
|
template<typename Context, typename Parser, bool FailOnMatch>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
expect_parser<Parser, FailOnMatch> const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename Context,
|
typename Context,
|
||||||
@@ -171,219 +163,206 @@ namespace boost { namespace parser { namespace detail {
|
|||||||
typename Parser,
|
typename Parser,
|
||||||
typename Attribute,
|
typename Attribute,
|
||||||
typename LocalState,
|
typename LocalState,
|
||||||
typename ParamsTuple,
|
typename ParamsTuple>
|
||||||
typename ParserMods>
|
void print_parser(
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
Context const & context,
|
||||||
rule_parser<
|
rule_parser<
|
||||||
UseCallbacks,
|
UseCallbacks,
|
||||||
Parser,
|
Parser,
|
||||||
Attribute,
|
Attribute,
|
||||||
LocalState,
|
LocalState,
|
||||||
ParamsTuple,
|
ParamsTuple> const & parser,
|
||||||
ParserMods> const & parser,
|
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename T, typename ParserMods>
|
template<typename Context, typename T>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
symbol_parser<T, ParserMods> const & parser,
|
symbol_parser<T> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename Predicate, typename ParserMods>
|
template<typename Context, typename Predicate>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
eps_parser<Predicate, ParserMods> const & parser,
|
eps_parser<Predicate> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename ParserMods>
|
template<typename Context>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
eps_parser<nope, ParserMods> const & parser,
|
eps_parser<nope> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename ParserMods>
|
template<typename Context>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
eoi_parser<ParserMods> const & parser,
|
eoi_parser const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename Atribute, typename ParserMods>
|
template<typename Context, typename Atribute>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
attr_parser<Atribute, ParserMods> const & parser,
|
attr_parser<Atribute> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<
|
template<typename Context, typename Expected, typename AttributeType>
|
||||||
typename Context,
|
void print_parser(
|
||||||
typename Expected,
|
|
||||||
typename AttributeType,
|
|
||||||
typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
Context const & context,
|
||||||
char_parser<Expected, AttributeType, ParserMods> const & parser,
|
char_parser<Expected, AttributeType> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename ParserMods>
|
template<typename Context>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
digit_parser<ParserMods> const & parser,
|
digit_parser const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename ParserMods>
|
template<typename Context>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
char_subrange_parser<hex_digit_subranges, ParserMods> const & parser,
|
char_subrange_parser<hex_digit_subranges> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename ParserMods>
|
template<typename Context>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
char_subrange_parser<control_subranges, ParserMods> const & parser,
|
char_subrange_parser<control_subranges> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename ParserMods>
|
template<typename Context>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
char_set_parser<punct_chars, ParserMods> const & parser,
|
char_set_parser<punct_chars> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename ParserMods>
|
template<typename Context>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
char_set_parser<lower_case_chars, ParserMods> const & parser,
|
char_set_parser<symb_chars> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<typename Context, typename ParserMods>
|
template<typename Context>
|
||||||
void print_parser_impl(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
char_set_parser<upper_case_chars, ParserMods> const & parser,
|
char_set_parser<lower_case_chars> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
template<
|
template<typename Context>
|
||||||
typename Context,
|
void print_parser(
|
||||||
typename StrIter,
|
|
||||||
typename StrSentinel,
|
|
||||||
typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
Context const & context,
|
||||||
string_parser<StrIter, StrSentinel, ParserMods> const & parser,
|
char_set_parser<upper_case_chars> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components);
|
int components = 0);
|
||||||
|
|
||||||
|
template<typename Context, typename Expected, typename AttributeType>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
omit_parser<char_parser<Expected, AttributeType>> const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
|
template<typename Context, typename StrIter, typename StrSentinel>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
string_parser<StrIter, StrSentinel> const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
|
template<typename Context, typename StrIter, typename StrSentinel>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
omit_parser<string_parser<StrIter, StrSentinel>> const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename Context,
|
typename Context,
|
||||||
typename Quotes,
|
typename Quotes,
|
||||||
typename Escapes,
|
typename Escapes,
|
||||||
typename ParserMods>
|
typename CharParser>
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
|
||||||
quoted_string_parser<Quotes, Escapes, ParserMods> const & parser,
|
|
||||||
std::ostream & os,
|
|
||||||
int components);
|
|
||||||
|
|
||||||
template<
|
|
||||||
typename Context,
|
|
||||||
bool NewlinesOnly,
|
|
||||||
bool NoNewlines,
|
|
||||||
typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
|
||||||
ws_parser<NewlinesOnly, NoNewlines, ParserMods> const & parser,
|
|
||||||
std::ostream & os,
|
|
||||||
int components);
|
|
||||||
|
|
||||||
template<typename Context, typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
|
||||||
bool_parser<ParserMods> const & parser,
|
|
||||||
std::ostream & os,
|
|
||||||
int components);
|
|
||||||
|
|
||||||
template<
|
|
||||||
typename Context,
|
|
||||||
typename T,
|
|
||||||
int Radix,
|
|
||||||
int MinDigits,
|
|
||||||
int MaxDigits,
|
|
||||||
typename Expected,
|
|
||||||
typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
|
||||||
uint_parser<
|
|
||||||
T,
|
|
||||||
Radix,
|
|
||||||
MinDigits,
|
|
||||||
MaxDigits,
|
|
||||||
Expected,
|
|
||||||
ParserMods> const & parser,
|
|
||||||
std::ostream & os,
|
|
||||||
int components);
|
|
||||||
|
|
||||||
template<
|
|
||||||
typename Context,
|
|
||||||
typename T,
|
|
||||||
int Radix,
|
|
||||||
int MinDigits,
|
|
||||||
int MaxDigits,
|
|
||||||
typename Expected,
|
|
||||||
typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
|
||||||
int_parser<T, Radix, MinDigits, MaxDigits, Expected, ParserMods> const &
|
|
||||||
parser,
|
|
||||||
std::ostream & os,
|
|
||||||
int components);
|
|
||||||
|
|
||||||
template<typename Context, typename T, typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
|
||||||
float_parser<T, ParserMods> const & parser,
|
|
||||||
std::ostream & os,
|
|
||||||
int components);
|
|
||||||
|
|
||||||
template<typename Context, typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
|
||||||
float_parser<float, ParserMods> const & parser,
|
|
||||||
std::ostream & os,
|
|
||||||
int components);
|
|
||||||
|
|
||||||
template<typename Context, typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
|
||||||
float_parser<double, ParserMods> const & parser,
|
|
||||||
std::ostream & os,
|
|
||||||
int components);
|
|
||||||
|
|
||||||
template<
|
|
||||||
typename Context,
|
|
||||||
typename SwitchValue,
|
|
||||||
typename OrParser,
|
|
||||||
typename ParserMods>
|
|
||||||
void print_parser_impl(
|
|
||||||
Context const & context,
|
|
||||||
switch_parser<SwitchValue, OrParser, ParserMods> const & parser,
|
|
||||||
std::ostream & os,
|
|
||||||
int components);
|
|
||||||
|
|
||||||
template<bool SuppressOmit = false, typename Context, typename Parser>
|
|
||||||
void print_parser(
|
void print_parser(
|
||||||
Context const & context,
|
Context const & context,
|
||||||
Parser const & parser,
|
quoted_string_parser<Quotes, Escapes, CharParser> const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
|
template<typename Context, bool NewlinesOnly, bool NoNewlines>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
ws_parser<NewlinesOnly, NoNewlines> const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
|
template<typename Context>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
bool_parser const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename Context,
|
||||||
|
typename T,
|
||||||
|
int Radix,
|
||||||
|
int MinDigits,
|
||||||
|
int MaxDigits,
|
||||||
|
typename Expected>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
uint_parser<T, Radix, MinDigits, MaxDigits, Expected> const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename Context,
|
||||||
|
typename T,
|
||||||
|
int Radix,
|
||||||
|
int MinDigits,
|
||||||
|
int MaxDigits,
|
||||||
|
typename Expected>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
int_parser<T, Radix, MinDigits, MaxDigits, Expected> const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
|
template<typename Context, typename T>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
float_parser<T> const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
|
template<typename Context>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
float_parser<float> const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
|
template<typename Context>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
float_parser<double> const & parser,
|
||||||
|
std::ostream & os,
|
||||||
|
int components = 0);
|
||||||
|
|
||||||
|
template<typename Context, typename SwitchValue, typename OrParser>
|
||||||
|
void print_parser(
|
||||||
|
Context const & context,
|
||||||
|
switch_parser<SwitchValue, OrParser> const & parser,
|
||||||
std::ostream & os,
|
std::ostream & os,
|
||||||
int components = 0);
|
int components = 0);
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -24,8 +24,12 @@
|
|||||||
#define BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE 0
|
#define BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
|
#if !BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
|
||||||
BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS && defined(__GNUC__) && 12 <= __GNUC__
|
BOOST_STL_INTERFACES_USE_CONCEPTS && defined(BOOST_GCC) && 14 <= __GNUC__
|
||||||
|
#define BOOST_PARSER_USE_LIBSTDCPP_GCC14_RANGE_ADAPTOR_CLOSURE 1
|
||||||
|
#elif !BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
|
||||||
|
BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS && \
|
||||||
|
defined(BOOST_PARSER_GCC) && 12 <= __GNUC__
|
||||||
#define BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 1
|
#define BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 1
|
||||||
#else
|
#else
|
||||||
#define BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 0
|
#define BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 0
|
||||||
@@ -197,6 +201,11 @@ namespace boost::parser::detail { namespace stl_interfaces {
|
|||||||
template<typename D>
|
template<typename D>
|
||||||
using range_adaptor_closure = std::ranges::range_adaptor_closure<D>;
|
using range_adaptor_closure = std::ranges::range_adaptor_closure<D>;
|
||||||
|
|
||||||
|
#elif BOOST_PARSER_USE_LIBSTDCPP_GCC14_RANGE_ADAPTOR_CLOSURE
|
||||||
|
|
||||||
|
template<typename D>
|
||||||
|
using range_adaptor_closure = std::views::__adaptor::_RangeAdaptorClosure<D>;
|
||||||
|
|
||||||
#elif BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE
|
#elif BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE
|
||||||
|
|
||||||
template<typename D>
|
template<typename D>
|
||||||
@@ -258,7 +267,7 @@ namespace boost::parser::detail { namespace stl_interfaces {
|
|||||||
template<typename F>
|
template<typename F>
|
||||||
struct closure : range_adaptor_closure<closure<F>>
|
struct closure : range_adaptor_closure<closure<F>>
|
||||||
{
|
{
|
||||||
constexpr closure(F f) : f_(f) {}
|
constexpr closure(F f) : f_(std::move(f)) {}
|
||||||
|
|
||||||
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
|
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -326,7 +335,7 @@ namespace boost::parser::detail { namespace stl_interfaces {
|
|||||||
template<typename F>
|
template<typename F>
|
||||||
struct adaptor
|
struct adaptor
|
||||||
{
|
{
|
||||||
constexpr adaptor(F f) : f_(f) {}
|
constexpr adaptor(F f) : f_(std::move(f)) {}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
constexpr auto operator()(Args &&... args) const
|
constexpr auto operator()(Args &&... args) const
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ namespace boost::parser::detail::text::detail {
|
|||||||
template<typename R>
|
template<typename R>
|
||||||
constexpr bool view =
|
constexpr bool view =
|
||||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || \
|
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || \
|
||||||
(defined(__cpp_lib_concepts) && (!defined(__GNUC__) || 12 <= __GNUC__))
|
(defined(__cpp_lib_concepts) && \
|
||||||
|
(!defined(BOOST_PARSER_GCC) || 12 <= __GNUC__))
|
||||||
std::ranges::view<R>
|
std::ranges::view<R>
|
||||||
#else
|
#else
|
||||||
range_<R> && !container_<R> &&
|
range_<R> && !container_<R> &&
|
||||||
@@ -125,7 +126,7 @@ namespace boost::parser::detail::text::detail {
|
|||||||
else if constexpr (can_ref_view<R>)
|
else if constexpr (can_ref_view<R>)
|
||||||
return ref_view(r);
|
return ref_view(r);
|
||||||
else
|
else
|
||||||
return owning_view<T>(std::move(r));
|
return owning_view<T>((R &&)r);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -88,10 +88,12 @@ namespace boost::parser::detail { namespace text {
|
|||||||
{
|
{
|
||||||
V base_ = V();
|
V base_ = V();
|
||||||
|
|
||||||
template<bool Const>
|
// HACK: SentType is here to work around irritating big-3
|
||||||
class iterator;
|
// implementation inconsistencies.
|
||||||
template<bool Const>
|
template<bool Const>
|
||||||
class sentinel;
|
class sentinel;
|
||||||
|
template<bool Const, typename SentType = sentinel<Const>>
|
||||||
|
class iterator;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr project_view()
|
constexpr project_view()
|
||||||
@@ -140,7 +142,7 @@ namespace boost::parser::detail { namespace text {
|
|||||||
#else
|
#else
|
||||||
template<typename V, typename F>
|
template<typename V, typename F>
|
||||||
#endif
|
#endif
|
||||||
template<bool Const>
|
template<bool Const, typename SentType>
|
||||||
class project_view<V, F>::iterator
|
class project_view<V, F>::iterator
|
||||||
: public boost::parser::detail::stl_interfaces::proxy_iterator_interface<
|
: public boost::parser::detail::stl_interfaces::proxy_iterator_interface<
|
||||||
iterator<Const>,
|
iterator<Const>,
|
||||||
@@ -161,7 +163,7 @@ namespace boost::parser::detail { namespace text {
|
|||||||
decltype(detail::function_for_tag<F>(0))
|
decltype(detail::function_for_tag<F>(0))
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
using sentinel = project_view<V, F>::sentinel<Const>;
|
using sentinel = SentType;
|
||||||
|
|
||||||
friend boost::parser::detail::stl_interfaces::access;
|
friend boost::parser::detail::stl_interfaces::access;
|
||||||
iterator_type & base_reference() noexcept { return it_; }
|
iterator_type & base_reference() noexcept { return it_; }
|
||||||
@@ -169,7 +171,7 @@ namespace boost::parser::detail { namespace text {
|
|||||||
|
|
||||||
iterator_type it_ = iterator_type();
|
iterator_type it_ = iterator_type();
|
||||||
|
|
||||||
friend project_view<V, F>::sentinel<Const>;
|
friend project_view<V, F>::template sentinel<Const>;
|
||||||
|
|
||||||
template<bool OtherConst>
|
template<bool OtherConst>
|
||||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -90,6 +90,9 @@ namespace boost { namespace parser {
|
|||||||
os << ":\n";
|
os << ":\n";
|
||||||
|
|
||||||
std::string underlining(std::distance(position.line_start, it), ' ');
|
std::string underlining(std::distance(position.line_start, it), ' ');
|
||||||
|
std::transform(position.line_start, it,
|
||||||
|
underlining.begin(),
|
||||||
|
[](auto c) { return c == '\t' ? '\t' : ' ';});
|
||||||
detail::trace_input(os, position.line_start, it, false, 1u << 31);
|
detail::trace_input(os, position.line_start, it, false, 1u << 31);
|
||||||
if (it == last) {
|
if (it == last) {
|
||||||
os << '\n' << underlining << "^\n";
|
os << '\n' << underlining << "^\n";
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ namespace boost { namespace parser {
|
|||||||
|
|
||||||
/** The error handler used when the user does not specify a custom one.
|
/** The error handler used when the user does not specify a custom one.
|
||||||
This error handler prints warnings and errors to `std::cerr`, and does
|
This error handler prints warnings and errors to `std::cerr`, and does
|
||||||
not have an associcated filename. */
|
not have an associated filename. */
|
||||||
struct default_error_handler
|
struct default_error_handler
|
||||||
{
|
{
|
||||||
constexpr default_error_handler() = default;
|
constexpr default_error_handler() = default;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -115,7 +115,7 @@ namespace boost { namespace parser {
|
|||||||
bool & success,
|
bool & success,
|
||||||
int & indent,
|
int & indent,
|
||||||
ErrorHandler const & error_handler,
|
ErrorHandler const & error_handler,
|
||||||
nope &,
|
nope const &,
|
||||||
symbol_table_tries_t & symbol_table_tries,
|
symbol_table_tries_t & symbol_table_tries,
|
||||||
pending_symbol_table_operations_t &
|
pending_symbol_table_operations_t &
|
||||||
pending_symbol_table_operations) noexcept;
|
pending_symbol_table_operations) noexcept;
|
||||||
@@ -143,41 +143,14 @@ namespace boost { namespace parser {
|
|||||||
|
|
||||||
struct punct_chars
|
struct punct_chars
|
||||||
{};
|
{};
|
||||||
|
struct symb_chars
|
||||||
|
{};
|
||||||
struct lower_case_chars
|
struct lower_case_chars
|
||||||
{};
|
{};
|
||||||
struct upper_case_chars
|
struct upper_case_chars
|
||||||
{};
|
{};
|
||||||
}
|
}
|
||||||
|
|
||||||
enum struct omit_attr_t { no, yes };
|
|
||||||
enum struct ignore_case_t { no, yes };
|
|
||||||
enum struct expect_match_t { no, yes };
|
|
||||||
|
|
||||||
template<typename Parser, expect_match_t ExpectMatch>
|
|
||||||
struct expected_parser
|
|
||||||
{
|
|
||||||
static constexpr expect_match_t expect_match = ExpectMatch;
|
|
||||||
|
|
||||||
Parser parser;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<
|
|
||||||
omit_attr_t OmitAttr = omit_attr_t::no,
|
|
||||||
ignore_case_t IgnoreCase = ignore_case_t::no,
|
|
||||||
typename PreParser = detail::nope,
|
|
||||||
typename PostParser = detail::nope>
|
|
||||||
struct parser_modifiers
|
|
||||||
{
|
|
||||||
using pre_parser_type = PreParser;
|
|
||||||
using post_parser_type = PostParser;
|
|
||||||
|
|
||||||
static constexpr omit_attr_t omit_attr = OmitAttr;
|
|
||||||
static constexpr ignore_case_t ignore_case = IgnoreCase;
|
|
||||||
|
|
||||||
[[no_unique_address]] PreParser pre_parser;
|
|
||||||
[[no_unique_address]] PostParser post_parser;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Repeats the application of another parser `p` of type `Parser`,
|
/** Repeats the application of another parser `p` of type `Parser`,
|
||||||
optionally applying another parser `d` of type `DelimiterParser` in
|
optionally applying another parser `d` of type `DelimiterParser` in
|
||||||
between each pair of applications of `p`. The parse succeeds if `p`
|
between each pair of applications of `p`. The parse succeeds if `p`
|
||||||
@@ -188,21 +161,20 @@ namespace boost { namespace parser {
|
|||||||
typename Parser,
|
typename Parser,
|
||||||
typename DelimiterParser = detail::nope,
|
typename DelimiterParser = detail::nope,
|
||||||
typename MinType = int64_t,
|
typename MinType = int64_t,
|
||||||
typename MaxType = int64_t,
|
typename MaxType = int64_t>
|
||||||
typename ParserMods = parser_modifiers<>>
|
|
||||||
struct repeat_parser;
|
struct repeat_parser;
|
||||||
|
|
||||||
/** Repeats the application of another parser `p` of type `Parser`, `[0,
|
/** Repeats the application of another parser `p` of type `Parser`, `[0,
|
||||||
Inf)` times. The parse always succeeds. The attribute produced is a
|
Inf)` times. The parse always succeeds. The attribute produced is a
|
||||||
sequence of the type of attribute produced by `Parser`. */
|
sequence of the type of attribute produced by `Parser`. */
|
||||||
template<typename Parser, typename ParserMods>
|
template<typename Parser>
|
||||||
struct zero_plus_parser;
|
struct zero_plus_parser;
|
||||||
|
|
||||||
/** Repeats the application of another parser `p` of type `Parser`, `[1,
|
/** Repeats the application of another parser `p` of type `Parser`, `[1,
|
||||||
Inf)` times. The parse succeeds iff `p` succeeds at least once. The
|
Inf)` times. The parse succeeds iff `p` succeeds at least once. The
|
||||||
attribute produced is a sequence of the type of attribute produced by
|
attribute produced is a sequence of the type of attribute produced by
|
||||||
`Parser`. */
|
`Parser`. */
|
||||||
template<typename Parser, typename ParserMods>
|
template<typename Parser>
|
||||||
struct one_plus_parser;
|
struct one_plus_parser;
|
||||||
|
|
||||||
/** Repeats the application of another parser `p` of type `Parser`, `[1,
|
/** Repeats the application of another parser `p` of type `Parser`, `[1,
|
||||||
@@ -211,14 +183,14 @@ namespace boost { namespace parser {
|
|||||||
succeeds at least once, and `d` succeeds each time it is applied. The
|
succeeds at least once, and `d` succeeds each time it is applied. The
|
||||||
attribute produced is a sequence of the type of attribute produced by
|
attribute produced is a sequence of the type of attribute produced by
|
||||||
`Parser`. */
|
`Parser`. */
|
||||||
template<typename Parser, typename DelimiterParser, typename ParserMods>
|
template<typename Parser, typename DelimiterParser>
|
||||||
struct delimited_seq_parser;
|
struct delimited_seq_parser;
|
||||||
|
|
||||||
/** Repeats the application of another parser of type `Parser`, `[0, 1]`
|
/** Repeats the application of another parser of type `Parser`, `[0, 1]`
|
||||||
times. The parse always succeeds. The attribute produced is a
|
times. The parse always succeeds. The attribute produced is a
|
||||||
`std::optional<T>`, where `T` is the type of attribute produced by
|
`std::optional<T>`, where `T` is the type of attribute produced by
|
||||||
`Parser`. */
|
`Parser`. */
|
||||||
template<typename Parser, typename ParserMods>
|
template<typename Parser>
|
||||||
struct opt_parser;
|
struct opt_parser;
|
||||||
|
|
||||||
/** Applies each parser in `ParserTuple`, in order, stopping after the
|
/** Applies each parser in `ParserTuple`, in order, stopping after the
|
||||||
@@ -226,7 +198,7 @@ namespace boost { namespace parser {
|
|||||||
one of the sub-parsers succeeds. The attribute produced is a
|
one of the sub-parsers succeeds. The attribute produced is a
|
||||||
`std::variant` over the types of attribute produced by the parsers in
|
`std::variant` over the types of attribute produced by the parsers in
|
||||||
`ParserTuple`. */
|
`ParserTuple`. */
|
||||||
template<typename ParserTuple, typename ParserMods>
|
template<typename ParserTuple>
|
||||||
struct or_parser;
|
struct or_parser;
|
||||||
|
|
||||||
/** Applies each parsers in `ParserTuple`, an any order, stopping after
|
/** Applies each parsers in `ParserTuple`, an any order, stopping after
|
||||||
@@ -237,7 +209,7 @@ namespace boost { namespace parser {
|
|||||||
`ParserTuple`, not the order of the parsers' matches. It is an error
|
`ParserTuple`, not the order of the parsers' matches. It is an error
|
||||||
to specialize `perm_parser` with a `ParserTuple` template parameter
|
to specialize `perm_parser` with a `ParserTuple` template parameter
|
||||||
that includes an `eps_parser`. */
|
that includes an `eps_parser`. */
|
||||||
template<typename ParserTuple, typename ParserMods>
|
template<typename ParserTuple, typename DelimiterParser>
|
||||||
struct perm_parser;
|
struct perm_parser;
|
||||||
|
|
||||||
/** Applies each parser in `ParserTuple`, in order. The parse succeeds
|
/** Applies each parser in `ParserTuple`, in order. The parse succeeds
|
||||||
@@ -250,15 +222,14 @@ namespace boost { namespace parser {
|
|||||||
template<
|
template<
|
||||||
typename ParserTuple,
|
typename ParserTuple,
|
||||||
typename BacktrackingTuple,
|
typename BacktrackingTuple,
|
||||||
typename CombiningGroups,
|
typename CombiningGroups>
|
||||||
typename ParserMods>
|
|
||||||
struct seq_parser;
|
struct seq_parser;
|
||||||
|
|
||||||
/** Applies the given parser `p` of type `Parser` and an invocable `a` of
|
/** Applies the given parser `p` of type `Parser` and an invocable `a` of
|
||||||
type `Action`. `Action` shall model `semantic_action`, and `a` will
|
type `Action`. `Action` shall model `semantic_action`, and `a` will
|
||||||
only be invoked if `p` succeeds. The parse succeeds iff `p` succeeds.
|
only be invoked if `p` succeeds. The parse succeeds iff `p` succeeds.
|
||||||
Produces no attribute. */
|
Produces no attribute. */
|
||||||
template<typename Parser, typename Action, typename ParserMods>
|
template<typename Parser, typename Action>
|
||||||
struct action_parser;
|
struct action_parser;
|
||||||
|
|
||||||
/** Applies the given parser `p` of type `Parser`. The attribute produced
|
/** Applies the given parser `p` of type `Parser`. The attribute produced
|
||||||
@@ -266,14 +237,21 @@ namespace boost { namespace parser {
|
|||||||
only be invoked if `p` succeeds and sttributes are currently being
|
only be invoked if `p` succeeds and sttributes are currently being
|
||||||
generated. The parse succeeds iff `p` succeeds. The attribute
|
generated. The parse succeeds iff `p` succeeds. The attribute
|
||||||
produced is the the result of the call to `f`. */
|
produced is the the result of the call to `f`. */
|
||||||
template<typename Parser, typename F, typename ParserMods>
|
template<typename Parser, typename F>
|
||||||
struct transform_parser;
|
struct transform_parser;
|
||||||
|
|
||||||
|
/** Applies the given parser `p` of type `Parser`. This parser produces
|
||||||
|
no attribute, and suppresses the production of any attributes that
|
||||||
|
would otherwise be produced by `p`. The parse succeeds iff `p`
|
||||||
|
succeeds. */
|
||||||
|
template<typename Parser>
|
||||||
|
struct omit_parser;
|
||||||
|
|
||||||
/** Applies the given parser `p` of type `Parser`; regardless of the
|
/** Applies the given parser `p` of type `Parser`; regardless of the
|
||||||
attribute produced by `Parser`, this parser's attribute is equivalent
|
attribute produced by `Parser`, this parser's attribute is equivalent
|
||||||
to `_where(ctx)` within a semantic action on `p`. The parse succeeds
|
to `_where(ctx)` within a semantic action on `p`. The parse succeeds
|
||||||
iff `p` succeeds. */
|
iff `p` succeeds. */
|
||||||
template<typename Parser, typename ParserMods>
|
template<typename Parser>
|
||||||
struct raw_parser;
|
struct raw_parser;
|
||||||
|
|
||||||
#if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS
|
#if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS
|
||||||
@@ -286,30 +264,34 @@ namespace boost { namespace parser {
|
|||||||
non-contiguous, code using `string_view_parser` is ill-formed. The
|
non-contiguous, code using `string_view_parser` is ill-formed. The
|
||||||
parse succeeds iff `p` succeeds. This parser is only available in
|
parse succeeds iff `p` succeeds. This parser is only available in
|
||||||
C++20 and later. */
|
C++20 and later. */
|
||||||
template<typename Parser, typename ParserMods>
|
template<typename Parser>
|
||||||
struct string_view_parser;
|
struct string_view_parser;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Applies the given parser `p` of type `Parser`, disabling the current
|
/** Applies the given parser `p` of type `Parser`, disabling the current
|
||||||
skipper in use, if any. The parse succeeds iff `p` succeeds. The
|
skipper in use, if any. The parse succeeds iff `p` succeeds. The
|
||||||
attribute produced is the type of attribute produced by `Parser`. */
|
attribute produced is the type of attribute produced by `Parser`. */
|
||||||
template<typename Parser, typename ParserMods>
|
template<typename Parser>
|
||||||
struct lexeme_parser;
|
struct lexeme_parser;
|
||||||
|
|
||||||
|
/** Applies the given parser `p` of type `Parser`, enabling
|
||||||
|
case-insensitive matching, based on Unicode case folding. The parse
|
||||||
|
succeeds iff `p` succeeds. The attribute produced is the type of
|
||||||
|
attribute produced by `Parser`. */
|
||||||
|
template<typename Parser>
|
||||||
|
struct no_case_parser;
|
||||||
|
|
||||||
/** Applies the given parser `p` of type `Parser`, using a parser of type
|
/** Applies the given parser `p` of type `Parser`, using a parser of type
|
||||||
`SkipParser` as the skipper. The parse succeeds iff `p` succeeds.
|
`SkipParser` as the skipper. The parse succeeds iff `p` succeeds.
|
||||||
The attribute produced is the type of attribute produced by
|
The attribute produced is the type of attribute produced by
|
||||||
`Parser`. */
|
`Parser`. */
|
||||||
template<
|
template<typename Parser, typename SkipParser = detail::nope>
|
||||||
typename Parser,
|
|
||||||
typename SkipParser = detail::nope,
|
|
||||||
typename ParserMods = parser_modifiers<>>
|
|
||||||
struct skip_parser;
|
struct skip_parser;
|
||||||
|
|
||||||
/** Applies the given parser `p` of type `Parser`, producing no attributes
|
/** Applies the given parser `p` of type `Parser`, producing no attributes
|
||||||
and consuming no input. The parse succeeds iff `p`'s success is equal
|
and consuming no input. The parse succeeds iff `p`'s success is
|
||||||
to `ExpectMatch == expect_match_t::yes`. */
|
unequal to `FailOnMatch`. */
|
||||||
template<typename Parser, expect_match_t ExpectMatch, typename ParserMods>
|
template<typename Parser, bool FailOnMatch>
|
||||||
struct expect_parser;
|
struct expect_parser;
|
||||||
|
|
||||||
/** Matches one of a set S of possible inputs, each of which is associated
|
/** Matches one of a set S of possible inputs, each of which is associated
|
||||||
@@ -318,7 +300,7 @@ namespace boost { namespace parser {
|
|||||||
from S dynamically, during parsing; any such changes are reverted at
|
from S dynamically, during parsing; any such changes are reverted at
|
||||||
the end of parsing. The parse succeeds iff an element of S is
|
the end of parsing. The parse succeeds iff an element of S is
|
||||||
matched. \see `symbols` */
|
matched. \see `symbols` */
|
||||||
template<typename T, typename ParserMods>
|
template<typename T>
|
||||||
struct symbol_parser;
|
struct symbol_parser;
|
||||||
|
|
||||||
/** Applies another parser `p`, associated with this parser via `TagType`.
|
/** Applies another parser `p`, associated with this parser via `TagType`.
|
||||||
@@ -337,24 +319,22 @@ namespace boost { namespace parser {
|
|||||||
typename TagType,
|
typename TagType,
|
||||||
typename Attribute,
|
typename Attribute,
|
||||||
typename LocalState,
|
typename LocalState,
|
||||||
typename ParamsTuple,
|
typename ParamsTuple>
|
||||||
typename ParserMods>
|
|
||||||
struct rule_parser;
|
struct rule_parser;
|
||||||
|
|
||||||
/** Matches anything, and consumes no input. If `Predicate` is anything
|
/** Matches anything, and consumes no input. If `Predicate` is anything
|
||||||
other than `detail::nope` (which it is by default), and `pred_(ctx)`
|
other than `detail::nope` (which it is by default), and `pred_(ctx)`
|
||||||
evaluates to false, where `ctx` is the parser context, the parse
|
evaluates to false, where `ctx` is the parser context, the parse
|
||||||
fails. */
|
fails. */
|
||||||
template<typename Predicate, typename ParserMods>
|
template<typename Predicate>
|
||||||
struct eps_parser;
|
struct eps_parser;
|
||||||
|
|
||||||
/** Matches only the end of input. Produces no attribute. */
|
/** Matches only the end of input. Produces no attribute. */
|
||||||
template<typename ParserMods>
|
|
||||||
struct eoi_parser;
|
struct eoi_parser;
|
||||||
|
|
||||||
/** Matches anything, consumes no input, and produces an attribute of type
|
/** Matches anything, consumes no input, and produces an attribute of type
|
||||||
`RESOLVE(Attribute)`. */
|
`RESOLVE(Attribute)`. */
|
||||||
template<typename Attribute, typename ParserMods>
|
template<typename Attribute>
|
||||||
struct attr_parser;
|
struct attr_parser;
|
||||||
|
|
||||||
/** A tag type that can be passed as the first parameter to `char_()` when
|
/** A tag type that can be passed as the first parameter to `char_()` when
|
||||||
@@ -371,10 +351,7 @@ namespace boost { namespace parser {
|
|||||||
parse fails only if the parser is constructed with a specific set of
|
parse fails only if the parser is constructed with a specific set of
|
||||||
expected code point values that does not include the matched code
|
expected code point values that does not include the matched code
|
||||||
point. */
|
point. */
|
||||||
template<
|
template<typename Expected, typename AttributeType = void>
|
||||||
typename Expected,
|
|
||||||
typename AttributeType = void,
|
|
||||||
typename ParserMods = parser_modifiers<>>
|
|
||||||
struct char_parser;
|
struct char_parser;
|
||||||
|
|
||||||
/** Matches a single code point that is equal to one of the code points
|
/** Matches a single code point that is equal to one of the code points
|
||||||
@@ -382,7 +359,7 @@ namespace boost { namespace parser {
|
|||||||
characters for matching Unicode character classes like punctuation or
|
characters for matching Unicode character classes like punctuation or
|
||||||
lower case. Attribute type is the attribute type of the character
|
lower case. Attribute type is the attribute type of the character
|
||||||
being matched. */
|
being matched. */
|
||||||
template<typename Tag, typename ParserMods>
|
template<typename Tag>
|
||||||
struct char_set_parser;
|
struct char_set_parser;
|
||||||
|
|
||||||
/** Matches a single code point that falls into one of the subranges of
|
/** Matches a single code point that falls into one of the subranges of
|
||||||
@@ -390,18 +367,17 @@ namespace boost { namespace parser {
|
|||||||
sets of characters for matching Unicode character classes like hex
|
sets of characters for matching Unicode character classes like hex
|
||||||
digits or control characters. Attribute type is the attribute type of
|
digits or control characters. Attribute type is the attribute type of
|
||||||
the character being matched. */
|
the character being matched. */
|
||||||
template<typename Tag, typename ParserMods>
|
template<typename Tag>
|
||||||
struct char_subrange_parser;
|
struct char_subrange_parser;
|
||||||
|
|
||||||
/** Matches a single decimal digit code point, using the Unicode character
|
/** Matches a single decimal digit code point, using the Unicode character
|
||||||
class Hex_Digit. Attribute type is the attribute type of the
|
class Hex_Digit. Attribute type is the attribute type of the
|
||||||
character being matched. */
|
character being matched. */
|
||||||
template<typename ParserMods>
|
|
||||||
struct digit_parser;
|
struct digit_parser;
|
||||||
|
|
||||||
/** Matches a particular string, delimited by an iterator sentinel pair;
|
/** Matches a particular string, delimited by an iterator sentinel pair;
|
||||||
produces no attribute. */
|
produces no attribute. */
|
||||||
template<typename StrIter, typename StrSentinel, typename ParserMods>
|
template<typename StrIter, typename StrSentinel>
|
||||||
struct string_parser;
|
struct string_parser;
|
||||||
|
|
||||||
/** Matches a string delimited by quotation marks; produces a
|
/** Matches a string delimited by quotation marks; produces a
|
||||||
@@ -409,7 +385,7 @@ namespace boost { namespace parser {
|
|||||||
template<
|
template<
|
||||||
typename Quotes = detail::nope,
|
typename Quotes = detail::nope,
|
||||||
typename Escapes = detail::nope,
|
typename Escapes = detail::nope,
|
||||||
typename ParserMods = parser_modifiers<>>
|
typename CharParser = char_parser<detail::nope>>
|
||||||
struct quoted_string_parser;
|
struct quoted_string_parser;
|
||||||
|
|
||||||
/** Matches an end-of-line (`NewlinesOnly == true`), whitespace
|
/** Matches an end-of-line (`NewlinesOnly == true`), whitespace
|
||||||
@@ -417,27 +393,25 @@ namespace boost { namespace parser {
|
|||||||
but not newline) code point, based on the Unicode definitions of each
|
but not newline) code point, based on the Unicode definitions of each
|
||||||
(also matches the two code points `"\r\n"`). Produces no
|
(also matches the two code points `"\r\n"`). Produces no
|
||||||
attribute. */
|
attribute. */
|
||||||
template<bool NewlinesOnly, bool NoNewlines, typename ParserMods>
|
template<bool NewlinesOnly, bool NoNewlines>
|
||||||
struct ws_parser;
|
struct ws_parser;
|
||||||
|
|
||||||
/** Matches the strings "true" and "false", producing an attribute of
|
/** Matches the strings "true" and "false", producing an attribute of
|
||||||
`true` or `false`, respectively, and fails on any other input. */
|
`true` or `false`, respectively, and fails on any other input. */
|
||||||
template<typename ParserMods>
|
|
||||||
struct bool_parser;
|
struct bool_parser;
|
||||||
|
|
||||||
/** Matches an unsigned number of radix `Radix`, of at least `MinDigits`
|
/** Matches an unsigned number of radix `Radix`, of at least `MinDigits`
|
||||||
and at most `MaxDigits`, producing an attribute of type `T`. Fails on
|
and at most `MaxDigits`, producing an attribute of type `T`. Fails on
|
||||||
any other input. The parse will also fail if `Expected` is anything
|
any other input. The parse will also fail if `Expected` is anything
|
||||||
but `detail::nope` (which it is by default), and the produced
|
but `detail::nope` (which it is by default), and the produced
|
||||||
attribute is not equal to `expected_`. `Radix` must be in `[2,
|
attribute is not equal to `expected_`. `Radix` must be one of `2`,
|
||||||
36]`. */
|
`8`, `10`, or `16`. */
|
||||||
template<
|
template<
|
||||||
typename T,
|
typename T,
|
||||||
int Radix = 10,
|
int Radix = 10,
|
||||||
int MinDigits = 1,
|
int MinDigits = 1,
|
||||||
int MaxDigits = -1,
|
int MaxDigits = -1,
|
||||||
typename Expected = detail::nope,
|
typename Expected = detail::nope>
|
||||||
typename ParserMods = parser_modifiers<>>
|
|
||||||
struct uint_parser;
|
struct uint_parser;
|
||||||
|
|
||||||
/** Matches a signed number of radix `Radix`, of at least `MinDigits` and
|
/** Matches a signed number of radix `Radix`, of at least `MinDigits` and
|
||||||
@@ -451,13 +425,12 @@ namespace boost { namespace parser {
|
|||||||
int Radix = 10,
|
int Radix = 10,
|
||||||
int MinDigits = 1,
|
int MinDigits = 1,
|
||||||
int MaxDigits = -1,
|
int MaxDigits = -1,
|
||||||
typename Expected = detail::nope,
|
typename Expected = detail::nope>
|
||||||
typename ParserMods = parser_modifiers<>>
|
|
||||||
struct int_parser;
|
struct int_parser;
|
||||||
|
|
||||||
/** Matches a floating point number, producing an attribute of type
|
/** Matches a floating point number, producing an attribute of type
|
||||||
`T`. */
|
`T`. */
|
||||||
template<typename T, typename ParserMods>
|
template<typename T>
|
||||||
struct float_parser;
|
struct float_parser;
|
||||||
|
|
||||||
/** Applies at most one of the parsers in `OrParser`. If `switch_value_`
|
/** Applies at most one of the parsers in `OrParser`. If `switch_value_`
|
||||||
@@ -465,10 +438,7 @@ namespace boost { namespace parser {
|
|||||||
first such parser is applied, and the success or failure and attribute
|
first such parser is applied, and the success or failure and attribute
|
||||||
of the parse are those of the applied parser. Otherwise, the parse
|
of the parse are those of the applied parser. Otherwise, the parse
|
||||||
fails. */
|
fails. */
|
||||||
template<
|
template<typename SwitchValue, typename OrParser = detail::nope>
|
||||||
typename SwitchValue,
|
|
||||||
typename OrParser = detail::nope,
|
|
||||||
typename ParserMods = parser_modifiers<>>
|
|
||||||
struct switch_parser;
|
struct switch_parser;
|
||||||
|
|
||||||
/** A wrapper for parsers that provides the operations that must be
|
/** A wrapper for parsers that provides the operations that must be
|
||||||
|
|||||||
@@ -451,7 +451,7 @@ namespace boost::parser {
|
|||||||
Parser,
|
Parser,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
ErrorHandler,
|
ErrorHandler,
|
||||||
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
|
parser_interface<eps_parser<detail::phony>>>;
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename V,
|
typename V,
|
||||||
@@ -469,7 +469,7 @@ namespace boost::parser {
|
|||||||
Parser,
|
Parser,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
ErrorHandler,
|
ErrorHandler,
|
||||||
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
|
parser_interface<eps_parser<detail::phony>>>;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<
|
template<
|
||||||
@@ -571,8 +571,7 @@ namespace boost::parser {
|
|||||||
Parser,
|
Parser,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
ErrorHandler,
|
ErrorHandler,
|
||||||
parser_interface<
|
parser_interface<eps_parser<detail::phony>>>
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>>
|
|
||||||
[[nodiscard]] constexpr auto operator()(
|
[[nodiscard]] constexpr auto operator()(
|
||||||
R && r,
|
R && r,
|
||||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||||
@@ -583,8 +582,7 @@ namespace boost::parser {
|
|||||||
return (*this)(
|
return (*this)(
|
||||||
(R &&)r,
|
(R &&)r,
|
||||||
parser,
|
parser,
|
||||||
parser_interface<
|
parser_interface<eps_parser<detail::phony>>{},
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>{},
|
|
||||||
(ReplacementR &&)replacement,
|
(ReplacementR &&)replacement,
|
||||||
trace_mode);
|
trace_mode);
|
||||||
}
|
}
|
||||||
@@ -625,11 +623,10 @@ namespace boost::parser {
|
|||||||
std::is_same_v<Trace, trace>) {
|
std::is_same_v<Trace, trace>) {
|
||||||
// (r, parser, replacement, trace) case
|
// (r, parser, replacement, trace) case
|
||||||
return impl(
|
return impl(
|
||||||
(R &&)r,
|
(R &&) r,
|
||||||
parser,
|
parser,
|
||||||
parser_interface<
|
parser_interface<eps_parser<detail::phony>>{},
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>{},
|
(SkipParser &&) skip,
|
||||||
(SkipParser &&)skip,
|
|
||||||
replacement);
|
replacement);
|
||||||
} else {
|
} else {
|
||||||
static_assert(
|
static_assert(
|
||||||
|
|||||||
@@ -116,9 +116,7 @@ namespace boost::parser {
|
|||||||
return BOOST_PARSER_SUBRANGE(first, first);
|
return BOOST_PARSER_SUBRANGE(first, first);
|
||||||
|
|
||||||
auto const search_parser = omit[*(char_ - parser)] >> -raw[parser];
|
auto const search_parser = omit[*(char_ - parser)] >> -raw[parser];
|
||||||
if constexpr (std::is_same_v<
|
if constexpr (std::is_same_v<SkipParser, eps_parser<phony>>) {
|
||||||
SkipParser,
|
|
||||||
eps_parser<phony, parser_modifiers<>>>) {
|
|
||||||
auto result = parser::prefix_parse(
|
auto result = parser::prefix_parse(
|
||||||
first, last, search_parser, trace_mode);
|
first, last, search_parser, trace_mode);
|
||||||
if (*result)
|
if (*result)
|
||||||
@@ -257,9 +255,9 @@ namespace boost::parser {
|
|||||||
trace trace_mode = trace::off)
|
trace trace_mode = trace::off)
|
||||||
{
|
{
|
||||||
return parser::search(
|
return parser::search(
|
||||||
(R &&)r,
|
(R &&) r,
|
||||||
parser,
|
parser,
|
||||||
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>{},
|
parser_interface<eps_parser<detail::phony>>{},
|
||||||
trace_mode);
|
trace_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +292,7 @@ namespace boost::parser {
|
|||||||
return parser::search(
|
return parser::search(
|
||||||
BOOST_PARSER_SUBRANGE(first, last),
|
BOOST_PARSER_SUBRANGE(first, last),
|
||||||
parser,
|
parser,
|
||||||
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>{},
|
parser_interface<eps_parser<detail::phony>>{},
|
||||||
trace_mode);
|
trace_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,7 +483,7 @@ namespace boost::parser {
|
|||||||
Parser,
|
Parser,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
ErrorHandler,
|
ErrorHandler,
|
||||||
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
|
parser_interface<eps_parser<detail::phony>>>;
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename V,
|
typename V,
|
||||||
@@ -498,7 +496,7 @@ namespace boost::parser {
|
|||||||
Parser,
|
Parser,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
ErrorHandler,
|
ErrorHandler,
|
||||||
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
|
parser_interface<eps_parser<detail::phony>>>;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<
|
template<
|
||||||
@@ -571,8 +569,7 @@ namespace boost::parser {
|
|||||||
Parser,
|
Parser,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
ErrorHandler,
|
ErrorHandler,
|
||||||
parser_interface<
|
parser_interface<eps_parser<detail::phony>>>
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>>
|
|
||||||
[[nodiscard]] constexpr auto operator()(
|
[[nodiscard]] constexpr auto operator()(
|
||||||
R && r,
|
R && r,
|
||||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||||
@@ -582,8 +579,7 @@ namespace boost::parser {
|
|||||||
return (*this)(
|
return (*this)(
|
||||||
(R &&)r,
|
(R &&)r,
|
||||||
parser,
|
parser,
|
||||||
parser_interface<
|
parser_interface<eps_parser<detail::phony>>{},
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>{},
|
|
||||||
trace_mode);
|
trace_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,8 +590,8 @@ namespace boost::parser {
|
|||||||
typename Parser,
|
typename Parser,
|
||||||
typename GlobalState,
|
typename GlobalState,
|
||||||
typename ErrorHandler,
|
typename ErrorHandler,
|
||||||
typename SkipParser = parser_interface<
|
typename SkipParser =
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>,
|
parser_interface<eps_parser<detail::phony>>,
|
||||||
typename Trace = trace,
|
typename Trace = trace,
|
||||||
typename Enable = std::enable_if_t<is_parsable_range_v<R>>>
|
typename Enable = std::enable_if_t<is_parsable_range_v<R>>>
|
||||||
[[nodiscard]] constexpr auto operator()(
|
[[nodiscard]] constexpr auto operator()(
|
||||||
@@ -611,10 +607,9 @@ namespace boost::parser {
|
|||||||
std::is_same_v<Trace, trace>) {
|
std::is_same_v<Trace, trace>) {
|
||||||
// (r, parser, trace) case
|
// (r, parser, trace) case
|
||||||
return impl(
|
return impl(
|
||||||
(R &&)r,
|
(R &&) r,
|
||||||
parser,
|
parser,
|
||||||
parser_interface<
|
parser_interface<eps_parser<detail::phony>>{},
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>{},
|
|
||||||
skip);
|
skip);
|
||||||
} else if constexpr (
|
} else if constexpr (
|
||||||
detail::is_parser_iface<SkipParser> &&
|
detail::is_parser_iface<SkipParser> &&
|
||||||
|
|||||||
@@ -193,13 +193,14 @@ namespace boost::parser {
|
|||||||
typename Parser,
|
typename Parser,
|
||||||
typename GlobalState,
|
typename GlobalState,
|
||||||
typename ErrorHandler>
|
typename ErrorHandler>
|
||||||
split_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
|
split_view(
|
||||||
|
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
|
||||||
-> split_view<
|
-> split_view<
|
||||||
detail::text::detail::all_t<V>,
|
detail::text::detail::all_t<V>,
|
||||||
Parser,
|
Parser,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
ErrorHandler,
|
ErrorHandler,
|
||||||
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
|
parser_interface<eps_parser<detail::phony>>>;
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename V,
|
typename V,
|
||||||
@@ -212,7 +213,7 @@ namespace boost::parser {
|
|||||||
Parser,
|
Parser,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
ErrorHandler,
|
ErrorHandler,
|
||||||
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
|
parser_interface<eps_parser<detail::phony>>>;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<
|
template<
|
||||||
@@ -285,8 +286,7 @@ namespace boost::parser {
|
|||||||
Parser,
|
Parser,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
ErrorHandler,
|
ErrorHandler,
|
||||||
parser_interface<
|
parser_interface<eps_parser<detail::phony>>>
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>>
|
|
||||||
[[nodiscard]] constexpr auto operator()(
|
[[nodiscard]] constexpr auto operator()(
|
||||||
R && r,
|
R && r,
|
||||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||||
@@ -296,8 +296,7 @@ namespace boost::parser {
|
|||||||
return (*this)(
|
return (*this)(
|
||||||
(R &&)r,
|
(R &&)r,
|
||||||
parser,
|
parser,
|
||||||
parser_interface<
|
parser_interface<eps_parser<detail::phony>>{},
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>{},
|
|
||||||
trace_mode);
|
trace_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ namespace boost::parser {
|
|||||||
typename Parser,
|
typename Parser,
|
||||||
typename GlobalState,
|
typename GlobalState,
|
||||||
typename ErrorHandler,
|
typename ErrorHandler,
|
||||||
typename SkipParser = parser_interface<
|
typename SkipParser =
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>,
|
parser_interface<eps_parser<detail::phony>>,
|
||||||
typename Trace = trace,
|
typename Trace = trace,
|
||||||
typename Enable = std::enable_if_t<is_parsable_range_v<R>>>
|
typename Enable = std::enable_if_t<is_parsable_range_v<R>>>
|
||||||
[[nodiscard]] constexpr auto operator()(
|
[[nodiscard]] constexpr auto operator()(
|
||||||
@@ -325,10 +324,9 @@ namespace boost::parser {
|
|||||||
std::is_same_v<Trace, trace>) {
|
std::is_same_v<Trace, trace>) {
|
||||||
// (r, parser, trace) case
|
// (r, parser, trace) case
|
||||||
return impl(
|
return impl(
|
||||||
(R &&)r,
|
(R &&) r,
|
||||||
parser,
|
parser,
|
||||||
parser_interface<
|
parser_interface<eps_parser<detail::phony>>{},
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>{},
|
|
||||||
skip);
|
skip);
|
||||||
} else if constexpr (
|
} else if constexpr (
|
||||||
detail::is_parser_iface<SkipParser> &&
|
detail::is_parser_iface<SkipParser> &&
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
#include <boost/parser/replace.hpp>
|
#include <boost/parser/replace.hpp>
|
||||||
|
|
||||||
#if (!defined(_MSC_VER) || BOOST_PARSER_USE_CONCEPTS) && \
|
#if (!defined(_MSC_VER) || BOOST_PARSER_USE_CONCEPTS) && \
|
||||||
(!defined(__GNUC__) || 12 <= __GNUC__ || !BOOST_PARSER_USE_CONCEPTS)
|
(!defined(BOOST_PARSER_GCC) || 12 <= __GNUC__ || \
|
||||||
|
!BOOST_PARSER_USE_CONCEPTS)
|
||||||
|
|
||||||
|
|
||||||
namespace boost::parser {
|
namespace boost::parser {
|
||||||
@@ -254,9 +255,7 @@ namespace boost::parser {
|
|||||||
BOOST_PARSER_SUBRANGE(first, first), parse_result{});
|
BOOST_PARSER_SUBRANGE(first, first), parse_result{});
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (std::is_same_v<
|
if constexpr (std::is_same_v<SkipParser, eps_parser<phony>>) {
|
||||||
SkipParser,
|
|
||||||
eps_parser<phony, parser_modifiers<>>>) {
|
|
||||||
auto result = parser::prefix_parse(
|
auto result = parser::prefix_parse(
|
||||||
first, last, search_parser, trace_mode);
|
first, last, search_parser, trace_mode);
|
||||||
if (*result) {
|
if (*result) {
|
||||||
@@ -580,7 +579,7 @@ namespace boost::parser {
|
|||||||
Parser,
|
Parser,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
ErrorHandler,
|
ErrorHandler,
|
||||||
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
|
parser_interface<eps_parser<detail::phony>>>;
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename V,
|
typename V,
|
||||||
@@ -596,7 +595,7 @@ namespace boost::parser {
|
|||||||
Parser,
|
Parser,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
ErrorHandler,
|
ErrorHandler,
|
||||||
parser_interface<eps_parser<detail::phony, parser_modifiers<>>>>;
|
parser_interface<eps_parser<detail::phony>>>;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<
|
template<
|
||||||
@@ -699,8 +698,7 @@ namespace boost::parser {
|
|||||||
Parser,
|
Parser,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
ErrorHandler,
|
ErrorHandler,
|
||||||
parser_interface<
|
parser_interface<eps_parser<detail::phony>>>
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>>
|
|
||||||
[[nodiscard]] constexpr auto operator()(
|
[[nodiscard]] constexpr auto operator()(
|
||||||
R && r,
|
R && r,
|
||||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||||
@@ -711,8 +709,7 @@ namespace boost::parser {
|
|||||||
return (*this)(
|
return (*this)(
|
||||||
(R &&)r,
|
(R &&)r,
|
||||||
parser,
|
parser,
|
||||||
parser_interface<
|
parser_interface<eps_parser<detail::phony>>{},
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>{},
|
|
||||||
(F &&)f,
|
(F &&)f,
|
||||||
trace_mode);
|
trace_mode);
|
||||||
}
|
}
|
||||||
@@ -757,11 +754,10 @@ namespace boost::parser {
|
|||||||
std::is_same_v<Trace, trace>) {
|
std::is_same_v<Trace, trace>) {
|
||||||
// (r, parser, f, trace) case
|
// (r, parser, f, trace) case
|
||||||
return impl(
|
return impl(
|
||||||
to_range<R>::call((R &&)r),
|
to_range<R>::call((R &&) r),
|
||||||
parser,
|
parser,
|
||||||
parser_interface<
|
parser_interface<eps_parser<detail::phony>>{},
|
||||||
eps_parser<detail::phony, parser_modifiers<>>>{},
|
(SkipParser &&) skip,
|
||||||
(SkipParser &&)skip,
|
|
||||||
f);
|
f);
|
||||||
} else {
|
} else {
|
||||||
static_assert(
|
static_assert(
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ namespace boost { namespace parser {
|
|||||||
/** A literal that can be used to concisely name `parser::llong`
|
/** A literal that can be used to concisely name `parser::llong`
|
||||||
integral constants. */
|
integral constants. */
|
||||||
template<char... chars>
|
template<char... chars>
|
||||||
constexpr auto operator"" _c()
|
constexpr auto operator""_c()
|
||||||
{
|
{
|
||||||
constexpr long long n =
|
constexpr long long n =
|
||||||
detail::parse_llong<sizeof...(chars)>({chars...});
|
detail::parse_llong<sizeof...(chars)>({chars...});
|
||||||
@@ -185,14 +185,10 @@ namespace boost { namespace parser {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
operator T() const && noexcept
|
operator T() const && noexcept
|
||||||
{
|
{
|
||||||
#if defined(__GNUC__) && __GNUC__ < 13
|
|
||||||
// Yuck.
|
// Yuck.
|
||||||
std::remove_reference_t<T> * ptr = nullptr;
|
std::remove_reference_t<T> * ptr = nullptr;
|
||||||
ptr += 1; // warning mitigation
|
ptr += 1; // warning mitigation
|
||||||
return *ptr;
|
return *ptr;
|
||||||
#else
|
|
||||||
return std::declval<T>();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,5 +4,6 @@
|
|||||||
"authors": [ "T. Zachary Laine" ],
|
"authors": [ "T. Zachary Laine" ],
|
||||||
"maintainers": [ "Zach Laine <whatwasthataddress -at- gmail.com>" ],
|
"maintainers": [ "Zach Laine <whatwasthataddress -at- gmail.com>" ],
|
||||||
"description": "A parser combinator library.",
|
"description": "A parser combinator library.",
|
||||||
"category": [ "Parsing" ]
|
"category": [ "Parsing" ],
|
||||||
|
"cxxstd": "17"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import testing ;
|
|||||||
|
|
||||||
project
|
project
|
||||||
: requirements <library>/boost/charconv//boost_charconv
|
: requirements <library>/boost/charconv//boost_charconv
|
||||||
|
<library>/boost/parser//boost_parser
|
||||||
;
|
;
|
||||||
|
|
||||||
compile compile_all_t.cpp ;
|
compile compile_all_t.cpp ;
|
||||||
|
|||||||
@@ -237,6 +237,326 @@ void github_issue_125()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void github_issue_209()
|
||||||
|
{
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
|
||||||
|
BOOST_TEST(std::is_sorted(
|
||||||
|
std::begin(bp::detail::char_set<detail::punct_chars>::chars),
|
||||||
|
std::end(bp::detail::char_set<detail::punct_chars>::chars)));
|
||||||
|
|
||||||
|
BOOST_TEST(std::is_sorted(
|
||||||
|
std::begin(bp::detail::char_set<detail::symb_chars>::chars),
|
||||||
|
std::end(bp::detail::char_set<detail::symb_chars>::chars)));
|
||||||
|
|
||||||
|
BOOST_TEST(std::is_sorted(
|
||||||
|
std::begin(bp::detail::char_set<detail::lower_case_chars>::chars),
|
||||||
|
std::end(bp::detail::char_set<detail::lower_case_chars>::chars)));
|
||||||
|
|
||||||
|
BOOST_TEST(std::is_sorted(
|
||||||
|
std::begin(bp::detail::char_set<detail::upper_case_chars>::chars),
|
||||||
|
std::end(bp::detail::char_set<detail::upper_case_chars>::chars)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void github_issue_223()
|
||||||
|
{
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
|
||||||
|
// failing case
|
||||||
|
{
|
||||||
|
std::vector<char> v;
|
||||||
|
const auto parser = *('x' | bp::char_('y'));
|
||||||
|
bp::parse("xy", parser, bp::ws, v);
|
||||||
|
|
||||||
|
BOOST_TEST(v.size() == 1);
|
||||||
|
BOOST_TEST(v == std::vector<char>({'y'}));
|
||||||
|
|
||||||
|
// the assert fails since there are two elements in the vector: '\0'
|
||||||
|
// and 'y'. Seems pretty surprising to me
|
||||||
|
}
|
||||||
|
|
||||||
|
// working case
|
||||||
|
{
|
||||||
|
const auto parser = *('x' | bp::char_('y'));
|
||||||
|
const auto result = bp::parse("xy", parser, bp::ws);
|
||||||
|
|
||||||
|
BOOST_TEST(result->size() == 1);
|
||||||
|
BOOST_TEST(*(*result)[0] == 'y');
|
||||||
|
|
||||||
|
// success, the vector has only one 'y' element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace github_issue_248_ {
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
|
||||||
|
static constexpr bp::rule<struct symbol, int> symbol = "//";
|
||||||
|
static constexpr bp::rule<struct vector, std::vector<int>> list =
|
||||||
|
"<int>(,<int>)*";
|
||||||
|
static constexpr bp::rule<struct working, std::vector<int>> working =
|
||||||
|
"working";
|
||||||
|
static constexpr bp::rule<struct failing, std::vector<int>> failing =
|
||||||
|
"failing";
|
||||||
|
|
||||||
|
static auto const symbol_def = bp::symbols<int>{{"//", 0}};
|
||||||
|
static constexpr auto list_def = bp::int_ % ',';
|
||||||
|
static constexpr auto working_def = -symbol >> (bp::int_ % ',');
|
||||||
|
static constexpr auto failing_def = -symbol >> list;
|
||||||
|
|
||||||
|
BOOST_PARSER_DEFINE_RULES(symbol, list, working, failing);
|
||||||
|
}
|
||||||
|
|
||||||
|
void github_issue_248()
|
||||||
|
{
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
|
||||||
|
using namespace github_issue_248_;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto const result = bp::parse("//1,2,3", working, bp::ws);
|
||||||
|
auto const expected = std::vector<int>{0, 1, 2, 3};
|
||||||
|
BOOST_TEST(result.has_value());
|
||||||
|
bool const equal = std::equal(
|
||||||
|
result->begin(), result->end(), expected.begin(), expected.end());
|
||||||
|
BOOST_TEST(equal);
|
||||||
|
if (!equal) {
|
||||||
|
std::cout << "contents of *result:\n";
|
||||||
|
for (auto x : *result) {
|
||||||
|
std::cout << x << '\n';
|
||||||
|
}
|
||||||
|
std::cout << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto const result = bp::parse("//1,2,3", failing, bp::ws);
|
||||||
|
auto const expected = std::vector<int>{0, 1, 2, 3};
|
||||||
|
BOOST_TEST(result.has_value());
|
||||||
|
bool const equal = std::equal(
|
||||||
|
result->begin(), result->end(), expected.begin(), expected.end());
|
||||||
|
BOOST_TEST(equal);
|
||||||
|
if (!equal) {
|
||||||
|
std::cout << "contents of *result:\n";
|
||||||
|
for (auto x : *result) {
|
||||||
|
std::cout << x << '\n';
|
||||||
|
}
|
||||||
|
std::cout << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BOOST_PARSER_USE_CONCEPTS
|
||||||
|
namespace github_issue_268_ {
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
constexpr bp::rule<struct name, std::string_view> name = "name";
|
||||||
|
auto name_def = bp::string_view[bp::lexeme[+(
|
||||||
|
bp::lower | bp::upper | bp::digit | bp::char_("_"))]];
|
||||||
|
BOOST_PARSER_DEFINE_RULES(name)
|
||||||
|
constexpr bp::rule<struct qd_vec, std::vector<double>> qd_vec = "qd_vec";
|
||||||
|
auto qd_vec_def = bp::lit("\"") >>
|
||||||
|
bp::double_ %
|
||||||
|
(bp::lit(",") |
|
||||||
|
(bp::lit("\"") >> bp::lit(",") >> bp::lit("\""))) >>
|
||||||
|
bp::lit('\"');
|
||||||
|
BOOST_PARSER_DEFINE_RULES(qd_vec)
|
||||||
|
struct lu_table_template_1
|
||||||
|
{
|
||||||
|
std::vector<double> index_1;
|
||||||
|
std::string_view variable_1;
|
||||||
|
};
|
||||||
|
constexpr boost::parser::
|
||||||
|
rule<struct lu_table_template_1_tag, lu_table_template_1>
|
||||||
|
lu_table_template_1_rule = "lu_table_template_1";
|
||||||
|
auto lu_table_template_1_rule_def = (bp::lit("index_1") >> '(' >> qd_vec >>
|
||||||
|
')' >> ';') >>
|
||||||
|
(bp::lit("variable_1") >> ':' >> name >>
|
||||||
|
';');
|
||||||
|
BOOST_PARSER_DEFINE_RULES(lu_table_template_1_rule)
|
||||||
|
|
||||||
|
constexpr boost::parser::
|
||||||
|
rule<struct lu_table_template_1_permut_tag, lu_table_template_1>
|
||||||
|
lu_table_template_1_permut_rule = "lu_table_template_1";
|
||||||
|
auto lu_table_template_1_permut_rule_def =
|
||||||
|
(bp::lit("index_1") >> '(' >> qd_vec >> ')' >> ';') ||
|
||||||
|
(bp::lit("variable_1") >> ':' >> name >> ';');
|
||||||
|
BOOST_PARSER_DEFINE_RULES(lu_table_template_1_permut_rule)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void github_issue_268()
|
||||||
|
{
|
||||||
|
#if BOOST_PARSER_USE_CONCEPTS
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
using namespace github_issue_268_;
|
||||||
|
std::string inputstring = "index_1 ( \"1\" ) ; variable_1 : bier;";
|
||||||
|
|
||||||
|
auto const def_result = bp::parse(
|
||||||
|
inputstring, lu_table_template_1_rule_def, bp::blank, bp::trace::off);
|
||||||
|
std::cout << "seq_parser generates this type:\n"
|
||||||
|
<< typeid(def_result.value()).name() << std::endl;
|
||||||
|
BOOST_TEST(def_result);
|
||||||
|
|
||||||
|
auto const permut_def_result = bp::parse(
|
||||||
|
inputstring,
|
||||||
|
lu_table_template_1_permut_rule_def,
|
||||||
|
bp::blank,
|
||||||
|
bp::trace::off);
|
||||||
|
std::cout << "permut_parser generates this type:\n"
|
||||||
|
<< typeid(permut_def_result.value()).name() << std::endl;
|
||||||
|
BOOST_TEST(permut_def_result);
|
||||||
|
|
||||||
|
auto const result = bp::parse(
|
||||||
|
inputstring, lu_table_template_1_rule, bp::blank, bp::trace::off);
|
||||||
|
std::cout << "seq_parser in rule generates this type:\n"
|
||||||
|
<< typeid(result.value()).name() << std::endl;
|
||||||
|
BOOST_TEST(result);
|
||||||
|
|
||||||
|
auto const permut_result = bp::parse(
|
||||||
|
inputstring,
|
||||||
|
lu_table_template_1_permut_rule,
|
||||||
|
bp::blank,
|
||||||
|
bp::trace::off);
|
||||||
|
std::cout << "permut_parser generates this type:\n"
|
||||||
|
<< typeid(permut_result.value()).name() << std::endl;
|
||||||
|
BOOST_TEST(permut_result);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void github_issue_279()
|
||||||
|
{
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
|
||||||
|
{
|
||||||
|
constexpr auto condition_clause =
|
||||||
|
bp::lit(U"while") > bp::lit(U"someexpression") >> bp::attr(true);
|
||||||
|
|
||||||
|
constexpr auto do_statement =
|
||||||
|
bp::lexeme[bp::lit(U"do") >> &bp::ws] > -condition_clause > bp::eol;
|
||||||
|
|
||||||
|
auto const result =
|
||||||
|
bp::parse(U"do\n", do_statement, bp::blank, bp::trace::off);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
std::optional<bool> const & condition = result.value();
|
||||||
|
BOOST_TEST(!condition.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
constexpr auto condition_clause =
|
||||||
|
bp::lit(U"while") > bp::lit(U"someexpression") >> bp::attr(true);
|
||||||
|
|
||||||
|
constexpr auto do_statement_reverse =
|
||||||
|
-condition_clause > bp::lexeme[bp::lit(U"do") >> &bp::ws] > bp::eol;
|
||||||
|
|
||||||
|
auto const result =
|
||||||
|
bp::parse(U"do\n", do_statement_reverse, bp::blank, bp::trace::off);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
std::optional<bool> const & condition = result.value();
|
||||||
|
BOOST_TEST(!condition.has_value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace github_issue_285_ {
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
|
||||||
|
struct Content
|
||||||
|
{
|
||||||
|
~Content()
|
||||||
|
{
|
||||||
|
int setbreakpointhere = 0;
|
||||||
|
(void)setbreakpointhere;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
constexpr bp::rule<struct content_tag, std::shared_ptr<Content>> content =
|
||||||
|
"content";
|
||||||
|
constexpr auto content_action = [](auto & ctx) {
|
||||||
|
std::shared_ptr<Content> & result = _val(ctx);
|
||||||
|
result = std::make_shared<Content>();
|
||||||
|
};
|
||||||
|
constexpr auto content_def =
|
||||||
|
(bp::lit(U"content") >> bp::eol)[content_action];
|
||||||
|
BOOST_PARSER_DEFINE_RULES(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void github_issue_285()
|
||||||
|
{
|
||||||
|
using namespace github_issue_285_;
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
|
||||||
|
constexpr auto prolog = bp::lit(U"prolog") >> bp::eol;
|
||||||
|
|
||||||
|
constexpr auto epilog =
|
||||||
|
bp::no_case[bp::lexeme[bp::lit(U"epi") >> bp::lit(U"log")]] >> bp::eol;
|
||||||
|
|
||||||
|
constexpr auto full_parser = prolog >> content >> epilog;
|
||||||
|
|
||||||
|
std::string teststring =
|
||||||
|
"prolog\n"
|
||||||
|
"content\n"
|
||||||
|
"epilog\n";
|
||||||
|
|
||||||
|
// "content" produces a shared_ptr with the result.
|
||||||
|
// The "epilog" parser must not delete the result.
|
||||||
|
|
||||||
|
auto const result = bp::parse(teststring, full_parser, bp::blank);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(result.value().get() != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void github_pr_290()
|
||||||
|
{
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
|
||||||
|
auto const pTest = bp::lit("TEST:") > -bp::quoted_string;
|
||||||
|
|
||||||
|
auto result = bp::parse("TEST: \"foo\"", pTest, bp::blank);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(*result == "foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace github_pr_297_ {
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
constexpr auto bar_required_f = [](auto& ctx) -> bool {
|
||||||
|
const bool& argument = bp::_p<0>(ctx);
|
||||||
|
return argument;
|
||||||
|
};
|
||||||
|
constexpr bp::rule<struct foobar_parser_tag> foobar_parser = "foobar_parser";
|
||||||
|
constexpr auto foobar_parser_def =
|
||||||
|
bp::lit("foo")
|
||||||
|
>> bp::switch_(bar_required_f)
|
||||||
|
(true, bp::lit("bar"))
|
||||||
|
(false, -bp::lit("bar"));
|
||||||
|
BOOST_PARSER_DEFINE_RULES(foobar_parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
void github_pr_297()
|
||||||
|
{
|
||||||
|
namespace bp = boost::parser;
|
||||||
|
using namespace github_pr_297_;
|
||||||
|
|
||||||
|
{
|
||||||
|
const bool bar_required = true;
|
||||||
|
const bool result =
|
||||||
|
bp::parse("foo bar", foobar_parser.with(bar_required), bp::blank);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const bool bar_required = true;
|
||||||
|
const bool result =
|
||||||
|
bp::parse("foo", foobar_parser.with(bar_required), bp::blank);
|
||||||
|
BOOST_TEST(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const bool bar_required = false;
|
||||||
|
const bool result =
|
||||||
|
bp::parse("foo bar", foobar_parser.with(bar_required), bp::blank);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const bool bar_required = false;
|
||||||
|
const bool result =
|
||||||
|
bp::parse("foo", foobar_parser.with(bar_required), bp::blank);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
@@ -246,5 +566,13 @@ int main()
|
|||||||
github_issue_78();
|
github_issue_78();
|
||||||
github_issue_90();
|
github_issue_90();
|
||||||
github_issue_125();
|
github_issue_125();
|
||||||
|
github_issue_209();
|
||||||
|
github_issue_223();
|
||||||
|
github_issue_248();
|
||||||
|
github_issue_268();
|
||||||
|
github_issue_279();
|
||||||
|
github_issue_285();
|
||||||
|
github_pr_290();
|
||||||
|
github_pr_297();
|
||||||
return boost::report_errors();
|
return boost::report_errors();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ constexpr auto double_s = u8"sS"; // U+0073 U+0073
|
|||||||
|
|
||||||
// basic)
|
// basic)
|
||||||
{
|
{
|
||||||
auto char_p = no_case[char_('a') | char_('B')];
|
constexpr auto char_p = no_case[char_('a') | char_('B')];
|
||||||
|
|
||||||
{
|
{
|
||||||
auto const result = parse("a", char_p);
|
auto const result = parse("a", char_p);
|
||||||
@@ -461,12 +461,12 @@ constexpr auto double_s = u8"sS"; // U+0073 U+0073
|
|||||||
{
|
{
|
||||||
constexpr auto mixed_sharp_s1 = U"ẞs";
|
constexpr auto mixed_sharp_s1 = U"ẞs";
|
||||||
constexpr auto mixed_sharp_s2 = U"sẞ";
|
constexpr auto mixed_sharp_s2 = U"sẞ";
|
||||||
auto const result =
|
auto const result = detail::no_case_aware_string_mismatch(
|
||||||
detail::no_case_aware_string_mismatch<ignore_case_t::yes>(
|
mixed_sharp_s1,
|
||||||
mixed_sharp_s1,
|
detail::text::null_sentinel,
|
||||||
detail::text::null_sentinel,
|
mixed_sharp_s2,
|
||||||
mixed_sharp_s2,
|
detail::text::null_sentinel,
|
||||||
detail::text::null_sentinel);
|
true);
|
||||||
BOOST_TEST(result.first == detail::text::null_sentinel);
|
BOOST_TEST(result.first == detail::text::null_sentinel);
|
||||||
BOOST_TEST(result.second == detail::text::null_sentinel);
|
BOOST_TEST(result.second == detail::text::null_sentinel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -292,6 +292,15 @@ int main()
|
|||||||
}
|
}
|
||||||
BOOST_TEST(parse(str, parser_1));
|
BOOST_TEST(parse(str, parser_1));
|
||||||
BOOST_TEST(!parse(str, parser_2));
|
BOOST_TEST(!parse(str, parser_2));
|
||||||
|
{
|
||||||
|
BOOST_TEST(!parse(str, char_));
|
||||||
|
std::ostringstream err, warn;
|
||||||
|
stream_error_handler eh("", err, warn);
|
||||||
|
BOOST_TEST(!parse(str, with_error_handler(char_, eh)));
|
||||||
|
BOOST_TEST(
|
||||||
|
err.str() ==
|
||||||
|
"1:1: error: Expected end of input here:\nab\n ^\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::string str = "ab";
|
std::string str = "ab";
|
||||||
@@ -2753,6 +2762,16 @@ int main()
|
|||||||
BOOST_TEST(result == std::vector<uint32_t>({0x21, 0xfda}));
|
BOOST_TEST(result == std::vector<uint32_t>({0x21, 0xfda}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// symb_
|
||||||
|
{
|
||||||
|
auto parser = +symb;
|
||||||
|
|
||||||
|
std::u32string str = U"$^\u20AC!\u2194\u220F\U0001D7C6b\u2280\U0001FACE\U0001039F";
|
||||||
|
std::vector<uint32_t> result;
|
||||||
|
BOOST_TEST(parse(str, parser, char_ - symb, result));
|
||||||
|
BOOST_TEST(result == std::vector<uint32_t>({U'$', U'^', 0x20AC, 0x2194, 0x220F, 0x2280, 0x1FACE}));
|
||||||
|
}
|
||||||
|
|
||||||
// lower_
|
// lower_
|
||||||
{
|
{
|
||||||
auto parser = +lower;
|
auto parser = +lower;
|
||||||
|
|||||||
@@ -88,5 +88,66 @@ int main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return boost::report_errors();
|
{
|
||||||
|
using namespace bp::literals;
|
||||||
|
constexpr auto parser =
|
||||||
|
bp::delimiter(','_l)[bp::int_ || bp::string("foo") || bp::char_('g')];
|
||||||
|
|
||||||
|
{
|
||||||
|
auto result = bp::parse("42 foo g", parser, bp::ws);
|
||||||
|
BOOST_TEST(!result);
|
||||||
|
result = bp::parse("42, foo ,g", parser, bp::ws);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(
|
||||||
|
*result ==
|
||||||
|
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto result = bp::parse(",42, g, foo", parser, bp::ws);
|
||||||
|
BOOST_TEST(!result);
|
||||||
|
result = bp::parse("42, g , foo", parser, bp::ws);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(
|
||||||
|
*result ==
|
||||||
|
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto result = bp::parse("foo, 42, g,", parser, bp::ws);
|
||||||
|
BOOST_TEST(!result);
|
||||||
|
result = bp::parse("foo, 42, g", parser, bp::ws);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(
|
||||||
|
*result ==
|
||||||
|
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto result = bp::parse("foo g 42", parser, bp::ws);
|
||||||
|
BOOST_TEST(!result);
|
||||||
|
result = bp::parse("foo, g, 42", parser, bp::ws);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(
|
||||||
|
*result ==
|
||||||
|
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto result = bp::parse("g foo 42", parser, bp::ws);
|
||||||
|
BOOST_TEST(!result);
|
||||||
|
result = bp::parse("g ,foo ,42", parser, bp::ws);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(
|
||||||
|
*result ==
|
||||||
|
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto result = bp::parse("g 42 foo", parser, bp::ws);
|
||||||
|
BOOST_TEST(!result);
|
||||||
|
result = bp::parse("g , 42 , foo", parser, bp::ws);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(
|
||||||
|
*result ==
|
||||||
|
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ int main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// different_char
|
// different_quote
|
||||||
{
|
{
|
||||||
constexpr auto parser = bp::quoted_string('\'');
|
constexpr auto parser = bp::quoted_string('\'');
|
||||||
|
|
||||||
@@ -75,9 +75,18 @@ int main()
|
|||||||
BOOST_TEST(result);
|
BOOST_TEST(result);
|
||||||
BOOST_TEST(*result == "'foo'");
|
BOOST_TEST(*result == "'foo'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
constexpr auto parser = bp::quoted_string('\'', bp::char_("g\t"));
|
||||||
|
|
||||||
|
auto result = bp::parse(R"('\'ggg\'')", parser, bp::ws);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(*result == "'ggg'");
|
||||||
|
BOOST_TEST(!bp::parse(R"('\'fff\'')", parser, bp::ws));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// different_char_with_escapes
|
// different_quote_with_escapes
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
auto parser = bp::quoted_string('\'', cu_escapes);
|
auto parser = bp::quoted_string('\'', cu_escapes);
|
||||||
@@ -119,6 +128,58 @@ int main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// different_quote_with_escapes_and_char_p
|
||||||
|
{
|
||||||
|
{
|
||||||
|
auto parser = bp::quoted_string('\'', cu_escapes, bp::char_("g\t"));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto result = bp::parse("", parser, bp::ws);
|
||||||
|
BOOST_TEST(!result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto result = bp::parse("'ggg'", parser, bp::ws);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto result = bp::parse("'fff'", parser, bp::ws);
|
||||||
|
BOOST_TEST(!result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto result = bp::parse(R"('ggg\t')", parser, bp::ws);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(*result == "ggg\t");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto result = bp::parse(R"('ggg\g')", parser, bp::ws);
|
||||||
|
BOOST_TEST(!result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto parser = bp::quoted_string('\'', cp_escapes);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto result = bp::parse("", parser, bp::ws);
|
||||||
|
BOOST_TEST(!result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto result = bp::parse(R"('\tggg')", parser, bp::ws);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(*result == "\tggg");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto result = bp::parse(R"('g\ggg')", parser, bp::ws);
|
||||||
|
BOOST_TEST(!result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// char_set
|
// char_set
|
||||||
{
|
{
|
||||||
constexpr auto parser = bp::quoted_string("'\"");
|
constexpr auto parser = bp::quoted_string("'\"");
|
||||||
@@ -171,6 +232,15 @@ int main()
|
|||||||
// character.
|
// character.
|
||||||
BOOST_TEST(!bp::parse(R"("\'foo")", parser, bp::ws));
|
BOOST_TEST(!bp::parse(R"("\'foo")", parser, bp::ws));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
constexpr auto parser = bp::quoted_string("'\"", bp::char_("g"));
|
||||||
|
|
||||||
|
auto result = bp::parse(R"('\'ggg\'')", parser, bp::ws);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(*result == "'ggg'");
|
||||||
|
BOOST_TEST(!bp::parse(R"('\'fff\'')", parser, bp::ws));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// char_set_with_escapes
|
// char_set_with_escapes
|
||||||
@@ -233,6 +303,15 @@ int main()
|
|||||||
BOOST_TEST(!result);
|
BOOST_TEST(!result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto parser = bp::quoted_string("'\"", cu_escapes, bp::char_("g"));
|
||||||
|
|
||||||
|
auto result = bp::parse(R"('\'ggg\'')", parser, bp::ws);
|
||||||
|
BOOST_TEST(result);
|
||||||
|
BOOST_TEST(*result == "'ggg'");
|
||||||
|
BOOST_TEST(!bp::parse(R"('\'fff\'')", parser, bp::ws));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// doc_examples
|
// doc_examples
|
||||||
@@ -244,8 +323,7 @@ int main()
|
|||||||
assert(result1);
|
assert(result1);
|
||||||
std::cout << *result1 << "\n"; // Prints: some text
|
std::cout << *result1 << "\n"; // Prints: some text
|
||||||
|
|
||||||
auto result2 =
|
auto result2 = bp::parse(R"("some \"text\"")", bp::quoted_string, bp::ws);
|
||||||
bp::parse("\"some \\\"text\\\"\"", bp::quoted_string, bp::ws);
|
|
||||||
assert(result2);
|
assert(result2);
|
||||||
std::cout << *result2 << "\n"; // Prints: some "text"
|
std::cout << *result2 << "\n"; // Prints: some "text"
|
||||||
//]
|
//]
|
||||||
@@ -279,6 +357,16 @@ int main()
|
|||||||
assert(result5);
|
assert(result5);
|
||||||
std::cout << *result5 << "\n"; // Prints (with a CRLF newline): some text
|
std::cout << *result5 << "\n"; // Prints (with a CRLF newline): some text
|
||||||
//]
|
//]
|
||||||
|
|
||||||
|
//[ quoted_string_example_6
|
||||||
|
auto result6 = bp::parse(
|
||||||
|
"'some text'", bp::quoted_string("'\"", bp::char_('g')), bp::ws);
|
||||||
|
assert(!result6);
|
||||||
|
result6 =
|
||||||
|
bp::parse("'gggg'", bp::quoted_string("'\"", bp::char_('g')), bp::ws);
|
||||||
|
assert(result6);
|
||||||
|
std::cout << *result6 << "\n"; // Prints: gggg
|
||||||
|
//]
|
||||||
}
|
}
|
||||||
|
|
||||||
return boost::report_errors();
|
return boost::report_errors();
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ int main()
|
|||||||
add_parser >> roman_numerals >> next_delete_parser >>
|
add_parser >> roman_numerals >> next_delete_parser >>
|
||||||
roman_numerals);
|
roman_numerals);
|
||||||
BOOST_TEST(result);
|
BOOST_TEST(result);
|
||||||
BOOST_TEST(*result == std::tuple(100, 100));
|
BOOST_TEST(*result == detail::hl::make_tuple(100, 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ int main()
|
|||||||
|
|
||||||
std::cout << "\n\n"
|
std::cout << "\n\n"
|
||||||
<< "----------------------------------------\n"
|
<< "----------------------------------------\n"
|
||||||
<< "| transform(f)[] |\n"
|
<< "| transform)f_[] |\n"
|
||||||
<< "----------------------------------------\n";
|
<< "----------------------------------------\n";
|
||||||
|
|
||||||
auto f = [](auto x) { return x; };
|
auto f = [](auto x) { return x; };
|
||||||
@@ -156,8 +156,6 @@ int main()
|
|||||||
<< "----------------------------------------\n";
|
<< "----------------------------------------\n";
|
||||||
|
|
||||||
PARSE(omit[char_]);
|
PARSE(omit[char_]);
|
||||||
PARSE(omit[omit[char_]]);
|
|
||||||
PARSE(omit[*omit[char_]]);
|
|
||||||
|
|
||||||
std::cout << "\n\n"
|
std::cout << "\n\n"
|
||||||
<< "----------------------------------------\n"
|
<< "----------------------------------------\n"
|
||||||
@@ -190,15 +188,6 @@ int main()
|
|||||||
PARSE(skip[char_]);
|
PARSE(skip[char_]);
|
||||||
PARSE(skip(ws)[char_]);
|
PARSE(skip(ws)[char_]);
|
||||||
|
|
||||||
std::cout << "\n\n"
|
|
||||||
<< "----------------------------------------\n"
|
|
||||||
<< "| no_case[] |\n"
|
|
||||||
<< "----------------------------------------\n";
|
|
||||||
|
|
||||||
PARSE(no_case[char_]);
|
|
||||||
PARSE(no_case[no_case[char_]]);
|
|
||||||
PARSE(no_case[*no_case[char_]]);
|
|
||||||
|
|
||||||
std::cout << "\n\n"
|
std::cout << "\n\n"
|
||||||
<< "----------------------------------------\n"
|
<< "----------------------------------------\n"
|
||||||
<< "| merge[] |\n"
|
<< "| merge[] |\n"
|
||||||
@@ -229,16 +218,6 @@ int main()
|
|||||||
PARSE(!char_);
|
PARSE(!char_);
|
||||||
PARSE(!(*char_ >> char_));
|
PARSE(!(*char_ >> char_));
|
||||||
|
|
||||||
PARSE(!char_ >> char_);
|
|
||||||
PARSE(*char_ >> !char_);
|
|
||||||
PARSE(!char_ >> *char_ >> char_ >> !char_);
|
|
||||||
try {
|
|
||||||
PARSE((!char_) > char_);
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
PARSE(*char_ > !char_);
|
|
||||||
PARSE((!char_) > *char_ >> char_ > !char_);
|
|
||||||
|
|
||||||
std::cout << "\n\n"
|
std::cout << "\n\n"
|
||||||
<< "----------------------------------------\n"
|
<< "----------------------------------------\n"
|
||||||
<< "| operator& |\n"
|
<< "| operator& |\n"
|
||||||
@@ -247,16 +226,6 @@ int main()
|
|||||||
PARSE(&char_);
|
PARSE(&char_);
|
||||||
PARSE(&(*char_ >> char_));
|
PARSE(&(*char_ >> char_));
|
||||||
|
|
||||||
PARSE(&char_ >> char_);
|
|
||||||
PARSE(*char_ >> &char_);
|
|
||||||
PARSE(&char_ >> *char_ >> char_ >> &char_);
|
|
||||||
try {
|
|
||||||
PARSE(&char_ > char_);
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
PARSE(*char_ > &char_);
|
|
||||||
PARSE(&char_ >>*char_ >> char_ > &char_);
|
|
||||||
|
|
||||||
std::cout << "\n\n"
|
std::cout << "\n\n"
|
||||||
<< "----------------------------------------\n"
|
<< "----------------------------------------\n"
|
||||||
<< "| symbols<T> |\n"
|
<< "| symbols<T> |\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user