259 lines
24 KiB
HTML
259 lines
24 KiB
HTML
<html>
|
|
<head>
|
|
<title>Semantic Actions</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
</head>
|
|
|
|
<body>
|
|
<table width="100%" border="0" background="theme/bkd2.gif" cellspacing="2">
|
|
<tr>
|
|
<td width="10">
|
|
</td>
|
|
<td width="85%">
|
|
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Semantic Actions</b></font>
|
|
</td>
|
|
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" width="112" height="48" align="right" border="0"></a></td>
|
|
</tr>
|
|
</table>
|
|
<br>
|
|
<table border="0">
|
|
<tr>
|
|
<td width="10"></td>
|
|
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
|
<td width="30"><a href="subrules.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
<td width="30"><a href="indepth_the_parser.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
</tr>
|
|
</table>
|
|
<p>Semantic actions have the form: <b>expression[action]</b></p>
|
|
<p>Ultimately, after having defined our grammar and having generated a corresponding
|
|
parser, we will need to produce some output and do some work besides syntax
|
|
analysis; unless, of course, what we want is merely to check for the conformance
|
|
of an input with our grammar, which is very seldom the case. Semantic actions
|
|
may be attached to any expression at any level within the parser hierarchy.
|
|
An action is a C/C++ function or function object that will be called if a match
|
|
is found in the particular context where it is attached. The action function
|
|
serves as a hook into the parser and may be used to, for example:</p>
|
|
<blockquote>
|
|
<p><img src="theme/bullet.gif" width="13" height="13"> Generate output from
|
|
the parser (ASTs, for example)<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> Report warnings or errors<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> Manage symbol tables</p>
|
|
</blockquote>
|
|
<h2>Generic Semantic Actions (Transduction Interface)</h2>
|
|
<p>A generic semantic action can be any free function or function object that
|
|
is compatible with the interface:</p>
|
|
<pre><code><font color="#000000"><span class=identifier></span><span class=keyword> void </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>IteratorT </span><span class=identifier>first</span><span class=special>, </span><span class=identifier>IteratorT </span><span class=identifier>last</span><span class=special>);</span></font></code></pre>
|
|
<p>where <tt>IteratorT</tt> is the type of iterator used, <tt>first</tt> points
|
|
to the current input and <tt>last</tt> points to one after the end of the input
|
|
(identical to STL iterator ranges). A function object (functor) should have
|
|
a member <tt>operator()</tt> with the same signature as above:</p>
|
|
<pre><code><font color="#000000"><span class=special> </span><span class=keyword>struct </span><span class=identifier>my_functor
|
|
</span><span class=special>{
|
|
</span><span class=keyword>void </span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>IteratorT </span><span class=identifier>first</span><span class=special>, </span><span class=identifier>IteratorT </span><span class=identifier>last</span><span class=special>) </span><span class=keyword>const</span><span class=special>;
|
|
</span><span class=special>};</span></font></code></pre>
|
|
<p>Iterators pointing to the matching portion of the input are passed into the
|
|
function/functor.</p>
|
|
<p>In general, semantic actions accept the first-last iterator pair. This is the
|
|
transduction interface. The action functions or functors receive the unprocessed
|
|
data representing the matching production directly from the input. In many cases,
|
|
this is sufficient. Examples are source to source translation, pre-processing,
|
|
etc. </p>
|
|
<h3>Example:</h3>
|
|
<pre><code><font color="#000000"><span class=special> </span><span class=keyword>void
|
|
</span><span class=identifier>my_action</span><span class=special>(</span><span class=keyword>char const</span><span class=special>* </span><span class=identifier>first</span><span class=special>, </span><span class=keyword>char const</span><span class=special>* </span><span class=identifier>last</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">str</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>std</span><span class=special>::</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>str </span><span class=special><< </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>;
|
|
}
|
|
|
|
</span><span class=identifier>rule</span><span class=special><> </span><span class=identifier>myrule </span><span class=special>= (</span><span class=identifier>a </span><span class=special>| </span><span class=identifier>b </span><span class=special>| *(</span><span class=identifier>c </span><span class=special>>> </span><span class=identifier>d</span><span class=special>))[&</span><span class=identifier>my_action</span><span class=special>];</span></font></code></pre>
|
|
<p>The function <tt>my_action</tt> will be called whenever the expression <tt>(a
|
|
| b | *(c >> d)</tt> matches a portion of the input stream while parsing.
|
|
Two iterators, <tt>first</tt> and <tt>last</tt>, are passed into the function.
|
|
These iterators point to the start and end, respectively, of the portion of
|
|
input stream where the match is found.</p>
|
|
<h3>Const-ness:</h3>
|
|
<p>With functors, take note that the <tt>operator()</tt> should be <tt>const</tt>.
|
|
This implies that functors are immutable. One may wish to have some member variables
|
|
that are modified when the action gets called. This is not a good idea. First
|
|
of all, functors are preferably lightweight. Functors are passed around a lot
|
|
and it would incur a lot of overhead if the functors are heavily laden. Second,
|
|
functors are passed by value. Thus, the actual functor object that finally attaches
|
|
to the parser, will surely not be the original instance supplied by the client.
|
|
What this means is that changes to a functor's state will not affect the original
|
|
functor that the client passed in since they are distinct copies. If a functor
|
|
needs to update some state variables, which is often the case, it is better
|
|
to use references to external data. The following example shows how this can
|
|
be done:</p>
|
|
<pre><code><font color="#000000"><span class=special> </span><span class=keyword>struct </span><span class=identifier>my_functor
|
|
</span><span class=special>{
|
|
</span><span class=identifier>my_functor</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>str_</span><span class=special>)
|
|
</span><span class=special>: </span><span class=identifier>str</span><span class=special>(</span><span class=identifier>str_</span><span class=special>) </span><span class=special>{}
|
|
|
|
</span><span class=keyword>void
|
|
</span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>IteratorT </span><span class=identifier>first</span><span class=special>, </span><span class=identifier>IteratorT </span><span class=identifier>last</span><span class=special>) </span><span class=keyword>const
|
|
</span><span class=special>{
|
|
</span><span class=identifier>str</span><span class=special>.</span><span class=identifier>assign</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=special>}
|
|
|
|
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>& </span><span class=identifier>str</span><span class=special>;
|
|
</span><span class=special>};</span></font></code></pre>
|
|
<h3>Full Example:</h3>
|
|
<p>Here now is our calculator enhanced with semantic actions:</p>
|
|
<pre><code><font color="#000000"><span class=special> </span><span class=keyword>namespace
|
|
</span><span class=special>{
|
|
</span><span class=keyword>void </span><span class=identifier>do_int</span><span class=special>(</span><span class=keyword>char </span><span class=keyword>const</span><span class=special>* </span><span class=identifier>str</span><span class=special>, </span><span class=keyword>char </span><span class=keyword>const</span><span class=special>* </span><span class=identifier>end</span><span class=special>)
|
|
</span><span class=special>{
|
|
</span><span class=identifier>string </span><span class=identifier>s</span><span class=special>(</span><span class=identifier>str</span><span class=special>, </span><span class=identifier>end</span><span class=special>);
|
|
</span><span class=identifier>cout </span><span class=special><< </span><span class=string>"PUSH(" </span><span class=special><< </span><span class=identifier>s </span><span class=special><< </span><span class=literal>')' </span><span class=special><< </span><span class=identifier>endl</span><span class=special>;
|
|
</span><span class=special>}
|
|
|
|
</span><span class=keyword>void </span><span class=identifier>do_add</span><span class=special>(</span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*, </span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*) </span><span class=special>{ </span><span class=identifier>cout </span><span class=special><< </span><span class=string>"ADD\n"</span><span class=special>; </span><span class=special>}
|
|
</span><span class=keyword>void </span><span class=identifier>do_subt</span><span class=special>(</span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*, </span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*) </span><span class=special>{ </span><span class=identifier>cout </span><span class=special><< </span><span class=string>"SUBTRACT\n"</span><span class=special>; </span><span class=special>}
|
|
</span><span class=keyword>void </span><span class=identifier>do_mult</span><span class=special>(</span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*, </span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*) </span><span class=special>{ </span><span class=identifier>cout </span><span class=special><< </span><span class=string>"MULTIPLY\n"</span><span class=special>; </span><span class=special>}
|
|
</span><span class=keyword>void </span><span class=identifier>do_div</span><span class=special>(</span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*, </span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*) </span><span class=special>{ </span><span class=identifier>cout </span><span class=special><< </span><span class=string>"DIVIDE\n"</span><span class=special>; </span><span class=special>}
|
|
</span><span class=keyword>void </span><span class=identifier>do_neg</span><span class=special>(</span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*, </span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*) </span><span class=special>{ </span><span class=identifier>cout </span><span class=special><< </span><span class=string>"NEGATE\n"</span><span class=special>; </span><span class=special>}
|
|
</span><span class=special>}</span></font></code></pre>
|
|
<p>We augment our grammar with semantic actions:</p>
|
|
<pre><code><font color="#000000"><span class=special> </span><span class=keyword>struct </span><span class=identifier>calculator </span><span class=special>: </span><span class=keyword>public </span><span class=identifier>grammar</span><span class=special><</span><span class=identifier>calculator</span><span class=special>>
|
|
</span><span class=special>{
|
|
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>ScannerT</span><span class=special>>
|
|
</span><span class=keyword>struct </span><span class=identifier>definition
|
|
</span><span class=special>{
|
|
</span><span class=identifier>definition</span><span class=special>(</span><span class=identifier>calculator </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>self</span><span class=special>)
|
|
</span><span class=special>{
|
|
</span><span class=identifier>expression
|
|
</span><span class=special>= </span><span class=identifier>term
|
|
</span><span class=special>>> </span><span class=special>*( </span><span class=special>(</span><span class=literal>'+' </span><span class=special>>> </span><span class=identifier>term</span><span class=special>)[&</span><span class=identifier>do_add</span><span class=special>]
|
|
</span><span class=special>| </span><span class=special>(</span><span class=literal>'-' </span><span class=special>>> </span><span class=identifier>term</span><span class=special>)[&</span><span class=identifier>do_subt</span><span class=special>]
|
|
</span><span class=special>)
|
|
</span><span class=special>;
|
|
|
|
</span><span class=identifier>term </span><span class=special>=
|
|
</span><span class=identifier>factor
|
|
</span><span class=special>>> </span><span class=special>*( </span><span class=special>(</span><span class=literal>'*' </span><span class=special>>> </span><span class=identifier>factor</span><span class=special>)[&</span><span class=identifier>do_mult</span><span class=special>]
|
|
</span><span class=special>| </span><span class=special>(</span><span class=literal>'/' </span><span class=special>>> </span><span class=identifier>factor</span><span class=special>)[&</span><span class=identifier>do_div</span><span class=special>]
|
|
</span><span class=special>)
|
|
</span><span class=special>;
|
|
|
|
</span><span class=identifier>factor
|
|
</span><span class=special>= </span><span class=identifier>lexeme_d</span><span class=special>[(+</span><span class=identifier>digit_p</span><span class=special>)[&</span><span class=identifier>do_int</span><span class=special>]]
|
|
</span><span class=special>| </span><span class=literal>'(' </span><span class=special>>> </span><span class=identifier>expression </span><span class=special>>> </span><span class=literal>')'
|
|
</span><span class=special>| </span><span class=special>(</span><span class=literal>'-' </span><span class=special>>> </span><span class=identifier>factor</span><span class=special>)[&</span><span class=identifier>do_neg</span><span class=special>]
|
|
</span><span class=special>| </span><span class=special>(</span><span class=literal>'+' </span><span class=special>>> </span><span class=identifier>factor</span><span class=special>)
|
|
</span><span class=special>;
|
|
</span><span class=special>}
|
|
|
|
</span><span class=identifier>rule</span><span class=special><</span><span class=identifier>ScannerT</span><span class=special>> </span><span class=identifier>expression</span><span class=special>, </span><span class=identifier>term</span><span class=special>, </span><span class=identifier>factor</span><span class=special>;
|
|
|
|
</span><span class=identifier>rule</span><span class=special><</span><span class=identifier>ScannerT</span><span class=special>> </span><span class=keyword>const</span><span class=special>&
|
|
</span><span class=identifier>start</span><span class=special>() </span><span class=keyword>const </span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>expression</span><span class=special>; </span><span class=special>}
|
|
</span><span class=special>};
|
|
</span><span class=special>};</span></font></code></pre>
|
|
<p>Feeding in the expression <tt>(-1 + 2) * (3 + -4)</tt>, for example, to the
|
|
rule <tt>expression</tt> will produce the expected output:</p>
|
|
<pre><code><span class=special>-</span><span class=number>1
|
|
</span><span class=number>2
|
|
</span><span class=identifier>ADD
|
|
</span><span class=number>3
|
|
</span><span class=special>-</span><span class=number>4
|
|
</span><span class=identifier>ADD
|
|
</span><span class=identifier>MULT</span></code></pre>
|
|
<p>which, by the way, is the Reverse Polish Notation (RPN) of the given expression,
|
|
reminiscent of some primitive calculators and the language Forth.</p>
|
|
<p><img src="theme/lens.gif" width="15" height="16"> <a href="../example/fundamental/calc_plain.cpp">View
|
|
the complete source code here</a>. This is part of the Spirit distribution.
|
|
</p>
|
|
<h2><a name="specialized_actions"></a>Specialized Actions</h2>
|
|
<p>In general, semantic actions accept the first-last iterator pair. There are
|
|
situations though where we might want to pass data in its processed form. A
|
|
concrete example is the numeric parser. It is unwise to pass unprocessed data
|
|
to a semantic action attached to a numeric parser and just throw away what has
|
|
been parsed by the parser. We want to pass the actual parsed number.</p>
|
|
<p>The function and functor signature of a semantic action varies depending on
|
|
the parser where it is attached to. The following table lists the parsers that
|
|
accept unique signatures.</p>
|
|
<table width="80%" border="0" align="center">
|
|
<tr>
|
|
<td class="note_box"><img src="theme/note.gif" width="16" height="16"> Unless
|
|
explicitly stated in the documentation of a specific parser type, parsers
|
|
not included in the list by default expect the generic signature as explained
|
|
above.</td>
|
|
</tr>
|
|
</table>
|
|
<h3>Numeric Actions</h3>
|
|
<p><b>Applies to:</b></p>
|
|
<blockquote>
|
|
<p><img src="theme/bullet.gif" width="13" height="13"> uint_p<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> int_p<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> ureal_p<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> real_p</p>
|
|
</blockquote>
|
|
<p><b>Signature for functions:</b></p>
|
|
<pre><code><font color="#000000"><span class=identifier> </span><span class=keyword>void </span><span class=identifier>func</span><span class=special>(</span><span class=identifier>NumT </span><span class=identifier>val</span><span class=special>);</span></font></code></pre>
|
|
<p><b>Signature for functors:</b> </p>
|
|
<pre><code><font color="#000000"><span class=special> </span><span class=keyword>struct </span><span class=identifier>ftor
|
|
</span><span class=special>{
|
|
</span><span class=keyword>void </span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>NumT </span><span class=identifier>val</span><span class=special>) </span><span class=keyword>const</span><span class=special>;
|
|
</span><span class=special>};</span></font></code></pre>
|
|
<p>Where <tt>NumT</tt> is any primitive numeric type such as <tt>int</tt>, <tt>long</tt>,
|
|
<tt>float</tt>, <tt>double</tt>, etc., or a user defined numeric type such as
|
|
big_int. <tt>NumT</tt> is the same type used as template parameter to <tt>uint_p</tt>,
|
|
<tt>int_p</tt>, <tt>ureal_p</tt> or <tt>real_p</tt>. The parsed number is passed
|
|
into the function/functor.</p>
|
|
<h3>Character Actions</h3>
|
|
<p><b>Applies to:</b></p>
|
|
<blockquote>
|
|
<p><img src="theme/bullet.gif" width="13" height="13"> chlit, ch_p<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> range, range_p<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> anychar<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> alnum, alpha<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> cntrl, digit<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> graph, lower<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> print, punct<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> space, upper<br>
|
|
<img src="theme/bullet.gif" width="13" height="13"> xdigit</p>
|
|
</blockquote>
|
|
<p><b>Signature for functions:</b></p>
|
|
<pre><code><font color="#000000"><span class=identifier> </span><span class=keyword>void </span><span class=identifier>func</span><span class=special>(</span><span class=identifier>CharT </span><span class=identifier>ch</span><span class=special>);</span></font></code></pre>
|
|
<p><b>Signature for functors:</b></p>
|
|
<pre><code><font color="#000000"><span class=special> </span><span class=keyword>struct </span><span class=identifier>ftor
|
|
</span><span class=special>{
|
|
</span><span class=keyword>void </span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>CharT </span><span class=identifier>ch</span><span class=special>) </span><span class=keyword>const</span><span class=special>;
|
|
</span><span class=special>};</span></font></code></pre>
|
|
<p>Where <tt>CharT</tt> is the value_type of the iterator used in parsing. A <tt>char
|
|
const*</tt> iterator for example has a <tt>value_type</tt> of <tt>char</tt>.
|
|
The matching character is passed into the function/functor.</p>
|
|
<h2>Cascading Actions</h2>
|
|
<p>Actions can be cascaded. Cascaded actions also inherit the function/functor
|
|
interface of the original. For example:</p>
|
|
<pre><code><font color="#000000"><span class=special> </span><span class=identifier>uint_p</span><span class=special>[</span><span class=identifier>fa</span><span class=special>][</span><span class=identifier>fb</span><span class=special>][</span><span class=identifier>fc</span><span class=special>]</span></font></code></pre>
|
|
<p>Here, the functors <tt>fa</tt>, <tt>fb</tt> and <tt>fc</tt> all expect the
|
|
signature <tt>void operator()(unsigned n) const</tt>.</p>
|
|
<h2>Directives and Actions</h2>
|
|
<p>Directives inherit the function/functor interface of the subject it is
|
|
enclosing. Example:</p>
|
|
<pre><code><font color="#000000"><span class=special> </span><span class=identifier>as_lower_d</span><span class=special>[</span><span class=identifier>ch_p</span><span class=special>(</span><span class=literal>'x'</span><span class=special>)][</span><span class=identifier>f</span><span class=special>]</span></font></code></pre>
|
|
<p>Here, the functor <tt>f</tt> expects the signature <tt>void operator()(char
|
|
ch) const</tt>, assuming that the iterator used is a <tt>char const*</tt>.</p>
|
|
<table border="0">
|
|
<tr>
|
|
<td width="10"></td>
|
|
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
|
<td width="30"><a href="subrules.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
<td width="30"><a href="indepth_the_parser.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
</tr>
|
|
</table>
|
|
<br>
|
|
<hr size="1">
|
|
<p class="copyright">Copyright © 1998-2003 Joel de Guzman<br>
|
|
<br>
|
|
<font size="2">Use, modification and distribution is subject to the Boost Software
|
|
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
|
http://www.boost.org/LICENSE_1_0.txt)</font></p>
|
|
<p> </p>
|
|
<p> </p>
|
|
</body>
|
|
</html>
|