Let's look at a slightly more complicated example, even if it is still trivial.
Instead of taking any old chars
we're given, let's require some structure. Let's parse one or more doubles, separated by commas.
The Boost.Parser parser for double
is double_.
So, to parse a single double,
we'd just use that. If we wanted to parse two doubles
in a row, we'd use:
boost::parser::double_ >> boost::parser::double_
operator>>
in this expression is the sequence-operator; read it as "followed by".
If we combine the sequence-operator with Kleene
star, we can get the parser we want by writing:
boost::parser::double_ >> *(',' >> boost::parser::double_)
This is a parser that matches at least one double
— because of the first double_ in the expression
above — followed by zero or more instances of a-comma-followed-by-a-double. Notice that we can use ',' directly. Though it is not a parser, operator>>
and the other operators defined on Boost.Parser parsers have overloads that
accept character/parser pairs of arguments; these operator overloads will
create the right parser to recognize ','.
#include <boost/parser/parser.hpp> #include <iostream> #include <string> namespace bp = boost::parser; int main() { std::cout << "Enter a list of doubles, separated by commas. No pressure. "; std::string input; std::getline(std::cin, input); auto const result = bp::parse(input, bp::double_ >> *(',' >> bp::double_)); if (result) { std::cout << "Great! It looks like you entered:\n"; for (double x : *result) { std::cout << x << "\n"; } } else { std::cout << "Good job! Please proceed to the recovery annex for cake.\n"; } }
The first example filled in an out-parameter to deliver the result of the
parse. This call to parse()
returns a result instead. As you can see, the result is contextually convertible
to bool, and *result is some sort of range. In fact,
the return type of this call to parse()
is std::optional<std::vector<double>>. Naturally, if the parse fails,
std::nullopt is returned. We'll look at how
Boost.Parser maps the type of the parser to the return type, or the filled
in out-parameter's type, a bit later.
![]() |
Note |
|---|---|
There's a type trait that can tell you the attribute type for a parser,
|
If I run it in a shell, this is the result:
$ example/trivial Enter a list of doubles, separated by commas. No pressure. 5.6,8.9 Great! It looks like you entered: 5.6 8.9 $ example/trivial Enter a list of doubles, separated by commas. No pressure. 5.6, 8.9 Good job! Please proceed to the recovery annex for cake.
It does not recognize "5.6, 8.9".
This is because it expects a comma followed immediately
by a double, but I inserted
a space after the comma. The same failure to parse would occur if I put a
space before the comma, or before or after the list of doubles.
One more thing: there is a much better way to write the parser above. Instead
of repeating the double_
subparser, we could have written this:
bp::double_ % ','
That's semantically identical to bp::double_ >> *(',' >> bp::double_). This pattern — some bit of input
repeated one or more times, with a separator between each instance —
comes up so often that there's an operator specifically for that, operator%.
We'll be using that operator from now on.