2
0
mirror of https://github.com/boostorg/parser.git synced 2026-01-21 17:12:16 +00:00
Files
parser/doc/html/boost_parser/tutorial/attribute_generation.html
2024-12-08 17:19:48 -06:00

1695 lines
132 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Attribute Generation</title>
<link rel="stylesheet" href="../../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Chapter 1. Boost.Parser">
<link rel="up" href="../tutorial.html" title="Tutorial">
<link rel="prev" href="combining_operations.html" title="Combining Operations">
<link rel="next" href="the__parse____api.html" title="The parse() API">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="spirit-nav">
<a accesskey="p" href="combining_operations.html"><img src="../../images/prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.html"><img src="../../images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../images/home.png" alt="Home"></a><a accesskey="n" href="the__parse____api.html"><img src="../../images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="boost_parser.tutorial.attribute_generation"></a><a class="link" href="attribute_generation.html" title="Attribute Generation">Attribute
Generation</a>
</h3></div></div></div>
<p>
So far, we've seen several different types of attributes that come from different
parsers, <code class="computeroutput"><span class="keyword">int</span></code> for <code class="computeroutput"><a class="link" href="../../boost/parser/int_.html" title="Global int_">int_</a></code>,
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="keyword">char</span><span class="special">,</span>
<span class="keyword">int</span><span class="special">&gt;</span></code>
for <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">::</span><span class="identifier">char_</span> <span class="special">&gt;&gt;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">::</span><span class="identifier">int_</span></code>, etc. Let's get into how this works
with more rigor.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
Some parsers have no attribute at all. In the tables below, the type of
the attribute is listed as "None." There is a non-<code class="computeroutput"><span class="keyword">void</span></code> type that is returned from each parser
that lacks an attribute. This keeps the logic simple; having to handle
the two cases — <code class="computeroutput"><span class="keyword">void</span></code>
or non-<code class="computeroutput"><span class="keyword">void</span></code> — would
make the library significantly more complicated. The type of this non-<code class="computeroutput"><span class="keyword">void</span></code> attribute associated with these parsers
is an implementation detail. The type comes from the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">::</span><span class="identifier">detail</span></code>
namespace and is pretty useless. You should never see this type in practice.
Within semantic actions, asking for the attribute of a non-attribute-producing
parser (using <code class="computeroutput"><span class="identifier">_attr</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">)</span></code>)
will yield a value of the special type <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">::</span><span class="identifier">none</span></code>.
When calling <code class="computeroutput"><a class="link" href="../../boost/parser/parse_id2.html" title="Function template parse">parse()</a></code> in a form that returns
the attribute parsed, when there is no attribute, simply returns <code class="computeroutput"><span class="keyword">bool</span></code>; this indicates the success of failure
of the parse.
</p></td></tr>
</table></div>
<div class="warning"><table border="0" summary="Warning">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="../../images/warning.png"></td>
<th align="left">Warning</th>
</tr>
<tr><td align="left" valign="top"><p>
Boost.Parser assumes that all attributes are semi-regular (see <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">semiregular</span></code>). Within the Boost.Parser
code, attributes are assigned, moved, copy, and default constructed. There
is no support for move-only or non-default-constructible types.
</p></td></tr>
</table></div>
<h5>
<a name="boost_parser.tutorial.attribute_generation.h0"></a>
<span class="phrase"><a name="boost_parser.tutorial.attribute_generation.the_attribute_type_trait___classname_alt__boost__parser__attribute___code__phrase_role__identifier__attribute__phrase___code___classname_"></a></span><a class="link" href="attribute_generation.html#boost_parser.tutorial.attribute_generation.the_attribute_type_trait___classname_alt__boost__parser__attribute___code__phrase_role__identifier__attribute__phrase___code___classname_">The
attribute type trait, attribute</a>
</h5>
<p>
You can use <code class="computeroutput"><a class="link" href="../../boost/parser/attribute.html" title="Struct template attribute">attribute</a></code>
(and the associated alias, <code class="computeroutput"><a class="link" href="../../boost/parser/attribute_t.html" title="Type definition attribute_t">attribute_t</a></code>) to determine the
attribute a parser would have if it were passed to <code class="computeroutput"><a class="link" href="../../boost/parser/parse_id2.html" title="Function template parse">parse()</a></code>.
Since at least one parser (<code class="computeroutput"><a class="link" href="../../boost/parser/char_.html" title="Global char_">char_</a></code>) has a polymorphic attribute
type, <code class="computeroutput"><a class="link" href="../../boost/parser/attribute.html" title="Struct template attribute">attribute</a></code>
also takes the type of the range being parsed. If a parser produces no attribute,
<code class="computeroutput"><a class="link" href="../../boost/parser/attribute.html" title="Struct template attribute">attribute</a></code>
will produce <code class="computeroutput"><a class="link" href="../../boost/parser/none.html" title="Struct none">none</a></code>,
not <code class="computeroutput"><span class="keyword">void</span></code>.
</p>
<p>
If you want to feed an iterator/sentinel pair to <code class="computeroutput"><a class="link" href="../../boost/parser/attribute.html" title="Struct template attribute">attribute</a></code>, create a range from
it like so:
</p>
<pre class="programlisting"><span class="keyword">constexpr</span> <span class="keyword">auto</span> <span class="identifier">parser</span> <span class="special">=</span> <span class="comment">/* ... */</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">first</span> <span class="special">=</span> <span class="comment">/* ... */</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">last</span> <span class="special">=</span> <span class="comment">/* ... */</span><span class="special">;</span>
<span class="keyword">namespace</span> <span class="identifier">bp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">;</span>
<span class="comment">// You can of course use std::ranges::subrange directly in C++20 and later.</span>
<span class="keyword">using</span> <span class="identifier">attr_type</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">attribute_t</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">BOOST_PARSER_SUBRANGE</span><span class="special">(</span><span class="identifier">first</span><span class="special">,</span> <span class="identifier">last</span><span class="special">)),</span> <span class="keyword">decltype</span><span class="special">(</span><span class="identifier">parser</span><span class="special">)&gt;;</span>
</pre>
<p>
There is no single attribute type for any parser, since a parser can be placed
within <code class="computeroutput"><a class="link" href="../../boost/parser/omit.html" title="Global omit">omit[]</a></code>, which makes its attribute
type <code class="computeroutput"><a class="link" href="../../boost/parser/none.html" title="Struct none">none</a></code>.
Therefore, <code class="computeroutput"><a class="link" href="../../boost/parser/attribute.html" title="Struct template attribute">attribute</a></code>
cannot tell you what attribute your parser will produce under all circumstances;
it only tells you what it would produce if it were passed to <code class="computeroutput"><a class="link" href="../../boost/parser/parse_id2.html" title="Function template parse">parse()</a></code>.
</p>
<h5>
<a name="boost_parser.tutorial.attribute_generation.h1"></a>
<span class="phrase"><a name="boost_parser.tutorial.attribute_generation.parser_attributes"></a></span><a class="link" href="attribute_generation.html#boost_parser.tutorial.attribute_generation.parser_attributes">Parser
attributes</a>
</h5>
<p>
This table summarizes the attributes generated for all Boost.Parser parsers.
In the table below:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
<span class="emphasis"><em><code class="literal">RESOLVE</code></em></span><code class="computeroutput"><span class="special">()</span></code>
is a notional macro that expands to the resolution of parse argument
or evaluation of a parse predicate (see <a class="link" href="the_parsers_and_their_uses.html" title="The Parsers And Their Uses">The
Parsers And Their Uses</a>); and
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">x</span></code> and <code class="computeroutput"><span class="identifier">y</span></code>
represent arbitrary objects.
</li>
</ul></div>
<div class="table">
<a name="boost_parser.tutorial.attribute_generation.t0"></a><p class="title"><b>Table 1.8. Parsers and Their Attributes</b></p>
<div class="table-contents"><table class="table" summary="Parsers and Their Attributes">
<colgroup>
<col>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
Parser
</p>
</th>
<th>
<p>
Attribute Type
</p>
</th>
<th>
<p>
Notes
</p>
</th>
</tr></thead>
<tbody>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/eps.html" title="Global eps">eps</a></code>
</p>
</td>
<td>
<p>
None.
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/eol.html" title="Global eol">eol</a></code>
</p>
</td>
<td>
<p>
None.
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/eoi.html" title="Global eoi">eoi</a></code>
</p>
</td>
<td>
<p>
None.
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/attr.html" title="Function template attr">attr</a><span class="special">(</span><span class="identifier">x</span><span class="special">)</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">decltype</span><span class="special">(</span><span class="emphasis"><em><code class="literal">RESOLVE</code></em></span><span class="special">(</span><span class="identifier">x</span><span class="special">))</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/char_.html" title="Global char_">char_</a></code>
</p>
</td>
<td>
<p>
The code point type in Unicode parsing, or <code class="computeroutput"><span class="keyword">char</span></code>
in non-Unicode parsing; see below.
</p>
</td>
<td>
<p>
Includes all the <code class="computeroutput"><span class="identifier">_p</span></code>
<a href="https://en.cppreference.com/w/cpp/language/user_literal" target="_top">UDLs</a>
that take a single character, and all character class parsers like
<code class="computeroutput"><span class="identifier">control</span></code> and <code class="computeroutput"><span class="identifier">lower</span></code>.
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/cp.html" title="Global cp">cp</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">char32_t</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/cu.html" title="Global cu">cu</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">char</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/lit_id9.html" title="Function lit">lit</a><span class="special">(</span><span class="identifier">x</span><span class="special">)</span></code>
</p>
</td>
<td>
<p>
None.
</p>
</td>
<td>
<p>
Includes all the <code class="computeroutput"><span class="identifier">_l</span></code>
<a href="https://en.cppreference.com/w/cpp/language/user_literal" target="_top">UDLs</a>.
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/string.html" title="Function template string">string</a><span class="special">(</span><span class="identifier">x</span><span class="special">)</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
</p>
</td>
<td>
<p>
Includes all the <code class="computeroutput"><span class="identifier">_p</span></code>
<a href="https://en.cppreference.com/w/cpp/language/user_literal" target="_top">UDLs</a>
that take a string.
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/bool_.html" title="Global bool_">bool_</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">bool</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/bin.html" title="Global bin">bin</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">unsigned</span> <span class="keyword">int</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/oct.html" title="Global oct">oct</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">unsigned</span> <span class="keyword">int</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/hex.html" title="Global hex">hex</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">unsigned</span> <span class="keyword">int</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/ushort_.html" title="Global ushort_">ushort_</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">unsigned</span> <span class="keyword">short</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/uint_.html" title="Global uint_">uint_</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">unsigned</span> <span class="keyword">int</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/ulong_.html" title="Global ulong_">ulong_</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">unsigned</span> <span class="keyword">long</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/ulong_long.html" title="Global ulong_long">ulong_long</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">unsigned</span> <span class="keyword">long</span>
<span class="keyword">long</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/short_.html" title="Global short_">short_</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">short</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/int_.html" title="Global int_">int_</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">int</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/long_.html" title="Global long_">long_</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">long</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/long_long.html" title="Global long_long">long_long</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">long</span> <span class="keyword">long</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/float_.html" title="Global float_">float_</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">float</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/double_.html" title="Global double_">double_</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="keyword">double</span></code>
</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/symbols.html" title="Struct template symbols">symbols&lt;T&gt;</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">T</span></code>
</p>
</td>
<td>
</td>
</tr>
</tbody>
</table></div>
</div>
<br class="table-break"><p>
<code class="computeroutput"><a class="link" href="../../boost/parser/char_.html" title="Global char_">char_</a></code>
is a bit odd, since its attribute type is polymorphic. When you use <code class="computeroutput"><a class="link" href="../../boost/parser/char_.html" title="Global char_">char_</a></code>
to parse text in the non-Unicode code path (i.e. a string of <code class="computeroutput"><span class="keyword">char</span></code>), the attribute is <code class="computeroutput"><span class="keyword">char</span></code>.
When you use the exact same <code class="computeroutput"><a class="link" href="../../boost/parser/char_.html" title="Global char_">char_</a></code> to parse in the Unicode-aware
code path, all matching is code point based, and so the attribute type is
the type used to represent code points, <code class="computeroutput"><span class="keyword">char32_t</span></code>.
All parsing of UTF-8 falls under this case.
</p>
<p>
Here, we're parsing plain <code class="computeroutput"><span class="keyword">char</span></code>s,
meaning that the parsing is in the non-Unicode code path, the attribute of
<code class="computeroutput"><a class="link" href="../../boost/parser/char_.html" title="Global char_">char_</a></code>
is <code class="computeroutput"><span class="keyword">char</span></code>:
</p>
<pre class="programlisting"><span class="keyword">auto</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">parse</span><span class="special">(</span><span class="string">"some text"</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">::</span><span class="identifier">char_</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same_v</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">result</span><span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">&gt;&gt;));</span>
</pre>
<p>
When you parse UTF-8, the matching is done on a code point basis, so the
attribute type is <code class="computeroutput"><span class="keyword">char32_t</span></code>:
</p>
<pre class="programlisting"><span class="keyword">auto</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">parse</span><span class="special">(</span><span class="string">"some text"</span> <span class="special">|</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">::</span><span class="identifier">as_utf8</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">::</span><span class="identifier">char_</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same_v</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">result</span><span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="keyword">char32_t</span><span class="special">&gt;&gt;));</span>
</pre>
<p>
The good news is that usually you don't parse characters individually. When
you parse with <code class="computeroutput"><a class="link" href="../../boost/parser/char_.html" title="Global char_">char_</a></code>,
you usually parse repetition of then, which will produce a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>,
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 attribute type,
you can use <code class="computeroutput"><a class="link" href="../../boost/parser/cp.html" title="Global cp">cp</a></code>
and/or <code class="computeroutput"><a class="link" href="../../boost/parser/cu.html" title="Global cu">cu</a></code>
to enforce a non-polymorphic attribute type.
</p>
<h5>
<a name="boost_parser.tutorial.attribute_generation.h2"></a>
<span class="phrase"><a name="boost_parser.tutorial.attribute_generation.combining_operation_attributes"></a></span><a class="link" href="attribute_generation.html#boost_parser.tutorial.attribute_generation.combining_operation_attributes">Combining
operation attributes</a>
</h5>
<p>
Combining operations of course affect the generation of attributes. In the
tables below:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
<code class="computeroutput"><span class="identifier">m</span></code> and <code class="computeroutput"><span class="identifier">n</span></code>
are parse arguments that resolve to integral values;
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">pred</span></code> is a parse predicate;
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">arg0</span></code>, <code class="computeroutput"><span class="identifier">arg1</span></code>,
<code class="computeroutput"><span class="identifier">arg2</span></code>, ... are parse arguments;
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">a</span></code> is a semantic action;
and
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">p</span></code>, <code class="computeroutput"><span class="identifier">p1</span></code>,
<code class="computeroutput"><span class="identifier">p2</span></code>, ... are parsers that
generate attributes.
</li>
</ul></div>
<div class="table">
<a name="boost_parser.tutorial.attribute_generation.t1"></a><p class="title"><b>Table 1.9. Combining Operations and Their Attributes</b></p>
<div class="table-contents"><table class="table" summary="Combining Operations and Their Attributes">
<colgroup>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
Parser
</p>
</th>
<th>
<p>
Attribute Type
</p>
</th>
</tr></thead>
<tbody>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">!</span><span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
None.
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">&amp;</span><span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
None.
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">*</span><span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> if <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> is <code class="computeroutput"><span class="keyword">char</span></code>
or <code class="computeroutput"><span class="keyword">char32_t</span></code>, otherwise
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">+</span><span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> if <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> is <code class="computeroutput"><span class="keyword">char</span></code>
or <code class="computeroutput"><span class="keyword">char32_t</span></code>, otherwise
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">+*</span><span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> if <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> is <code class="computeroutput"><span class="keyword">char</span></code>
or <code class="computeroutput"><span class="keyword">char32_t</span></code>, otherwise
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">*+</span><span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> if <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> is <code class="computeroutput"><span class="keyword">char</span></code>
or <code class="computeroutput"><span class="keyword">char32_t</span></code>, otherwise
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">-</span><span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">&gt;&gt;</span>
<span class="identifier">p2</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">&gt;</span>
<span class="identifier">p2</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">&gt;&gt;</span>
<span class="identifier">p2</span> <span class="special">&gt;&gt;</span>
<span class="identifier">p3</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p3</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">&gt;</span>
<span class="identifier">p2</span> <span class="special">&gt;&gt;</span>
<span class="identifier">p3</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p3</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">&gt;&gt;</span>
<span class="identifier">p2</span> <span class="special">&gt;</span>
<span class="identifier">p3</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p3</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">&gt;</span>
<span class="identifier">p2</span> <span class="special">&gt;</span>
<span class="identifier">p3</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p3</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">|</span>
<span class="identifier">p2</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">|</span>
<span class="identifier">p2</span> <span class="special">|</span>
<span class="identifier">p3</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p3</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">||</span>
<span class="identifier">p2</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">||</span>
<span class="identifier">p2</span> <span class="special">||</span>
<span class="identifier">p3</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p3</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">%</span>
<span class="identifier">p2</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> if <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> is <code class="computeroutput"><span class="keyword">char</span></code>
or <code class="computeroutput"><span class="keyword">char32_t</span></code>, otherwise
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p</span><span class="special">[</span><span class="identifier">a</span><span class="special">]</span></code>
</p>
</td>
<td>
<p>
None.
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/repeat_id13.html" title="Function template repeat">repeat</a><span class="special">(</span><span class="identifier">arg0</span><span class="special">)[</span><span class="identifier">p</span><span class="special">]</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> if <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> is <code class="computeroutput"><span class="keyword">char</span></code>
or <code class="computeroutput"><span class="keyword">char32_t</span></code>, otherwise
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/repeat_id13.html" title="Function template repeat">repeat</a><span class="special">(</span><span class="identifier">arg0</span><span class="special">,</span> <span class="identifier">arg1</span><span class="special">)[</span><span class="identifier">p</span><span class="special">]</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> if <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> is <code class="computeroutput"><span class="keyword">char</span></code>
or <code class="computeroutput"><span class="keyword">char32_t</span></code>, otherwise
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/if_.html" title="Function template if_">if_</a><span class="special">(</span><span class="identifier">pred</span><span class="special">)[</span><span class="identifier">p</span><span class="special">]</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/switch_.html" title="Function template switch_">switch_</a><span class="special">(</span><span class="identifier">arg0</span><span class="special">)(</span><span class="identifier">arg1</span><span class="special">,</span> <span class="identifier">p1</span><span class="special">)(</span><span class="identifier">arg2</span><span class="special">,</span> <span class="identifier">p2</span><span class="special">)...</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">),</span> <span class="special">...&gt;</span></code>
</p>
</td>
</tr>
</tbody>
</table></div>
</div>
<br class="table-break"><div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
All the character parsers, like <code class="computeroutput"><a class="link" href="../../boost/parser/char_.html" title="Global char_">char_</a></code>, <code class="computeroutput"><a class="link" href="../../boost/parser/cp.html" title="Global cp">cp</a></code> and <code class="computeroutput"><a class="link" href="../../boost/parser/cu.html" title="Global cu">cu</a></code> produce either <code class="computeroutput"><span class="keyword">char</span></code> or <code class="computeroutput"><span class="keyword">char32_t</span></code>
attributes. So when you see "<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
if <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> is
<code class="computeroutput"><span class="keyword">char</span></code> or <code class="computeroutput"><span class="keyword">char32_t</span></code>,
otherwise <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>"
in the table above, that effectively means that every sequences of character
attributes get turned into a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>.
The only time this does not happen is when you introduce your own rules
with attributes using another character type (or use <code class="computeroutput"><a class="link" href="../../boost/parser/attribute.html" title="Struct template attribute">attribute</a></code> to do so).
</p></td></tr>
</table></div>
<div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
In case you did not notice it above, adding a semantic action to a parser
erases the parser's attribute. The attribute is still available inside
the semantic action as <code class="computeroutput"><span class="identifier">_attr</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">)</span></code>.
</p></td></tr>
</table></div>
<p>
There are a relatively small number of rules that define how sequence parsers
and alternative parsers' attributes are generated. (Don't worry, there are
examples below.)
</p>
<h5>
<a name="boost_parser.tutorial.attribute_generation.h3"></a>
<span class="phrase"><a name="boost_parser.tutorial.attribute_generation.sequence_parser_attribute_rules"></a></span><a class="link" href="attribute_generation.html#boost_parser.tutorial.attribute_generation.sequence_parser_attribute_rules">Sequence
parser attribute rules</a>
</h5>
<p>
The attribute generation behavior of sequence parsers is conceptually pretty
simple:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
the attributes of subparsers form a tuple of values;
</li>
<li class="listitem">
subparsers that do not generate attributes do not contribute to the sequence's
attribute;
</li>
<li class="listitem">
subparsers that do generate attributes usually contribute an individual
element to the tuple result; except
</li>
<li class="listitem">
when containers of the same element type are next to each other, or individual
elements are next to containers of their type, the two adjacent attributes
collapse into one attribute; and
</li>
<li class="listitem">
if the result of all that is a degenerate tuple <code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>
(even if <code class="computeroutput"><span class="identifier">T</span></code> is a type
that means "no attribute"), the attribute becomes <code class="computeroutput"><span class="identifier">T</span></code>.
</li>
</ul></div>
<p>
More formally, the attribute generation algorithm works like this. For a
sequence parser <code class="computeroutput"><span class="identifier">p</span></code>, let the
list of attribute types for the subparsers of <code class="computeroutput"><span class="identifier">p</span></code>
be <code class="computeroutput"><span class="identifier">a0</span><span class="special">,</span>
<span class="identifier">a1</span><span class="special">,</span> <span class="identifier">a2</span><span class="special">,</span> <span class="special">...,</span>
<span class="identifier">an</span></code>.
</p>
<p>
We get the attribute of <code class="computeroutput"><span class="identifier">p</span></code>
by evaluating a compile-time left fold operation, <code class="computeroutput"><span class="identifier">left</span><span class="special">-</span><span class="identifier">fold</span><span class="special">({</span><span class="identifier">a1</span><span class="special">,</span> <span class="identifier">a2</span><span class="special">,</span> <span class="special">...,</span> <span class="identifier">an</span><span class="special">},</span> <span class="identifier">tuple</span><span class="special">&lt;</span><span class="identifier">a0</span><span class="special">&gt;,</span> <span class="identifier">OP</span><span class="special">)</span></code>. <code class="computeroutput"><span class="identifier">OP</span></code>
is the combining operation that takes the current attribute type (initially
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="identifier">a0</span><span class="special">&gt;</span></code>) and the next attribute type, and returns
the new current attribute type. The current attribute type at the end of
the fold operation is the attribute type for <code class="computeroutput"><span class="identifier">p</span></code>.
</p>
<p>
<code class="computeroutput"><span class="identifier">OP</span></code> attempts to apply a series
of rules, one at a time. The rules are noted as <code class="computeroutput"><span class="identifier">X</span>
<span class="special">&gt;&gt;</span> <span class="identifier">Y</span>
<span class="special">-&gt;</span> <span class="identifier">Z</span></code>,
where <code class="computeroutput"><span class="identifier">X</span></code> is the type of the
current attribute, <code class="computeroutput"><span class="identifier">Y</span></code> is the
type of the next attribute, and <code class="computeroutput"><span class="identifier">Z</span></code>
is the new current attribute type. In these rules, <code class="computeroutput"><span class="identifier">C</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>
is a container of <code class="computeroutput"><span class="identifier">T</span></code>; <code class="computeroutput"><span class="identifier">none</span></code> is a special type that indicates that
there is no attribute; <code class="computeroutput"><span class="identifier">T</span></code>
is a type; <code class="computeroutput"><span class="identifier">CHAR</span></code> is a character
type, either <code class="computeroutput"><span class="keyword">char</span></code> or <code class="computeroutput"><span class="keyword">char32_t</span></code>; and <code class="computeroutput"><span class="identifier">Ts</span><span class="special">...</span></code> is a parameter pack of one or more types.
Note that <code class="computeroutput"><span class="identifier">T</span></code> may be the special
type <code class="computeroutput"><span class="identifier">none</span></code>. The current attribute
is always a tuple (call it <code class="computeroutput"><span class="identifier">Tup</span></code>),
so the "current attribute <code class="computeroutput"><span class="identifier">X</span></code>"
refers to the last element of <code class="computeroutput"><span class="identifier">Tup</span></code>,
not <code class="computeroutput"><span class="identifier">Tup</span></code> itself, except for
those rules that explicitly mention <code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;&gt;</span></code>
as part of <code class="computeroutput"><span class="identifier">X</span></code>'s type.
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
<code class="computeroutput"><span class="identifier">none</span> <span class="special">&gt;&gt;</span>
<span class="identifier">T</span> <span class="special">-&gt;</span>
<span class="identifier">T</span></code>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">CHAR</span></code> &gt;&gt; <code class="computeroutput"><span class="identifier">CHAR</span></code> -&gt; <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">T</span> <span class="special">&gt;&gt;</span>
<span class="identifier">none</span> <span class="special">-&gt;</span>
<span class="identifier">T</span></code>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">C</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span> <span class="special">&gt;&gt;</span> <span class="identifier">T</span>
<span class="special">-&gt;</span> <span class="identifier">C</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">T</span> <span class="special">&gt;&gt;</span>
<span class="identifier">C</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span> <span class="special">-&gt;</span> <span class="identifier">C</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">C</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span> <span class="special">&gt;&gt;</span> <span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span> <span class="special">-&gt;</span> <span class="identifier">C</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span> <span class="special">&gt;&gt;</span> <span class="identifier">C</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span> <span class="special">-&gt;</span> <span class="identifier">C</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>
</li>
<li class="listitem">
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="identifier">none</span><span class="special">&gt;</span> <span class="special">&gt;&gt;</span>
<span class="identifier">T</span> <span class="special">-&gt;</span>
<a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>
</li>
<li class="listitem">
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="identifier">Ts</span><span class="special">...&gt;</span> <span class="special">&gt;&gt;</span>
<span class="identifier">T</span> <span class="special">-&gt;</span>
<a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="identifier">Ts</span><span class="special">...,</span> <span class="identifier">T</span><span class="special">&gt;</span></code>
</li>
</ul></div>
<p>
The rules that combine containers with (possibly optional) adjacent values
(e.g. <code class="computeroutput"><span class="identifier">C</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span> <span class="special">&gt;&gt;</span> <span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span>
<span class="special">-&gt;</span> <span class="identifier">C</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>)
have a special case for strings. If <code class="computeroutput"><span class="identifier">C</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>
is exactly <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>, and <code class="computeroutput"><span class="identifier">T</span></code>
is either <code class="computeroutput"><span class="keyword">char</span></code> or <code class="computeroutput"><span class="keyword">char32_t</span></code>, the combination yields a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>.
</p>
<p>
Again, if the final result is that the attribute is <code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>,
the attribute becomes <code class="computeroutput"><span class="identifier">T</span></code>.
</p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top">
<p>
What constitutes a container in the rules above is determined by the <code class="computeroutput"><span class="identifier">container</span></code> concept:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="identifier">concept</span> <span class="identifier">container</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ranges</span><span class="special">::</span><span class="identifier">common_range</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span> <span class="special">&amp;&amp;</span> <span class="identifier">requires</span><span class="special">(</span><span class="identifier">T</span> <span class="identifier">t</span><span class="special">)</span> <span class="special">{</span>
<span class="special">{</span> <span class="identifier">t</span><span class="special">.</span><span class="identifier">insert</span><span class="special">(</span><span class="identifier">t</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="special">*</span><span class="identifier">t</span><span class="special">.</span><span class="identifier">begin</span><span class="special">())</span> <span class="special">}</span>
<span class="special">-&gt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">same_as</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ranges</span><span class="special">::</span><span class="identifier">iterator_t</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;;</span>
<span class="special">};</span>
</pre>
<p>
</p>
</td></tr>
</table></div>
<h5>
<a name="boost_parser.tutorial.attribute_generation.h4"></a>
<span class="phrase"><a name="boost_parser.tutorial.attribute_generation.alternative_parser_attribute_rules"></a></span><a class="link" href="attribute_generation.html#boost_parser.tutorial.attribute_generation.alternative_parser_attribute_rules">Alternative
parser attribute rules</a>
</h5>
<p>
The rules for alternative parsers are much simpler. For an alternative parer
<code class="computeroutput"><span class="identifier">p</span></code>, let the list of attribute
types for the subparsers of <code class="computeroutput"><span class="identifier">p</span></code>
be <code class="computeroutput"><span class="identifier">a0</span><span class="special">,</span>
<span class="identifier">a1</span><span class="special">,</span> <span class="identifier">a2</span><span class="special">,</span> <span class="special">...,</span>
<span class="identifier">an</span></code>. The attribute of <code class="computeroutput"><span class="identifier">p</span></code> is <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="identifier">a0</span><span class="special">,</span> <span class="identifier">a1</span><span class="special">,</span>
<span class="identifier">a2</span><span class="special">,</span> <span class="special">...,</span> <span class="identifier">an</span><span class="special">&gt;</span></code>, with the following steps applied:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
all the <code class="computeroutput"><span class="identifier">none</span></code> attributes
are left out, and if any are, the attribute is wrapped in a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span></code>, like <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;/*...*/&gt;&gt;</span></code>;
</li>
<li class="listitem">
duplicates in the <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span></code>
template parameters <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">T1</span><span class="special">,</span> <span class="identifier">T2</span><span class="special">,</span> <span class="special">...</span> <span class="identifier">Tn</span><span class="special">&gt;</span></code> are removed; every type that appears
does so exacly once;
</li>
<li class="listitem">
if the attribute is <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code> or <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;</span></code>, the attribute becomes instead
<code class="computeroutput"><span class="identifier">T</span></code> or <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>, respectively; and
</li>
<li class="listitem">
if the attribute is <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;&gt;</span></code> or <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;&gt;&gt;</span></code>, the result becomes <code class="computeroutput"><span class="identifier">none</span></code> instead.
</li>
</ul></div>
<h5>
<a name="boost_parser.tutorial.attribute_generation.h5"></a>
<span class="phrase"><a name="boost_parser.tutorial.attribute_generation.formation_of_containers_in_attributes"></a></span><a class="link" href="attribute_generation.html#boost_parser.tutorial.attribute_generation.formation_of_containers_in_attributes">Formation
of containers in attributes</a>
</h5>
<p>
The rule for forming containers from non-containers is simple. You get a
vector from any of the repeating parsers, like <code class="computeroutput"><span class="special">+</span><span class="identifier">p</span></code>, <code class="computeroutput"><span class="special">*</span><span class="identifier">p</span></code>, <code class="computeroutput"><span class="identifier">repeat</span><span class="special">(</span><span class="number">3</span><span class="special">)[</span><span class="identifier">p</span><span class="special">]</span></code>, etc.
The value type of the vector is <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code>.
</p>
<p>
Another rule for sequence containers is that a value <code class="computeroutput"><span class="identifier">x</span></code>
and a container <code class="computeroutput"><span class="identifier">c</span></code> containing
elements of <code class="computeroutput"><span class="identifier">x</span></code>'s type will
form a single container. However, <code class="computeroutput"><span class="identifier">x</span></code>'s
type must be exactly the same as the elements in <code class="computeroutput"><span class="identifier">c</span></code>.
There is an exception to this in the special case for strings and characters
noted above. For instance, consider the attribute of <code class="computeroutput"><span class="identifier">char_</span>
<span class="special">&gt;&gt;</span> <span class="identifier">string</span><span class="special">(</span><span class="string">"str"</span><span class="special">)</span></code>. In the non-Unicode code path, <code class="computeroutput"><span class="identifier">char_</span></code>'s attribute type is guaranteed to
be <code class="computeroutput"><span class="keyword">char</span></code>, so <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">char_</span> <span class="special">&gt;&gt;</span> <span class="identifier">string</span><span class="special">(</span><span class="string">"str"</span><span class="special">))</span></code> is <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>.
If you are parsing UTF-8 in the Unicode code path, <code class="computeroutput"><span class="identifier">char_</span></code>'s
attribute type is <code class="computeroutput"><span class="keyword">char32_t</span></code>,
and the special rule makes it also produce a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>.
Otherwise, the attribute for <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">char_</span> <span class="special">&gt;&gt;</span> <span class="identifier">string</span><span class="special">(</span><span class="string">"str"</span><span class="special">))</span></code> would be <code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="keyword">char32_t</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;</span></code>.
</p>
<p>
Again, there are no special rules for combining values and containers. Every
combination results from an exact match, or fall into the string+character
special case.
</p>
<h5>
<a name="boost_parser.tutorial.attribute_generation.h6"></a>
<span class="phrase"><a name="boost_parser.tutorial.attribute_generation.another_special_case___code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__string__phrase___code__assignment"></a></span><a class="link" href="attribute_generation.html#boost_parser.tutorial.attribute_generation.another_special_case___code__phrase_role__identifier__std__phrase__phrase_role__special______phrase__phrase_role__identifier__string__phrase___code__assignment">Another
special case: <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> assignment</a>
</h5>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> can be assigned from a <code class="computeroutput"><span class="keyword">char</span></code>. This is dumb. But, we're stuck with
it. When you write a parser with a <code class="computeroutput"><span class="keyword">char</span></code>
attribute, and you try to parse it into a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>,
you've almost certainly made a mistake. More importantly, if you write this:
</p>
<pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">bp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">result</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">b</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">parse</span><span class="special">(</span><span class="string">"3"</span><span class="special">,</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">int_</span><span class="special">,</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">ws</span><span class="special">,</span> <span class="identifier">result</span><span class="special">);</span>
</pre>
<p>
... you are even more likely to have made a mistake. Though this should work,
because the assignment in <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">s</span><span class="special">;</span> <span class="identifier">s</span>
<span class="special">=</span> <span class="number">3</span><span class="special">;</span></code> is well-formed, Boost.Parser forbids it.
If you write parsing code like the snippet above, you will get a static assertion.
If you really do want to assign a <code class="computeroutput"><span class="keyword">float</span></code>
or whatever to a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>, do it in a semantic action.
</p>
<h5>
<a name="boost_parser.tutorial.attribute_generation.h7"></a>
<span class="phrase"><a name="boost_parser.tutorial.attribute_generation.examples_of_attributes_generated_by_sequence_and_alternative_parsers"></a></span><a class="link" href="attribute_generation.html#boost_parser.tutorial.attribute_generation.examples_of_attributes_generated_by_sequence_and_alternative_parsers">Examples
of attributes generated by sequence and alternative parsers</a>
</h5>
<p>
In the table: <code class="computeroutput"><span class="identifier">a</span></code> is a semantic
action; and <code class="computeroutput"><span class="identifier">p</span></code>, <code class="computeroutput"><span class="identifier">p1</span></code>, <code class="computeroutput"><span class="identifier">p2</span></code>,
... are parsers that generate attributes. Note that only <code class="computeroutput"><span class="special">&gt;&gt;</span></code>
is used here; <code class="computeroutput"><span class="special">&gt;</span></code> has the exact
same attribute generation rules.
</p>
<div class="table">
<a name="boost_parser.tutorial.attribute_generation.t2"></a><p class="title"><b>Table 1.10. Sequence and Alternative Combining Operations and Their Attributes</b></p>
<div class="table-contents"><table class="table" summary="Sequence and Alternative Combining Operations and Their Attributes">
<colgroup>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
Expression
</p>
</th>
<th>
<p>
Attribute Type
</p>
</th>
</tr></thead>
<tbody>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/eps.html" title="Global eps">eps</a>
<span class="special">&gt;&gt;</span> <a class="link" href="../../boost/parser/eps.html" title="Global eps">eps</a></code>
</p>
</td>
<td>
<p>
None.
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p</span> <span class="special">&gt;&gt;</span>
<a class="link" href="../../boost/parser/eps.html" title="Global eps">eps</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/eps.html" title="Global eps">eps</a>
<span class="special">&gt;&gt;</span> <span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/cu.html" title="Global cu">cu</a>
<span class="special">&gt;&gt;</span> <a class="link" href="../../boost/parser/string.html" title="Function template string">string</a><span class="special">(</span><span class="string">"str"</span><span class="special">)</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/string.html" title="Function template string">string</a><span class="special">(</span><span class="string">"str"</span><span class="special">)</span> <span class="special">&gt;&gt;</span>
<a class="link" href="../../boost/parser/cu.html" title="Global cu">cu</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">*</span><a class="link" href="../../boost/parser/cu.html" title="Global cu">cu</a> <span class="special">&gt;&gt;</span>
<a class="link" href="../../boost/parser/string.html" title="Function template string">string</a><span class="special">(</span><span class="string">"str"</span><span class="special">)</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/string.html" title="Function template string">string</a><span class="special">(</span><span class="string">"str"</span><span class="special">)</span> <span class="special">&gt;&gt;</span>
<span class="special">*</span><a class="link" href="../../boost/parser/cu.html" title="Global cu">cu</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p</span> <span class="special">&gt;&gt;</span>
<span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">*</span><span class="identifier">p</span>
<span class="special">&gt;&gt;</span> <span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> if <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> is <code class="computeroutput"><span class="keyword">char</span></code>
or <code class="computeroutput"><span class="keyword">char32_t</span></code>, otherwise
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p</span> <span class="special">&gt;&gt;</span>
<span class="special">*</span><span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> if <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> is <code class="computeroutput"><span class="keyword">char</span></code>
or <code class="computeroutput"><span class="keyword">char32_t</span></code>, otherwise
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">*</span><span class="identifier">p</span>
<span class="special">&gt;&gt;</span> <span class="special">-</span><span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> if <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> is <code class="computeroutput"><span class="keyword">char</span></code>
or <code class="computeroutput"><span class="keyword">char32_t</span></code>, otherwise
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">-</span><span class="identifier">p</span>
<span class="special">&gt;&gt;</span> <span class="special">*</span><span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> if <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code> is <code class="computeroutput"><span class="keyword">char</span></code>
or <code class="computeroutput"><span class="keyword">char32_t</span></code>, otherwise
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/string.html" title="Function template string">string</a><span class="special">(</span><span class="string">"str"</span><span class="special">)</span> <span class="special">&gt;&gt;</span>
<span class="special">-</span><a class="link" href="../../boost/parser/cu.html" title="Global cu">cu</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">-</span><a class="link" href="../../boost/parser/cu.html" title="Global cu">cu</a> <span class="special">&gt;&gt;</span>
<a class="link" href="../../boost/parser/string.html" title="Function template string">string</a><span class="special">(</span><span class="string">"str"</span><span class="special">)</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="special">!</span><span class="identifier">p1</span>
<span class="special">|</span> <span class="identifier">p2</span><span class="special">[</span><span class="identifier">a</span><span class="special">]</span></code>
</p>
</td>
<td>
<p>
None.
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p</span> <span class="special">|</span>
<span class="identifier">p</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">|</span>
<span class="identifier">p2</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p</span> <span class="special">|</span>
</code><code class="computeroutput"><a class="link" href="../../boost/parser/eps.html" title="Global eps">eps</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">|</span>
<span class="identifier">p2</span> <span class="special">|</span>
<a class="link" href="../../boost/parser/eps.html" title="Global eps">eps</a></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p2</span><span class="special">)&gt;&gt;</span></code>
</p>
</td>
</tr>
<tr>
<td>
<p>
<code class="computeroutput"><span class="identifier">p1</span> <span class="special">|</span>
<span class="identifier">p2</span><span class="special">[</span><span class="identifier">a</span><span class="special">]</span>
<span class="special">|</span> <span class="identifier">p3</span></code>
</p>
</td>
<td>
<p>
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">variant</span><span class="special">&lt;</span><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p1</span><span class="special">),</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p3</span><span class="special">)&gt;&gt;</span></code>
</p>
</td>
</tr>
</tbody>
</table></div>
</div>
<br class="table-break"><h5>
<a name="boost_parser.tutorial.attribute_generation.h8"></a>
<span class="phrase"><a name="boost_parser.tutorial.attribute_generation.controlling_attribute_generation_with__globalname_alt__boost__parser__merge___code__phrase_role__identifier__merge__phrase__phrase_role__special______phrase___code___globalname__and__globalname_alt__boost__parser__separate___code__phrase_role__identifier__separate__phrase__phrase_role__special______phrase___code___globalname_"></a></span><a class="link" href="attribute_generation.html#boost_parser.tutorial.attribute_generation.controlling_attribute_generation_with__globalname_alt__boost__parser__merge___code__phrase_role__identifier__merge__phrase__phrase_role__special______phrase___code___globalname__and__globalname_alt__boost__parser__separate___code__phrase_role__identifier__separate__phrase__phrase_role__special______phrase___code___globalname_">Controlling
attribute generation with merge[]
and separate[]</a>
</h5>
<p>
As we saw in the previous <a class="link" href="parsing_into__struct_s_and__class_es.html" title="Parsing into structs and classes">Parsing
into <code class="computeroutput"><span class="keyword">struct</span></code>s and <code class="computeroutput"><span class="keyword">class</span></code>es</a> section, if you parse two strings
in a row, you get two separate strings in the resulting attribute. The parser
from that example was this:
</p>
<pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">bp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">employee_parser</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">lit</span><span class="special">(</span><span class="string">"employee"</span><span class="special">)</span>
<span class="special">&gt;&gt;</span> <span class="char">'{'</span>
<span class="special">&gt;&gt;</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">int_</span> <span class="special">&gt;&gt;</span> <span class="char">','</span>
<span class="special">&gt;&gt;</span> <span class="identifier">quoted_string</span> <span class="special">&gt;&gt;</span> <span class="char">','</span>
<span class="special">&gt;&gt;</span> <span class="identifier">quoted_string</span> <span class="special">&gt;&gt;</span> <span class="char">','</span>
<span class="special">&gt;&gt;</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">double_</span>
<span class="special">&gt;&gt;</span> <span class="char">'}'</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">employee_parser</span></code>'s attribute
is <code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span> <span class="keyword">double</span><span class="special">&gt;</span></code>.
The two <code class="computeroutput"><span class="identifier">quoted_string</span></code> parsers
produce <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code> attributes, and those attributes
are not combined. That is the default behavior, and it is just what we want
for this case; we don't want the first and last name fields to be jammed
together such that we can't tell where one name ends and the other begins.
What if we were parsing some string that consisted of a prefix and a suffix,
and the prefix and suffix were defined separately for reuse elsewhere?
</p>
<pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">bp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">prefix</span> <span class="special">=</span> <span class="comment">/* ... */</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">suffix</span> <span class="special">=</span> <span class="comment">/* ... */</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">special_string</span> <span class="special">=</span> <span class="identifier">prefix</span> <span class="special">&gt;&gt;</span> <span class="identifier">suffix</span><span class="special">;</span>
<span class="comment">// Continue to use prefix and suffix to make other parsers....</span>
</pre>
<p>
In this case, we might want to use these separate parsers, but want <code class="computeroutput"><span class="identifier">special_string</span></code> to produce a single <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
for its attribute. <code class="computeroutput"><a class="link" href="../../boost/parser/merge.html" title="Global merge">merge[]</a></code> exists for this purpose.
</p>
<pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">bp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">prefix</span> <span class="special">=</span> <span class="comment">/* ... */</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">suffix</span> <span class="special">=</span> <span class="comment">/* ... */</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">special_string</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">merge</span><span class="special">[</span><span class="identifier">prefix</span> <span class="special">&gt;&gt;</span> <span class="identifier">suffix</span><span class="special">];</span>
</pre>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/merge.html" title="Global merge">merge[]</a></code> only applies to sequence parsers
(like <code class="computeroutput"><span class="identifier">p1</span> <span class="special">&gt;&gt;</span>
<span class="identifier">p2</span></code>), and forces all subparsers
in the sequence parser to use the same variable for their attribute.
</p>
<p>
Another directive, <code class="computeroutput"><a class="link" href="../../boost/parser/separate.html" title="Global separate">separate[]</a></code>,
also applies only to sequence parsers, but does the opposite of <code class="computeroutput"><a class="link" href="../../boost/parser/merge.html" title="Global merge">merge[]</a></code>. If forces all the attributes
produced by the subparsers of the sequence parser to stay separate, even
if they would have combined. For instance, consider this parser.
</p>
<pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">bp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">string_and_char</span> <span class="special">=</span> <span class="special">+</span><span class="identifier">bp</span><span class="special">::</span><span class="identifier">char_</span><span class="special">(</span><span class="char">'a'</span><span class="special">)</span> <span class="special">&gt;&gt;</span> <span class="char">' '</span> <span class="special">&gt;&gt;</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">cp</span><span class="special">;</span>
</pre>
<p>
<code class="computeroutput"><span class="identifier">string_and_char</span></code> matches one
or more <code class="computeroutput"><span class="char">'a'</span></code>s, followed by some
other character. As written above, <code class="computeroutput"><span class="identifier">string_and_char</span></code>
produces a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>, and the final character is appended
to the string, after all the <code class="computeroutput"><span class="char">'a'</span></code>s.
However, if you wanted to store the final character as a separate value,
you would use <code class="computeroutput"><a class="link" href="../../boost/parser/separate.html" title="Global separate">separate[]</a></code>.
</p>
<pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">bp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">string_and_char</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">separate</span><span class="special">[+</span><span class="identifier">bp</span><span class="special">::</span><span class="identifier">char_</span><span class="special">(</span><span class="char">'a'</span><span class="special">)</span> <span class="special">&gt;&gt;</span> <span class="char">' '</span> <span class="special">&gt;&gt;</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">cp</span><span class="special">];</span>
</pre>
<p>
With this change, <code class="computeroutput"><span class="identifier">string_and_char</span></code>
produces the attribute <code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span> <span class="keyword">char32_t</span><span class="special">&gt;</span></code>.
</p>
<h5>
<a name="boost_parser.tutorial.attribute_generation.h9"></a>
<span class="phrase"><a name="boost_parser.tutorial.attribute_generation._globalname_alt__boost__parser__merge___code__phrase_role__identifier__merge__phrase__phrase_role__special______phrase___code___globalname__and__globalname_alt__boost__parser__separate___code__phrase_role__identifier__separate__phrase__phrase_role__special______phrase___code___globalname__in_more_detail"></a></span><a class="link" href="attribute_generation.html#boost_parser.tutorial.attribute_generation._globalname_alt__boost__parser__merge___code__phrase_role__identifier__merge__phrase__phrase_role__special______phrase___code___globalname__and__globalname_alt__boost__parser__separate___code__phrase_role__identifier__separate__phrase__phrase_role__special______phrase___code___globalname__in_more_detail">merge[] and separate[]
in more detail</a>
</h5>
<p>
As mentioned previously, <code class="computeroutput"><a class="link" href="../../boost/parser/merge.html" title="Global merge">merge[]</a></code>
applies only to sequence parsers. All subparsers must have the same attribute,
or produce no attribute at all. At least one subparser must produce an attribute.
When you use <code class="computeroutput"><a class="link" href="../../boost/parser/merge.html" title="Global merge">merge[]</a></code>, you create a <span class="emphasis"><em>combining
group</em></span>. Every parser in a combining group uses the same variable
for its attribute. No parser in a combining group interacts with the attributes
of any parsers outside of its combining group. Combining groups are disjoint;
<code class="computeroutput"><span class="identifier">merge</span><span class="special">[/*...*/]</span>
<span class="special">&gt;&gt;</span> <span class="identifier">merge</span><span class="special">[/*...*/]</span></code> will produce a tuple of two attributes,
not one.
</p>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/separate.html" title="Global separate">separate[]</a></code> also applies only to sequence
parsers. When you use <code class="computeroutput"><a class="link" href="../../boost/parser/separate.html" title="Global separate">separate[]</a></code>,
you disable interaction of all the subparsers' attributes with adjacent attributes,
whether they are inside or outside the <code class="computeroutput"><a class="link" href="../../boost/parser/separate.html" title="Global separate">separate[]</a></code>
directive; you force each subparser to have a separate attribute.
</p>
<p>
The rules for <code class="computeroutput"><a class="link" href="../../boost/parser/merge.html" title="Global merge">merge[]</a></code> and <code class="computeroutput"><a class="link" href="../../boost/parser/separate.html" title="Global separate">separate[]</a></code>
overrule the steps of the algorithm described above for combining the attributes
of a sequence parser. Consider an example.
</p>
<pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">bp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">;</span>
<span class="keyword">constexpr</span> <span class="keyword">auto</span> <span class="identifier">parser</span> <span class="special">=</span>
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">char_</span> <span class="special">&gt;&gt;</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">merge</span><span class="special">[(</span><span class="identifier">bp</span><span class="special">::</span><span class="identifier">string</span><span class="special">(</span><span class="string">"abc"</span><span class="special">)</span> <span class="special">&gt;&gt;</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">char_</span> <span class="special">&gt;&gt;</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">char_</span><span class="special">)</span> <span class="special">&gt;&gt;</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">string</span><span class="special">(</span><span class="string">"ghi"</span><span class="special">)];</span>
</pre>
<p>
You might think that <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">parser</span><span class="special">)</span></code> would be <code class="computeroutput"><span class="identifier">bp</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">,</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;</span></code>.
It is not. The parser above does not even compile. Since we created a merge
group above, we disabled the default behavior in which the <code class="computeroutput"><span class="identifier">char_</span></code> parsers would have collapsed into
the <code class="computeroutput"><span class="identifier">string</span></code> parser that preceded
them. Since they are all treated as separate entities, and since they have
different attribute types, the use of <code class="computeroutput"><a class="link" href="../../boost/parser/merge.html" title="Global merge">merge[]</a></code>
is an error.
</p>
<p>
Many directives create a new parser out of the parser they are given. <code class="computeroutput"><a class="link" href="../../boost/parser/merge.html" title="Global merge">merge[]</a></code> and <code class="computeroutput"><a class="link" href="../../boost/parser/separate.html" title="Global separate">separate[]</a></code>
do not. Since they operate only on sequence parsers, all they do is create
a copy of the sequence parser they are given. The <code class="computeroutput"><a class="link" href="../../boost/parser/seq_parser.html" title="Struct template seq_parser">seq_parser</a></code> template has a template
parameter <code class="computeroutput"><span class="identifier">CombiningGroups</span></code>,
and all <code class="computeroutput"><a class="link" href="../../boost/parser/merge.html" title="Global merge">merge[]</a></code> and <code class="computeroutput"><a class="link" href="../../boost/parser/separate.html" title="Global separate">separate[]</a></code>
do is take a given <code class="computeroutput"><a class="link" href="../../boost/parser/seq_parser.html" title="Struct template seq_parser">seq_parser</a></code> and create a copy
of it with a different <code class="computeroutput"><span class="identifier">CombiningGroups</span></code>
template parameter. This means that <code class="computeroutput"><a class="link" href="../../boost/parser/merge.html" title="Global merge">merge[]</a></code>
and <code class="computeroutput"><a class="link" href="../../boost/parser/separate.html" title="Global separate">separate[]</a></code> are can be ignored in <code class="computeroutput"><span class="keyword">operator</span><span class="special">&gt;&gt;</span></code>
expressions much like parentheses are. Consider an example.
</p>
<pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">bp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">;</span>
<span class="keyword">constexpr</span> <span class="keyword">auto</span> <span class="identifier">parser1</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">separate</span><span class="special">[</span><span class="identifier">bp</span><span class="special">::</span><span class="identifier">int_</span> <span class="special">&gt;&gt;</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">int_</span><span class="special">]</span> <span class="special">&gt;&gt;</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">int_</span><span class="special">;</span>
<span class="keyword">constexpr</span> <span class="keyword">auto</span> <span class="identifier">parser2</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">lexeme</span><span class="special">[</span><span class="identifier">bp</span><span class="special">::</span><span class="identifier">int_</span> <span class="special">&gt;&gt;</span> <span class="char">' '</span> <span class="special">&gt;&gt;</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">int_</span><span class="special">]</span> <span class="special">&gt;&gt;</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">int_</span><span class="special">;</span>
</pre>
<p>
Note that <code class="computeroutput"><a class="link" href="../../boost/parser/separate.html" title="Global separate">separate[]</a></code> is a no-op here; it's only
being used this way for this example. These parsers have different attribute
types. <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">parser1</span><span class="special">)</span></code>
is <code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">(</span><span class="keyword">int</span><span class="special">,</span>
<span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">)</span></code>. <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">parser2</span><span class="special">)</span></code> is <code class="computeroutput"><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">(</span><a class="link" href="../../boost/parser/tuple.html" title="Type definition tuple">boost::parser::tuple</a><span class="special">(</span><span class="keyword">int</span><span class="special">,</span>
<span class="keyword">int</span><span class="special">),</span> <span class="keyword">int</span><span class="special">)</span></code>. This
is because <code class="computeroutput"><span class="identifier">bp</span><span class="special">::</span><span class="identifier">lexeme</span><span class="special">[]</span></code>
wraps its given parser in a new parser. <code class="computeroutput"><a class="link" href="../../boost/parser/merge.html" title="Global merge">merge[]</a></code>
does not. That's why, even though <code class="computeroutput"><span class="identifier">parser1</span></code>
and <code class="computeroutput"><span class="identifier">parser2</span></code> look so structurally
similar, they have different attributes.
</p>
<h5>
<a name="boost_parser.tutorial.attribute_generation.h10"></a>
<span class="phrase"><a name="boost_parser.tutorial.attribute_generation._globalname_alt__boost__parser__transform___code__phrase_role__identifier__transform__phrase__phrase_role__special_____phrase__phrase_role__identifier__f__phrase__phrase_role__special_______phrase___code___globalname_"></a></span><a class="link" href="attribute_generation.html#boost_parser.tutorial.attribute_generation._globalname_alt__boost__parser__transform___code__phrase_role__identifier__transform__phrase__phrase_role__special_____phrase__phrase_role__identifier__f__phrase__phrase_role__special_______phrase___code___globalname_"><code class="computeroutput">transform(f)[]</code></a>
</h5>
<p>
<code class="computeroutput">transform(f)[]</code>
is a directive that transforms the attribute of a parser using the given
function <code class="computeroutput"><span class="identifier">f</span></code>. For example:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">auto</span> <span class="identifier">str_sum</span> <span class="special">=</span> <span class="special">[&amp;](</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span> <span class="special">&amp;</span> <span class="identifier">s</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">int</span> <span class="identifier">retval</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
<span class="keyword">for</span> <span class="special">(</span><span class="keyword">auto</span> <span class="identifier">ch</span> <span class="special">:</span> <span class="identifier">s</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">retval</span> <span class="special">+=</span> <span class="identifier">ch</span> <span class="special">-</span> <span class="char">'0'</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">return</span> <span class="identifier">retval</span><span class="special">;</span>
<span class="special">};</span>
<span class="keyword">namespace</span> <span class="identifier">bp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">;</span>
<span class="keyword">constexpr</span> <span class="keyword">auto</span> <span class="identifier">parser</span> <span class="special">=</span> <span class="special">+</span><span class="identifier">bp</span><span class="special">::</span><span class="identifier">char_</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">str</span> <span class="special">=</span> <span class="string">"012345"</span><span class="special">;</span>
<span class="keyword">auto</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">parse</span><span class="special">(</span><span class="identifier">str</span><span class="special">,</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">transform</span><span class="special">(</span><span class="identifier">str_sum</span><span class="special">)[</span><span class="identifier">parser</span><span class="special">]);</span>
<span class="identifier">assert</span><span class="special">(</span><span class="identifier">result</span><span class="special">);</span>
<span class="identifier">assert</span><span class="special">(*</span><span class="identifier">result</span> <span class="special">==</span> <span class="number">15</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same_v</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">result</span><span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;&gt;);</span>
</pre>
<p>
</p>
<p>
Here, we have a function <code class="computeroutput"><span class="identifier">str_sum</span></code>
that we use for <code class="computeroutput"><span class="identifier">f</span></code>. It assumes
each character in the given <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>
<code class="computeroutput"><span class="identifier">s</span></code> is a digit, and returns
the sum of all the digits in <code class="computeroutput"><span class="identifier">s</span></code>.
Out parser <code class="computeroutput"><span class="identifier">parser</span></code> would normally
return a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>. However, since <code class="computeroutput"><span class="identifier">str_sum</span></code>
returns a different type — <code class="computeroutput"><span class="keyword">int</span></code>
— that is the attribute type of the full parser, <code class="computeroutput"><span class="identifier">bp</span><span class="special">::</span><span class="identifier">transform</span><span class="special">(</span><span class="identifier">by_value_str_sum</span><span class="special">)[</span><span class="identifier">parser</span><span class="special">]</span></code>, as you can see from the <code class="computeroutput"><span class="keyword">static_assert</span></code>.
</p>
<p>
As is the case with attributes all throughout Boost.Parser, the attribute
passed to <code class="computeroutput"><span class="identifier">f</span></code> will be moved.
You can take it by <code class="computeroutput"><span class="keyword">const</span> <span class="special">&amp;</span></code>,
<code class="computeroutput"><span class="special">&amp;&amp;</span></code>, or by value.
</p>
<p>
No distinction is made between parsers with and without an attribute, because
there is a Regular special no-attribute type that is generated by parsers
with no attribute. You may therefore write something like <code class="computeroutput">transform<span class="special">(</span><span class="identifier">f</span><span class="special">)[</span><a class="link" href="../../boost/parser/eps.html" title="Global eps">eps</a><span class="special">]</span></code>, and Boost.Parser will happily call <code class="computeroutput"><span class="identifier">f</span></code> with this special no-attribute type.
</p>
<h5>
<a name="boost_parser.tutorial.attribute_generation.h11"></a>
<span class="phrase"><a name="boost_parser.tutorial.attribute_generation.other_directives_that_affect_attribute_generation"></a></span><a class="link" href="attribute_generation.html#boost_parser.tutorial.attribute_generation.other_directives_that_affect_attribute_generation">Other
directives that affect attribute generation</a>
</h5>
<p>
<code class="computeroutput"><a class="link" href="../../boost/parser/omit.html" title="Global omit">omit</a><span class="special">[</span><span class="identifier">p</span><span class="special">]</span></code>
disables attribute generation for the parser <code class="computeroutput"><span class="identifier">p</span></code>.
<code class="computeroutput"><a class="link" href="../../boost/parser/raw.html" title="Global raw">raw</a><span class="special">[</span><span class="identifier">p</span><span class="special">]</span></code>
changes the attribute from <code class="computeroutput"><span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">p</span><span class="special">)</span></code>
to a view that indicates the subrange of the input that was matched by <code class="computeroutput"><span class="identifier">p</span></code>. <code class="computeroutput"><a class="link" href="../../boost/parser/string_view.html" title="Global string_view">string_view</a><span class="special">[</span><span class="identifier">p</span><span class="special">]</span></code> is just
like <code class="computeroutput"><a class="link" href="../../boost/parser/raw.html" title="Global raw">raw</a><span class="special">[</span><span class="identifier">p</span><span class="special">]</span></code>,
except that it produces <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">basic_string_view</span></code>s.
See <a class="link" href="directives.html" title="Directives">Directives</a> for
details.
</p>
</div>
<div class="copyright-footer">Copyright © 2020 T. Zachary Laine<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="combining_operations.html"><img src="../../images/prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.html"><img src="../../images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../images/home.png" alt="Home"></a><a accesskey="n" href="the__parse____api.html"><img src="../../images/next.png" alt="Next"></a>
</div>
</body>
</html>