mirror of
https://github.com/boostorg/parser.git
synced 2026-01-23 17:52:15 +00:00
150 lines
14 KiB
HTML
150 lines
14 KiB
HTML
<html>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
<title>A Trivial Example</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="hello__whomever.html" title="Hello, Whomever">
|
||
<link rel="next" href="a_trivial_example_that_gracefully_handles_whitespace.html" title="A Trivial Example That Gracefully Handles Whitespace">
|
||
<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="hello__whomever.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="a_trivial_example_that_gracefully_handles_whitespace.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.a_trivial_example"></a><a class="link" href="a_trivial_example.html" title="A Trivial Example">A Trivial Example</a>
|
||
</h3></div></div></div>
|
||
<p>
|
||
Let's look at a slightly more complicated example, even if it is still trivial.
|
||
Instead of taking any old <code class="computeroutput"><span class="keyword">char</span></code>s
|
||
we're given, let's require some structure. Let's parse one or more <code class="computeroutput"><span class="keyword">double</span></code>s, separated by commas.
|
||
</p>
|
||
<p>
|
||
The Boost.Parser parser for <code class="computeroutput"><span class="keyword">double</span></code>
|
||
is <code class="computeroutput"><a class="link" href="../../boost/parser/double_.html" title="Global double_">double_</a></code>.
|
||
So, to parse a single <code class="computeroutput"><span class="keyword">double</span></code>,
|
||
we'd just use that. If we wanted to parse two <code class="computeroutput"><span class="keyword">double</span></code>s
|
||
in a row, we'd use:
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">::</span><span class="identifier">double_</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">double_</span>
|
||
</pre>
|
||
<p>
|
||
<code class="computeroutput"><span class="keyword">operator</span><span class="special">>></span></code>
|
||
in this expression is the sequence-operator; read it as "followed by".
|
||
If we combine the sequence-operator with <a href="https://en.wikipedia.org/wiki/Kleene_star" target="_top">Kleene
|
||
star</a>, we can get the parser we want by writing:
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">parser</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">boost</span><span class="special">::</span><span class="identifier">parser</span><span class="special">::</span><span class="identifier">double_</span><span class="special">)</span>
|
||
</pre>
|
||
<p>
|
||
This is a parser that matches at least one <code class="computeroutput"><span class="keyword">double</span></code>
|
||
— because of the first <code class="computeroutput"><a class="link" href="../../boost/parser/double_.html" title="Global double_">double_</a></code> in the expression
|
||
above — followed by zero or more instances of a-comma-followed-by-a-<code class="computeroutput"><span class="keyword">double</span></code>. Notice that we can use <code class="computeroutput"><span class="char">','</span></code> directly. Though it is not a parser, <code class="computeroutput"><span class="keyword">operator</span><span class="special">>></span></code>
|
||
and the other operators defined on Boost.Parser parsers have overloads that
|
||
accept character/parser pairs of arguments; these operator overloads will
|
||
create the right parser to recognize <code class="computeroutput"><span class="char">','</span></code>.
|
||
</p>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting"><span class="preprocessor">#include</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">parser</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">string</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">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">cout</span> <span class="special"><<</span> <span class="string">"Enter a list of doubles, separated by commas. No pressure. "</span><span class="special">;</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">input</span><span class="special">;</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">getline</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cin</span><span class="special">,</span> <span class="identifier">input</span><span class="special">);</span>
|
||
|
||
<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">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="keyword">if</span> <span class="special">(</span><span class="identifier">result</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Great! It looks like you entered:\n"</span><span class="special">;</span>
|
||
<span class="keyword">for</span> <span class="special">(</span><span class="keyword">double</span> <span class="identifier">x</span> <span class="special">:</span> <span class="special">*</span><span class="identifier">result</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">x</span> <span class="special"><<</span> <span class="string">"\n"</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="special">}</span> <span class="keyword">else</span> <span class="special">{</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span>
|
||
<span class="special"><<</span> <span class="string">"Good job! Please proceed to the recovery annex for cake.\n"</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
</p>
|
||
<p>
|
||
The first example filled in an out-parameter to deliver the result of the
|
||
parse. This call to <code class="computeroutput"><a class="link" href="../../boost/parser/parse_id2.html" title="Function template parse">parse()</a></code>
|
||
returns a result instead. As you can see, the result is contextually convertible
|
||
to <code class="computeroutput"><span class="keyword">bool</span></code>, and <code class="computeroutput"><span class="special">*</span><span class="identifier">result</span></code> is some sort of range. In fact,
|
||
the return type of this call to <code class="computeroutput"><a class="link" href="../../boost/parser/parse_id2.html" title="Function template parse">parse()</a></code>
|
||
is <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>. Naturally, if the parse fails,
|
||
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">nullopt</span></code> is returned. We'll look at how
|
||
Boost.Parser maps the type of the parser to the return type, or the filled
|
||
in out-parameter's type, a bit later.
|
||
</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>
|
||
There's a type trait that can tell you the attribute type for a parser,
|
||
<code class="computeroutput"><a class="link" href="../../boost/parser/attribute.html" title="Struct template attribute">attribute</a></code>
|
||
(and an associated alias <code class="computeroutput"><a class="link" href="../../boost/parser/attribute_t.html" title="Type definition attribute_t">attribute_t</a></code>). We'll discuss
|
||
it more in the <a class="link" href="attribute_generation.html" title="Attribute Generation">Attribute
|
||
Generation</a> section.
|
||
</p></td></tr>
|
||
</table></div>
|
||
<p>
|
||
If I run it in a shell, this is the result:
|
||
</p>
|
||
<pre class="programlisting">$ example/trivial
|
||
Enter a list of doubles, separated by commas. No pressure. 5.6,8.9
|
||
Great! It looks like you entered:
|
||
5.6
|
||
8.9
|
||
$ example/trivial
|
||
Enter a list of doubles, separated by commas. No pressure. 5.6, 8.9
|
||
Good job! Please proceed to the recovery annex for cake.
|
||
</pre>
|
||
<p>
|
||
It does not recognize <code class="computeroutput"><span class="string">"5.6, 8.9"</span></code>.
|
||
This is because it expects a comma followed <span class="emphasis"><em>immediately</em></span>
|
||
by a <code class="computeroutput"><span class="keyword">double</span></code>, but I inserted
|
||
a space after the comma. The same failure to parse would occur if I put a
|
||
space before the comma, or before or after the list of <code class="computeroutput"><span class="keyword">double</span></code>s.
|
||
</p>
|
||
<p>
|
||
One more thing: there is a much better way to write the parser above. Instead
|
||
of repeating the <code class="computeroutput"><span class="identifier">double_</span></code>
|
||
subparser, we could have written this:
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">bp</span><span class="special">::</span><span class="identifier">double_</span> <span class="special">%</span> <span class="char">','</span>
|
||
</pre>
|
||
<p>
|
||
That's semantically identical to <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>. This pattern — some bit of input
|
||
repeated one or more times, with a separator between each instance —
|
||
comes up so often that there's an operator specifically for that, <code class="computeroutput"><span class="keyword">operator</span><span class="special">%</span></code>.
|
||
We'll be using that operator from now on.
|
||
</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="hello__whomever.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="a_trivial_example_that_gracefully_handles_whitespace.html"><img src="../../images/next.png" alt="Next"></a>
|
||
</div>
|
||
</body>
|
||
</html>
|