mirror of
https://github.com/boostorg/parser.git
synced 2026-01-28 07:22:29 +00:00
337 lines
46 KiB
HTML
337 lines
46 KiB
HTML
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
|
<title>Rules</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 (Proposed)">
|
|
<link rel="up" href="../tutorial.html" title="Tutorial">
|
|
<link rel="prev" href="the__parse____api.html" title="The parse() API">
|
|
<link rel="next" href="unicode_support.html" title="Unicode Support">
|
|
</head>
|
|
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
|
<div class="spirit-nav">
|
|
<a accesskey="p" href="the__parse____api.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="unicode_support.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__proposed_.tutorial.rules"></a><a class="link" href="rules.html" title="Rules">Rules</a>
|
|
</h3></div></div></div>
|
|
<p>
|
|
We saw in the previous section how <code class="computeroutput"><a class="link" href="../../boost/parser/parse_idm17532.html" title="Function template parse">parse()</a></code>
|
|
is flexible in what types it will accept as attribute out-parameters.
|
|
</p>
|
|
<p>
|
|
That flexibility is a blessing and a curse. For instance, say you wanted
|
|
to use the parser <code class="computeroutput"><span class="special">+</span><a class="link" href="../../boost/parser/char_.html" title="Global char_">char_</a></code> to parse a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>,
|
|
and capture the result in a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>.
|
|
<code class="computeroutput"><span class="special">+</span><a class="link" href="../../boost/parser/char_.html" title="Global char_">char_</a></code> generates an
|
|
attribute of <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">char</span><span class="special">></span></code> when
|
|
parsing a sequence of <code class="computeroutput"><span class="keyword">char</span></code>,
|
|
so you'd have to write the result into a vector first, including all the
|
|
allocations that implies, and then you'd have to allocate space in a string,
|
|
and copy the entire result. Not great. The flexibility of attribute out-parameters
|
|
lets you avoid that. On the other hand, if you want to parse your result
|
|
into a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">char</span><span class="special">></span></code>,
|
|
but <span class="bold"><strong>accidentally</strong></span> pass a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>,
|
|
the code is well-formed. Usually, we expect type mismatches like this to
|
|
be ill-formed in C++. Fortunately, <code class="computeroutput"><a class="link" href="../../boost/parser/rule.html" title="Struct template rule">rules</a></code> help you address both
|
|
these concerns.
|
|
</p>
|
|
<h5>
|
|
<a name="boost_parser__proposed_.tutorial.rules.h0"></a>
|
|
<span class="phrase"><a name="boost_parser__proposed_.tutorial.rules.using__classname_alt__boost__parser__rule___code__phrase_role__identifier__rule__phrase___code_s__classname__to_nail_down_attribute_flexibility"></a></span><a class="link" href="rules.html#boost_parser__proposed_.tutorial.rules.using__classname_alt__boost__parser__rule___code__phrase_role__identifier__rule__phrase___code_s__classname__to_nail_down_attribute_flexibility">Using
|
|
rules
|
|
to nail down attribute flexibility</a>
|
|
</h5>
|
|
<p>
|
|
Every rule has a specific attribute type. If one is not specified, the rule
|
|
has no attribute. The fact that the attribute is a specific type allows you
|
|
to remove attribute flexibility. For instance, say we have a rule defined
|
|
like this:
|
|
</p>
|
|
<p>
|
|
</p>
|
|
<pre class="programlisting"><span class="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"><</span><span class="keyword">struct</span> <span class="identifier">doubles</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">double</span><span class="special">>></span> <span class="identifier">doubles</span> <span class="special">=</span> <span class="string">"doubles"</span><span class="special">;</span>
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">doubles_def</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">double_</span> <span class="special">>></span> <span class="special">*(</span><span class="char">','</span> <span class="special">>></span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">double_</span><span class="special">);</span>
|
|
<span class="identifier">BOOST_PARSER_DEFINE_RULES</span><span class="special">(</span><span class="identifier">doubles</span><span class="special">);</span>
|
|
</pre>
|
|
<p>
|
|
</p>
|
|
<p>
|
|
You can then use it in a call to <code class="computeroutput"><a class="link" href="../../boost/parser/parse_idm17532.html" title="Function template parse">parse()</a></code>,
|
|
and <code class="computeroutput"><a class="link" href="../../boost/parser/parse_idm17532.html" title="Function template parse">parse()</a></code> will return a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">double</span><span class="special">>></span></code>:
|
|
</p>
|
|
<p>
|
|
</p>
|
|
<pre class="programlisting"><span class="keyword">auto</span> <span class="keyword">const</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">input</span><span class="special">,</span> <span class="identifier">doubles</span><span class="special">,</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">ws</span><span class="special">);</span>
|
|
</pre>
|
|
<p>
|
|
</p>
|
|
<p>
|
|
If you call <code class="computeroutput"><a class="link" href="../../boost/parser/parse_idm17532.html" title="Function template parse">parse()</a></code> with an attribute out-parameter,
|
|
it must be exactly <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span></code>:
|
|
</p>
|
|
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> <span class="identifier">vec_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">input</span><span class="special">,</span> <span class="identifier">doubles</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">vec_result</span><span class="special">);</span> <span class="comment">// Ok.</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">deque</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> <span class="identifier">deque_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">input</span><span class="special">,</span> <span class="identifier">doubles</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">deque_result</span><span class="special">);</span> <span class="comment">// Ill-formed!</span>
|
|
</pre>
|
|
<p>
|
|
If we wanted to use a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">deque</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span></code> as the attribute type of our rule:
|
|
</p>
|
|
<pre class="programlisting"><span class="comment">// Attribute changed to std::deque<double>.</span>
|
|
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"><</span><span class="keyword">struct</span> <span class="identifier">doubles</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">deque</span><span class="special"><</span><span class="keyword">double</span><span class="special">>></span> <span class="identifier">doubles</span> <span class="special">=</span> <span class="string">"doubles"</span><span class="special">;</span>
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">doubles_def</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">double_</span> <span class="special">>></span> <span class="special">*(</span><span class="char">','</span> <span class="special">>></span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">double_</span><span class="special">);</span>
|
|
<span class="identifier">BOOST_PARSER_DEFINE_RULES</span><span class="special">(</span><span class="identifier">doubles</span><span class="special">);</span>
|
|
|
|
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span>
|
|
<span class="special">{</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">deque</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> <span class="identifier">deque_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">input</span><span class="special">,</span> <span class="identifier">doubles</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">deque_result</span><span class="special">);</span> <span class="comment">// Ok.</span>
|
|
<span class="special">}</span>
|
|
</pre>
|
|
<p>
|
|
So, the attribute flexibility is still available, but only <span class="bold"><strong>within</strong></span>
|
|
the rule — the parser <code class="computeroutput"><span class="identifier">bp</span><span class="special">::</span><span class="identifier">double_</span> <span class="special">>></span> <span class="special">*(</span><span class="char">','</span> <span class="special">>></span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">double_</span><span class="special">)</span></code> can parse into a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span></code> or a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">deque</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span></code>, but the rule <code class="computeroutput"><span class="identifier">doubles</span></code>
|
|
must parse into only the exact attribute it was declared to generate.
|
|
</p>
|
|
<p>
|
|
The reason for this is that, inside the rule parsing implementation, there
|
|
is code something like this:
|
|
</p>
|
|
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">attr_t</span> <span class="special">=</span> <span class="emphasis"><em><code class="literal">ATTR</code></em></span><span class="special">(</span><span class="identifier">doubles_def</span><span class="special">);</span>
|
|
<span class="identifier">attr_t</span> <span class="identifier">attr</span><span class="special">;</span>
|
|
<span class="identifier">parse</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="identifier">parser</span><span class="special">,</span> <span class="identifier">attr</span><span class="special">);</span>
|
|
<span class="identifier">attribute_out_param</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">attr</span><span class="special">);</span>
|
|
</pre>
|
|
<p>
|
|
Where <code class="computeroutput"><span class="identifier">attribute_out_param</span></code>
|
|
is the attribute out-parameter we pass to <code class="computeroutput"><a class="link" href="../../boost/parser/parse_idm17532.html" title="Function template parse">parse()</a></code>.
|
|
If that final move assignment is ill-formed, the call to <code class="computeroutput"><a class="link" href="../../boost/parser/parse_idm17532.html" title="Function template parse">parse()</a></code>
|
|
is too.
|
|
</p>
|
|
<h5>
|
|
<a name="boost_parser__proposed_.tutorial.rules.h1"></a>
|
|
<span class="phrase"><a name="boost_parser__proposed_.tutorial.rules.using_rules_to_exploit_attribute_flexibility"></a></span><a class="link" href="rules.html#boost_parser__proposed_.tutorial.rules.using_rules_to_exploit_attribute_flexibility">Using
|
|
rules to exploit attribute flexibility</a>
|
|
</h5>
|
|
<p>
|
|
So, even though a rule reduces the flexibility of attributes it can generate,
|
|
the fact that it is so easy to write a new rule means that we can use rules
|
|
themselves to get the attribute flexibility we want across our 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="comment">// We only need to write the definition once...</span>
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">generic_doubles_def</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">double_</span> <span class="special">>></span> <span class="special">*(</span><span class="char">','</span> <span class="special">>></span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">double_</span><span class="special">);</span>
|
|
|
|
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"><</span><span class="keyword">struct</span> <span class="identifier">vec_doubles</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">double</span><span class="special">>></span> <span class="identifier">vec_doubles</span> <span class="special">=</span> <span class="string">"vec_doubles"</span><span class="special">;</span>
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">vec_doubles_def</span> <span class="special">=</span> <span class="identifier">generic_doubles_def</span><span class="special">;</span> <span class="comment">// ... and re-use it,</span>
|
|
<span class="identifier">BOOST_PARSER_DEFINE_RULES</span><span class="special">(</span><span class="identifier">vec_doubles</span><span class="special">);</span>
|
|
|
|
<span class="comment">// Attribute changed to std::deque<double>.</span>
|
|
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"><</span><span class="keyword">struct</span> <span class="identifier">deque_doubles</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">deque</span><span class="special"><</span><span class="keyword">double</span><span class="special">>></span> <span class="identifier">deque_doubles</span> <span class="special">=</span> <span class="string">"deque_doubles"</span><span class="special">;</span>
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">deque_doubles_def</span> <span class="special">=</span> <span class="identifier">generic_doubles_def</span><span class="special">;</span> <span class="comment">// .. and re-use again.</span>
|
|
<span class="identifier">BOOST_PARSER_DEFINE_RULES</span><span class="special">(</span><span class="identifier">deque_doubles</span><span class="special">);</span>
|
|
</pre>
|
|
<p>
|
|
Now we have one of each, and we did not have to copy any parsing logic that
|
|
would have to be maintained in two places.
|
|
</p>
|
|
<h5>
|
|
<a name="boost_parser__proposed_.tutorial.rules.h2"></a>
|
|
<span class="phrase"><a name="boost_parser__proposed_.tutorial.rules.forward_declaration"></a></span><a class="link" href="rules.html#boost_parser__proposed_.tutorial.rules.forward_declaration">Forward
|
|
declaration</a>
|
|
</h5>
|
|
<p>
|
|
One of the advantages of using rules is that you can declare all your rules
|
|
up front and then use them immediately afterward. This lets you make rules
|
|
that use each other without introducing cycles:
|
|
</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="comment">// Assume we have some polymorphic type that can be an object/dictionary,</span>
|
|
<span class="comment">// array, string, or int, called `value_type`.</span>
|
|
|
|
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"><</span><span class="keyword">class</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">const</span> <span class="identifier">string</span> <span class="special">=</span> <span class="string">"string"</span><span class="special">;</span>
|
|
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">object_element</span><span class="special">,</span> <span class="identifier">hana</span><span class="special">::</span><span class="identifier">tuple</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">value_type</span><span class="special">>></span> <span class="keyword">const</span> <span class="identifier">object_element</span> <span class="special">=</span> <span class="string">"object-element"</span><span class="special">;</span>
|
|
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">object</span><span class="special">,</span> <span class="identifier">value_type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">object</span> <span class="special">=</span> <span class="string">"object"</span><span class="special">;</span>
|
|
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">array</span><span class="special">,</span> <span class="identifier">value_type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">array</span> <span class="special">=</span> <span class="string">"array"</span><span class="special">;</span>
|
|
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">value_tag</span><span class="special">,</span> <span class="identifier">value_type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">value</span> <span class="special">=</span> <span class="string">"value"</span><span class="special">;</span>
|
|
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">string_def</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="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">'"'</span><span class="special">)</span> <span class="special">></span> <span class="char">'"'</span><span class="special">];</span>
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">object_element_def</span> <span class="special">=</span> <span class="identifier">string</span> <span class="special">></span> <span class="char">':'</span> <span class="special">></span> <span class="identifier">value</span><span class="special">;</span>
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">object_def</span> <span class="special">=</span> <span class="char">'{'</span><span class="identifier">_l</span> <span class="special">>></span> <span class="special">-(</span><span class="identifier">object_element</span> <span class="special">%</span> <span class="char">','</span><span class="special">)</span> <span class="special">></span> <span class="char">'}'</span><span class="special">;</span>
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">array_def</span> <span class="special">=</span> <span class="char">'['</span><span class="identifier">_l</span> <span class="special">>></span> <span class="special">-(</span><span class="identifier">value</span> <span class="special">%</span> <span class="char">','</span><span class="special">)</span> <span class="special">></span> <span class="char">']'</span><span class="special">;</span>
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">value_def</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">bool_</span> <span class="special">|</span> <span class="identifier">string</span> <span class="special">|</span> <span class="identifier">array</span> <span class="special">|</span> <span class="identifier">object</span><span class="special">;</span>
|
|
|
|
<span class="identifier">BOOST_PARSER_DEFINE_RULES</span><span class="special">(</span><span class="identifier">string</span><span class="special">,</span> <span class="identifier">object_element</span><span class="special">,</span> <span class="identifier">object</span><span class="special">,</span> <span class="identifier">array</span><span class="special">,</span> <span class="identifier">value</span><span class="special">);</span>
|
|
</pre>
|
|
<p>
|
|
Here we have a parser for a Javascript-value-like type <code class="computeroutput"><span class="identifier">value_type</span></code>.
|
|
<code class="computeroutput"><span class="identifier">value_type</span></code> may be an array,
|
|
which itself may contain other arrays, objects, strings, etc. Since we need
|
|
to be able to parse objects within arrays and vice versa, we need each of
|
|
those two parsers to be able to refer to each other.
|
|
</p>
|
|
<h5>
|
|
<a name="boost_parser__proposed_.tutorial.rules.h3"></a>
|
|
<span class="phrase"><a name="boost_parser__proposed_.tutorial.rules._functionname_alt__boost__parser___val___code__phrase_role__identifier___val__phrase__phrase_role__special______phrase___code___functionname_"></a></span><a class="link" href="rules.html#boost_parser__proposed_.tutorial.rules._functionname_alt__boost__parser___val___code__phrase_role__identifier___val__phrase__phrase_role__special______phrase___code___functionname_">_val()</a>
|
|
</h5>
|
|
<p>
|
|
Inside all of a rule's semantic actions, the expression <code class="computeroutput"><a class="link" href="../../boost/parser/_val.html" title="Function template _val">_val</a><span class="special">(</span><span class="identifier">ctx</span><span class="special">)</span></code>
|
|
is a reference to the attribute that the rule generates. This can be useful
|
|
when you want subparsers to build up the attribute in a specific way:
|
|
</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">using</span> <span class="keyword">namespace</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">literals</span><span class="special">;</span>
|
|
|
|
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">ints</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">int</span><span class="special">>></span> <span class="keyword">const</span> <span class="identifier">ints</span> <span class="special">=</span> <span class="string">"ints"</span><span class="special">;</span>
|
|
<span class="keyword">auto</span> <span class="identifier">twenty_zeros</span> <span class="special">=</span> <span class="special">[](</span><span class="keyword">auto</span> <span class="special">&</span> <span class="identifier">ctx</span><span class="special">)</span> <span class="special">{</span> <span class="identifier">_val</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">).</span><span class="identifier">resize</span><span class="special">(</span><span class="number">20</span><span class="special">,</span> <span class="number">0</span><span class="special">);</span> <span class="special">};</span>
|
|
<span class="keyword">auto</span> <span class="identifier">push_back</span> <span class="special">=</span> <span class="special">[](</span><span class="keyword">auto</span> <span class="special">&</span> <span class="identifier">ctx</span><span class="special">)</span> <span class="special">{</span> <span class="identifier">_val</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">).</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">_attr</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">));</span> <span class="special">};</span>
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">ints_def</span> <span class="special">=</span> <span class="string">"20-zeros"</span><span class="identifier">_l</span><span class="special">[</span><span class="identifier">twenty_zeros</span><span class="special">]</span> <span class="special">|</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">push_back</span><span class="special">];</span>
|
|
<span class="identifier">BOOST_PARSER_DEFINE_RULES</span><span class="special">(</span><span class="identifier">ints</span><span class="special">);</span>
|
|
</pre>
|
|
<div class="tip"><table border="0" summary="Tip">
|
|
<tr>
|
|
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="../../images/tip.png"></td>
|
|
<th align="left">Tip</th>
|
|
</tr>
|
|
<tr><td align="left" valign="top"><p>
|
|
That's just an example. It's almost always better to do things without
|
|
using semantic actions. We could have instead written <code class="computeroutput"><span class="identifier">ints_def</span></code>
|
|
as <code class="computeroutput"><span class="string">"20-zeros"</span> <span class="special">>></span>
|
|
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">attr</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="number">20</span><span class="special">))</span> <span class="special">|</span>
|
|
<span class="special">+</span><span class="identifier">bp</span><span class="special">::</span><span class="identifier">int_</span></code>,
|
|
which has the same semantics, is a lot easier to read, and is a lot less
|
|
code.
|
|
</p></td></tr>
|
|
</table></div>
|
|
<h5>
|
|
<a name="boost_parser__proposed_.tutorial.rules.h4"></a>
|
|
<span class="phrase"><a name="boost_parser__proposed_.tutorial.rules.locals"></a></span><a class="link" href="rules.html#boost_parser__proposed_.tutorial.rules.locals">Locals</a>
|
|
</h5>
|
|
<p>
|
|
The <code class="computeroutput"><a class="link" href="../../boost/parser/rule.html" title="Struct template rule">rule</a></code>
|
|
template takes another template parameter we have not discussed yet. You
|
|
can pass a third parameter to <code class="computeroutput"><a class="link" href="../../boost/parser/rule.html" title="Struct template rule">rule</a></code>, which will be available
|
|
within semantic actions used in the rule as <code class="computeroutput"><a class="link" href="../../boost/parser/_locals.html" title="Function template _locals">_locals</a><span class="special">(</span><span class="identifier">ctx</span><span class="special">)</span></code>. This
|
|
gives your rule some local state, if it needs it:
|
|
</p>
|
|
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">foo_locals</span>
|
|
<span class="special">{</span>
|
|
<span class="keyword">char</span> <span class="identifier">first_value</span> <span class="special">=</span> <span class="number">0</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="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">foo</span><span class="special">,</span> <span class="keyword">int</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">foo</span> <span class="special">=</span> <span class="string">"foo"</span><span class="special">;</span>
|
|
|
|
<span class="keyword">auto</span> <span class="identifier">record_first</span> <span class="special">=</span> <span class="special">[](</span><span class="keyword">auto</span> <span class="special">&</span> <span class="identifier">ctx</span><span class="special">)</span> <span class="special">{</span> <span class="identifier">_locals</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">).</span><span class="identifier">first_value</span> <span class="special">=</span> <span class="identifier">_attr</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">);</span> <span class="special">}</span>
|
|
<span class="keyword">auto</span> <span class="identifier">check_against_first</span> <span class="special">=</span> <span class="special">[](</span><span class="keyword">auto</span> <span class="special">&</span> <span class="identifier">ctx</span><span class="special">)</span> <span class="special">{</span>
|
|
<span class="keyword">char</span> <span class="keyword">const</span> <span class="identifier">first</span> <span class="special">=</span> <span class="identifier">_locals</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">).</span><span class="identifier">first_value</span><span class="special">;</span>
|
|
<span class="keyword">char</span> <span class="keyword">const</span> <span class="identifier">attr</span> <span class="special">=</span> <span class="identifier">_attr</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">);</span>
|
|
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">attr</span> <span class="special">==</span> <span class="identifier">first</span><span class="special">)</span>
|
|
<span class="identifier">_pass</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">)</span> <span class="special">=</span> <span class="keyword">false</span><span class="special">;</span>
|
|
<span class="identifier">_val</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">)</span> <span class="special">=</span> <span class="special">(</span><span class="keyword">int</span><span class="special">(</span><span class="identifier">first</span><span class="special">)</span> <span class="special"><<</span> <span class="number">8</span><span class="special">)</span> <span class="special">|</span> <span class="keyword">int</span><span class="special">(</span><span class="identifier">attr</span><span class="special">);</span>
|
|
<span class="special">};</span>
|
|
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">foo_def</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">cu</span><span class="special">[</span><span class="identifier">record_first</span><span class="special">]</span> <span class="special">>></span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">cu</span><span class="special">[</span><span class="identifier">check_against_first</span><span class="special">];</span>
|
|
<span class="identifier">BOOST_PARSER_DEFINE_RULES</span><span class="special">(</span><span class="identifier">foo</span><span class="special">);</span>
|
|
</pre>
|
|
<p>
|
|
<code class="computeroutput"><span class="identifier">foo</span></code> matches the input if
|
|
it can match two elements of the input in a row, and if they are not the
|
|
same value. Without locals, it's a lot harder to write parsers that have
|
|
to track state as they parse.
|
|
</p>
|
|
<h5>
|
|
<a name="boost_parser__proposed_.tutorial.rules.h5"></a>
|
|
<span class="phrase"><a name="boost_parser__proposed_.tutorial.rules.parameters"></a></span><a class="link" href="rules.html#boost_parser__proposed_.tutorial.rules.parameters">Parameters</a>
|
|
</h5>
|
|
<p>
|
|
Sometimes, it is convenient to parameterize parsers. Consider this parsing
|
|
rule from the <a href="https://yaml.org/spec/1.2/spec.html" target="_top">YAML 1.2</a>
|
|
spec:
|
|
</p>
|
|
<pre class="programlisting">[137] c-flow-sequence(n,c) ::= “[” s-separate(n,c)?
|
|
ns-s-flow-seq-entries(n,in-flow(c))? “]”
|
|
</pre>
|
|
<p>
|
|
This YAML rule says that the parsing should proceed into two YAML subrules,
|
|
all or which have these <code class="computeroutput"><span class="identifier">n</span></code>
|
|
and <code class="computeroutput"><span class="identifier">c</span></code> parameters. It is certainly
|
|
possible to transliterate these YAML parsing rules to something that uses
|
|
unparameterized Boost.Parser <code class="computeroutput"><a class="link" href="../../boost/parser/rule.html" title="Struct template rule">rules</a></code>, but it is quite painful
|
|
to do so.
|
|
</p>
|
|
<p>
|
|
You give parameters to a <code class="computeroutput"><a class="link" href="../../boost/parser/rule.html" title="Struct template rule">rule</a></code> by calling its <code class="computeroutput"><span class="identifier">with</span><span class="special">()</span></code>
|
|
member. The values you pass to <code class="computeroutput"><span class="identifier">with</span><span class="special">()</span></code> are used to create a <code class="computeroutput"><span class="identifier">hana</span><span class="special">::</span><span class="identifier">tuple</span></code>
|
|
that is available in semantic actions attached to the rule, using <code class="computeroutput"><a class="link" href="../../boost/parser/_params.html" title="Function template _params">_params</a><span class="special">(</span><span class="identifier">ctx</span><span class="special">)</span></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="comment">// Declare our rules.</span>
|
|
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"></*</span> <span class="special">...</span> <span class="special">*/></span> <span class="identifier">foo</span> <span class="special">=</span> <span class="string">"foo"</span><span class="special">;</span>
|
|
<span class="identifier">bp</span><span class="special">::</span><span class="identifier">rule</span><span class="special"></*</span> <span class="special">...</span> <span class="special">*/></span> <span class="identifier">bar</span> <span class="special">=</span> <span class="string">"bar"</span><span class="special">;</span>
|
|
|
|
<span class="comment">// Get the first parameter for this rule.</span>
|
|
<span class="keyword">auto</span> <span class="identifier">first_param</span> <span class="special">=</span> <span class="special">[](</span><span class="keyword">auto</span> <span class="special">&</span> <span class="identifier">ctx</span><span class="special">)</span> <span class="special">{</span>
|
|
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">hana</span><span class="special">::</span><span class="identifier">literals</span><span class="special">;</span>
|
|
<span class="keyword">return</span> <span class="identifier">_params</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">)[</span><span class="number">0</span><span class="identifier">_c</span><span class="special">];</span>
|
|
<span class="special">};</span>
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">foo_def</span> <span class="special">=</span> <span class="identifier">bp</span><span class="special">::</span><span class="identifier">repeat</span><span class="special">(</span><span class="identifier">first_param</span><span class="special">)[</span><span class="char">' '</span><span class="identifier">_l</span><span class="special">];</span> <span class="comment">// Match ' ' the number of times indicated by the first parameter to foo.</span>
|
|
|
|
<span class="comment">// Assume that bar has a locals struct with a local_indent member, and</span>
|
|
<span class="comment">// that set_local_indent and local_indent are lambdas that respectively write</span>
|
|
<span class="comment">// and read _locals(ctx).local_indent.</span>
|
|
|
|
<span class="comment">// Parse an integer, and then pass that as a parameter to foo.</span>
|
|
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">bar_def</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">set_local_indent</span><span class="special">]</span> <span class="special">>></span> <span class="identifier">foo</span><span class="special">.</span><span class="identifier">with</span><span class="special">(</span><span class="identifier">local_indent</span><span class="special">);</span>
|
|
|
|
<span class="identifier">BOOST_PARSER_DEFINE_RULES</span><span class="special">(</span><span class="identifier">foo</span><span class="special">,</span> <span class="identifier">bar</span><span class="special">);</span>
|
|
</pre>
|
|
<p>
|
|
Passing parameters to <code class="computeroutput"><a class="link" href="../../boost/parser/rule.html" title="Struct template rule">rules</a></code> like this allows you
|
|
to easily write parsers that change the way they parse depending on contextual
|
|
data that they have previously parsed.
|
|
</p>
|
|
<h5>
|
|
<a name="boost_parser__proposed_.tutorial.rules.h6"></a>
|
|
<span class="phrase"><a name="boost_parser__proposed_.tutorial.rules.the__globalname_alt__boost__parser___p___code__phrase_role__identifier___p__phrase___code___globalname__variable_template"></a></span><a class="link" href="rules.html#boost_parser__proposed_.tutorial.rules.the__globalname_alt__boost__parser___p___code__phrase_role__identifier___p__phrase___code___globalname__variable_template">The
|
|
_p
|
|
variable template</a>
|
|
</h5>
|
|
<p>
|
|
Getting at one of a rule's arguments and passing it as an argument to another
|
|
parser can be very verbose. <code class="computeroutput"><a class="link" href="../../boost/parser/_p.html" title="Global _p">_p</a></code> is a variable template
|
|
that allows you to refer to the <code class="computeroutput"><span class="identifier">n</span></code>th
|
|
argument to the current rule, so that you can, in turn, pass it to on of
|
|
the rule's subparsers:
|
|
</p>
|
|
<pre class="programlisting"><span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">indent_n_def</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">repeat</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">_p</span><span class="special"><</span><span class="number">0</span><span class="special">>)[</span><span class="char">' '</span><span class="identifier">_l</span><span class="special">];</span>
|
|
</pre>
|
|
<p>
|
|
Using <code class="computeroutput"><a class="link" href="../../boost/parser/_p.html" title="Global _p">_p</a></code>
|
|
can prevent you from having to write a bunch of lambdas that get each get
|
|
an argument out of the parse context using <code class="computeroutput"><a class="link" href="../../boost/parser/_params.html" title="Function template _params">_params</a><span class="special">(</span><span class="identifier">ctx</span><span class="special">)[</span><span class="number">0</span><span class="identifier">_c</span><span class="special">]</span></code> or
|
|
similar.
|
|
</p>
|
|
</div>
|
|
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
|
|
<td align="left"></td>
|
|
<td align="right"><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></td>
|
|
</tr></table>
|
|
<hr>
|
|
<div class="spirit-nav">
|
|
<a accesskey="p" href="the__parse____api.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="unicode_support.html"><img src="../../images/next.png" alt="Next"></a>
|
|
</div>
|
|
</body>
|
|
</html>
|