PrevUpHomeNext

Combining Operations

Certain overloaded operators are defined for all parsers in Boost.Parser. We've already seen some of them used in this tutorial, especially operator>>, operator|, and operator||, which are used to form sequence parsers, alternative parsers, and permutation parsers, respectively.

Here are all the operator overloaded for parsers. In the tables below:

[Note] Note

Some of the expressions in this table consume no input. All parsers consume the input they match unless otherwise stated in the table below.

Table 1.7. Combining Operations and Their Semantics

Expression

Semantics

Attribute Type

Notes

!p

Matches iff p does not match; consumes no input.

None.

&p

Matches iff p matches; consumes no input.

None.

*p

Parses using p repeatedly until p no longer matches; always matches.

std::string if ATTR(p) is char or char32_t, otherwise std::vector<ATTR(p)>

Matching eps an unlimited number of times creates an infinite loop, which is undefined behavior in C++. Boost.Parser will assert in debug mode when it encounters *eps (this applies to unconditional eps only).

+p

Parses using p repeatedly until p no longer matches; matches iff p matches at least once.

std::string if ATTR(p) is char or char32_t, otherwise std::vector<ATTR(p)>

Matching eps an unlimited number of times creates an infinite loop, which is undefined behavior in C++. Boost.Parser will assert in debug mode when it encounters +eps (this applies to unconditional eps only).

-p

Equivalent to p | eps.

std::optional<ATTR(p)>

p1 >> p2

Matches iff p1 matches and then p2 matches.

boost::parser::tuple<ATTR(p1), ATTR(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 Attribute Generation for the full rules.

p >> c

Equivalent to p >> lit(c).

ATTR(p)

p >> r

Equivalent to p >> lit(r).

ATTR(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.

boost::parser::tuple<ATTR(p1), ATTR(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 Attribute Generation for the full rules.

p > c

Equivalent to p > lit(c).

ATTR(p)

p > r

Equivalent to p > lit(r).

ATTR(p)

p1 | p2

Matches iff either p1 matches or p2 matches.

std::variant<ATTR(p1), ATTR(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 Attribute Generation for the full rules.

p | c

Equivalent to p | lit(c).

ATTR(p)

p | r

Equivalent to p | lit(r).

ATTR(p)

p1 || p2

Matches iff p1 matches and p2 matches, regardless of the order they match in.

boost::parser::tuple<ATTR(p1), ATTR(p2)>

|| is associative; p1 || p2 || p3, (p1 || p2) || p3, and p1 || (p2 || p3) are all equivalent. It is an error to include a eps (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(p1)

p - c

Equivalent to p - lit(c).

ATTR(p)

p - r

Equivalent to p - lit(r).

ATTR(p)

p1 % p2

Equivalent to p1 >> *(p2 >> p1).

std::string if ATTR(p) is char or char32_t, otherwise std::vector<ATTR(p1)>

p % c

Equivalent to p % lit(c).

std::string if ATTR(p) is char or char32_t, otherwise std::vector<ATTR(p)>

p % r

Equivalent to p % lit(r).

std::string if ATTR(p) is char or char32_t, otherwise std::vector<ATTR(p)>

p[a]

Matches iff p matches. If p matches, the semantic action a is executed.

None.


[Important] Important

All the character parsers, like char_, cp and cu produce either char or char32_t attributes. So when you see "std::string if ATTR(p) is char or char32_t, otherwise std::vector<ATTR(p)>" in the table above, that effectively means that every sequences of character attributes get turned into a std::string. The only time this does not happen is when you introduce your own rules with attributes using another character type (or use attribute to do so).

There are a couple of special rules not captured in the table above:

First, the zero-or-more and one-or-more repetitions (operator*() and operator+(), respectively) may collapse when combined. For any parser p, +(+p) collapses to +p; **p, *+p, and +*p each collapse to just *p.

Second, using eps in an alternative parser as any alternative except the last one is a common source of errors; Boost.Parser disallows it. This is true because, for any parser p, eps | p is equivalent to eps, since eps always matches. This is not true for eps parameterized with a condition. For any condition cond, eps(cond) is allowed to appear anywhere within an alternative parser.

[Note] Note

When looking at Boost.Parser parsers in a debugger, or when looking at their reference documentation, you may see reference to the template parser_interface. This template exists to provide the operator overloads described above. It allows the parsers themselves to be very simple — most parsers are just a struct with two member functions. parser_interface is essentially invisible when using Boost.Parser, and you should never have to name this template in your own code.


PrevUpHomeNext