[/
    Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.com)

    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)

    Official repository: https://github.com/boostorg/url
]

[section Compound Rules]

The rules shown so far have defined
[@https://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols ['terminal symbols]],
representing indivisible units of grammar. To parse more
complex things, a
[@https://en.wikipedia.org/wiki/Parser_combinator ['parser combinator]]
(or ['compound rule]) is a rule which accepts as parameters one
or more rules and combines them to form a higher order algorithm.
In this section we introduce the compound rules provided by the
library, and how they may be used to express more complex grammars.



[heading Tuple Rule]

Consider the following grammar:

```
version = "v" dec-octet "." dec-octet
```

We can express this using __tuple_rule__, which matches one
or more specified rules in sequence. The folllowing defines
a sequence using some character literals and two decimal octets,
which is a fancy way of saying a number between 0 and 255:

[code_grammar_3_1]

This rule has a value type of `std::tuple`, whose types correspond
to the value type of each rule specified upon construction. The decimal
octets are represented by the __dec_octet_rule__ which stores its
result in an `unsigned char`:

[code_grammar_3_2]

To extract elements from `std::tuple` the function __std_get__
must be used. In this case, we don't care to know the value for
the matching character literals. The __tuple_rule__ discards match
results whose value type is `void`. We can use the __squelch__
compound rule to convert a matching value type to `void`, and
reformulate our rule:

[code_grammar_3_3]

When all but one of the value types is `void`, the `std::tuple` is
elided and the remaining value type is promoted to the result of
the match:

[code_grammar_3_4]



[heading Optional Rule]

BNF elements in brackets denote optional components. These are
expressed using __optional_rule__, whose value type is an
__optional__. For example, we can adapt the port rule from
above to be an optional component:

[code_grammar_3_5]

In this example we build up a rule to represent an
endpoint as an IPv4 address with an optional port:

[code_grammar_3_6]

This can be simplified; the library provides __ipv4_address_rule__
whose result type is __ipv4_address__, offering more utility
than representing the address simply as a collection of four numbers:

[code_grammar_3_7]



[heading Variant Rule]

BNF elements separated by unquoted slashes represent a set
of alternatives from which one element may match. We represent
them using __variant_rule__, whose value type is a __variant__.
Consider the following HTTP production rule which comes from
[@https://datatracker.ietf.org/doc/html/rfc7230#section-5.3" rfc7230]:

```
request-target = origin-form
                / absolute-form
                / authority-form
                / asterisk-form
```

The ['request-target] can be exactly one of these things. Here we
define the rule, using __origin_form_rule__, __absolute_uri_rule__,
and __authority_rule__ which come with the library, and obtain
a result from parsing a string:

[code_grammar_3_8]

In the next section we discuss facilities to parse a
repeating number of elements.



[endsect]
