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/semantic_actions.html
2024-12-08 17:19:48 -06:00

159 lines
14 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>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 &amp; 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">&lt;</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">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">iostream</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">string</span><span class="special">&gt;</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">&lt;&lt;</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">&lt;</span><span class="keyword">double</span><span class="special">&gt;</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">[&amp;</span><span class="identifier">result</span><span class="special">](</span><span class="keyword">auto</span> <span class="special">&amp;</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">&lt;&lt;</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">&lt;&lt;</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">&lt;&lt;</span> <span class="identifier">x</span> <span class="special">&lt;&lt;</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">&lt;&lt;</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">[&amp;</span><span class="identifier">result</span><span class="special">](</span><span class="keyword">auto</span> <span class="special">&amp;</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">&lt;&lt;</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">&amp;</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">&amp;</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>