mirror of
https://github.com/boostorg/parser.git
synced 2026-01-21 17:12:16 +00:00
159 lines
14 KiB
HTML
159 lines
14 KiB
HTML
<html>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
<title>Semantic Actions</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="a_trivial_example_that_gracefully_handles_whitespace.html" title="A Trivial Example That Gracefully Handles Whitespace">
|
||
<link rel="next" href="parsing_to_find_subranges.html" title="Parsing to Find Subranges">
|
||
<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="a_trivial_example_that_gracefully_handles_whitespace.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="parsing_to_find_subranges.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.semantic_actions"></a><a class="link" href="semantic_actions.html" title="Semantic Actions">Semantic Actions</a>
|
||
</h3></div></div></div>
|
||
<p>
|
||
Like all parsing systems (lex & yacc, <a href="https://www.boost.org/doc/libs/release/libs/spirit" target="_top">Boost.Spirit</a>,
|
||
etc.), Boost.Parser has a mechanism for associating semantic actions with
|
||
different parts of the parse. Here is nearly the same program as we saw in
|
||
the previous example, except that it is implemented in terms of a semantic
|
||
action that appends each parsed <code class="computeroutput"><span class="keyword">double</span></code>
|
||
to a result, instead of automatically building and returning the result.
|
||
To do this, we replace the <code class="computeroutput"><a class="link" href="../../boost/parser/double_.html" title="Global double_">double_</a></code> from the previous
|
||
example with <code class="computeroutput"><a class="link" href="../../boost/parser/double_.html" title="Global double_">double_</a><span class="special">[</span><span class="identifier">action</span><span class="special">]</span></code>;
|
||
<code class="computeroutput"><span class="identifier">action</span></code> is our semantic action:
|
||
</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. "</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="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">result</span><span class="special">;</span>
|
||
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">action</span> <span class="special">=</span> <span class="special">[&</span><span class="identifier">result</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">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Got one!\n"</span><span class="special">;</span>
|
||
<span class="identifier">result</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">action_parser</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">action</span><span class="special">];</span>
|
||
<span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">success</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">action_parser</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">ws</span><span class="special">);</span>
|
||
|
||
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">success</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">"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="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">"Parse failure.\n"</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
</p>
|
||
<p>
|
||
Run in a shell, it looks like this:
|
||
</p>
|
||
<pre class="programlisting">$ example/semantic_actions
|
||
Enter a list of doubles, separated by commas. 4,3
|
||
Got one!
|
||
Got one!
|
||
You entered:
|
||
4
|
||
3
|
||
</pre>
|
||
<p>
|
||
In Boost.Parser, semantic actions are implemented in terms of invocable objects
|
||
that take a single parameter to a parse-context object. The parse-context
|
||
object represents the current state of the parse. In the example we used
|
||
this lambda as our invocable:
|
||
</p>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">action</span> <span class="special">=</span> <span class="special">[&</span><span class="identifier">result</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">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Got one!\n"</span><span class="special">;</span>
|
||
<span class="identifier">result</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>
|
||
</pre>
|
||
<p>
|
||
</p>
|
||
<p>
|
||
We're both printing a message to <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span></code>
|
||
and recording a parsed result in the lambda. It could do both, either, or
|
||
neither of these things if you like. The way we get the parsed <code class="computeroutput"><span class="keyword">double</span></code> in the lambda is by asking the parse
|
||
context for it. <code class="computeroutput"><span class="identifier">_attr</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">)</span></code> is
|
||
how you ask the parse context for the attribute produced by the parser to
|
||
which the semantic action is attached. There are lots of functions like
|
||
<code class="computeroutput"><span class="identifier">_attr</span><span class="special">()</span></code>
|
||
that can be used to access the state in the parse context. We'll cover more
|
||
of them later on. <a class="link" href="the_parse_context.html" title="The Parse Context">The
|
||
Parse Context</a> defines what exactly the parse context is and how it
|
||
works.
|
||
</p>
|
||
<p>
|
||
Note that you can't write an unadorned lambda directly as a semantic action.
|
||
Otherwise, the compile will see two <code class="computeroutput"><span class="char">'['</span></code>
|
||
characters and think it's about to parse an attribute. Parentheses fix this:
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">p</span><span class="special">[([](</span><span class="keyword">auto</span> <span class="special">&</span> <span class="identifier">ctx</span><span class="special">){/*...*/})]</span>
|
||
</pre>
|
||
<p>
|
||
Before you do this, note that the lambdas that you write as semantic actions
|
||
are almost always generic (having an <code class="computeroutput"><span class="keyword">auto</span>
|
||
<span class="special">&</span> <span class="identifier">ctx</span></code>
|
||
parameter), and so are very frequently re-usable. Most semantic action lambdas
|
||
you write should be written out-of-line, and given a good name. Even when
|
||
they are not reused, named lambdas keep your parsers smaller and easier to
|
||
read.
|
||
</p>
|
||
<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>
|
||
Attaching a semantic action to a parser removes its attribute. That 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><span class="identifier">a</span><span class="special">])</span></code> is always the special no-attribute type
|
||
<code class="computeroutput"><a class="link" href="../../boost/parser/none.html" title="Struct none">none</a></code>,
|
||
regardless of what type <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.
|
||
</p></td></tr>
|
||
</table></div>
|
||
<h5>
|
||
<a name="boost_parser.tutorial.semantic_actions.h0"></a>
|
||
<span class="phrase"><a name="boost_parser.tutorial.semantic_actions.semantic_actions_inside_rules"></a></span><a class="link" href="semantic_actions.html#boost_parser.tutorial.semantic_actions.semantic_actions_inside_rules">Semantic
|
||
actions inside rules</a>
|
||
</h5>
|
||
<p>
|
||
There are some other forms for semantic actions, when they are used inside
|
||
of <code class="computeroutput"><a class="link" href="../../boost/parser/rule.html" title="Struct template rule">rules</a></code>.
|
||
See <a class="link" href="more_about_rules.html" title="More About Rules">More About Rules</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="a_trivial_example_that_gracefully_handles_whitespace.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="parsing_to_find_subranges.html"><img src="../../images/next.png" alt="Next"></a>
|
||
</div>
|
||
</body>
|
||
</html>
|