1 | <html> |
---|
2 | <head> |
---|
3 | <title>Closures</title> |
---|
4 | <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
---|
5 | <link rel="stylesheet" href="theme/style.css" type="text/css"> |
---|
6 | <style type="text/css"> |
---|
7 | <!-- |
---|
8 | .style1 {font-family: "Courier New", Courier, mono} |
---|
9 | --> |
---|
10 | </style> |
---|
11 | </head> |
---|
12 | |
---|
13 | <body> |
---|
14 | <table width="100%" border="0" background="theme/bkd2.gif" cellspacing="2"> |
---|
15 | <tr> |
---|
16 | <td width="10"> |
---|
17 | </td> |
---|
18 | <td width="85%"> |
---|
19 | <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Closures</b></font> |
---|
20 | </td> |
---|
21 | <td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" width="112" height="48" align="right" border="0"></a></td> |
---|
22 | </tr> |
---|
23 | </table> |
---|
24 | <br> |
---|
25 | <table border="0"> |
---|
26 | <tr> |
---|
27 | <td width="10"></td> |
---|
28 | <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> |
---|
29 | <td width="30"><a href="phoenix.html"><img src="theme/l_arr.gif" border="0"></a></td> |
---|
30 | <td width="30"><a href="dynamic_parsers.html"><img src="theme/r_arr.gif" border="0"></a></td> |
---|
31 | </tr> |
---|
32 | </table> |
---|
33 | <h2>Overview</h2> |
---|
34 | <p>Using phoenix, in the previous chapter, we've seen how we can get data from our parsers using <tt>var</tt>:</p> |
---|
35 | <pre><code><font color="#000000"><span class=special> </span><span class=keyword>int </span><span class=identifier>i</span><span class=special>; |
---|
36 | </span><span class=identifier> integer </span><span class=special>= </span><span class=identifier>int_p</span><span class=special>[</span><span class="identifier">var</span><span class=special>(</span><span class=identifier>i</span><span class=special>) = </span><span class="identifier">arg1</span><span class=special>];</span></font></code></pre> |
---|
37 | <p>Nifty! Our rule <tt>integer</tt>, if successful, passes the parsed integer |
---|
38 | to the variable <tt>i</tt>. Everytime we need to parse an integer, we can call |
---|
39 | our rule <tt>integer</tt> and simply extract the parsed number from the variable |
---|
40 | <tt>i</tt>. There's something you should be aware of though. In the viewpoint |
---|
41 | of the grammar, the variable <tt>i</tt> is global. When the grammar gets more |
---|
42 | complex, it's hard to keep track of the current state of <tt>i</tt>. And, with |
---|
43 | recursive rules, global variables simply won't be adequate. </p> |
---|
44 | <p>Closures are needed if you need your rules (or grammars) to be reentrant. For example, a rule (or grammar) might be called recursively indirectly or directly by itself. The calculator is a good example. The expression rule recursively calls itself indirectly when it invokes the factor rule. </p> |
---|
45 | <p>Closures provide named (lazy) variables associated with each parse rule invocation. A closure variable is addressed using member syntax:</p> |
---|
46 | <pre><code><font color="#000000"><span class=identifier> </span>rulename<span class="special">.</span>varname</font></code></pre> |
---|
47 | <p>A closure variable <tt>R.x</tt> may be addressed in the semantic action of any other rule invoked by <tt>R</tt>; it refers to the innermost enclosing invocation of <tt>R</tt>. If no such invocation exists, an assertion occurs at runtime. </p> |
---|
48 | <p>Closures provide an environment, a stack frame, for local variables. |
---|
49 | Most importantly, the closure variables are accessible from the EBNF grammar |
---|
50 | specification and can be used to pass parser information upstream or downstream |
---|
51 | from the topmost rule down to the terminals in a top-down recursive descent. |
---|
52 | Closures facilitate dynamic scoping in C++. |
---|
53 | Spirit's closure implementation is based on <em>Todd Veldhuizen</em>'s <strong>Dynamic |
---|
54 | scoping in C++</strong> technique that he presented in his paper <a href="ftp://ftp.cs.indiana.edu/pub/techreports/TR542.pdf">Techniques |
---|
55 | for Scientic C++</a>. </p> |
---|
56 | <p>When a rule is given a closure, the closure's local variables are created prior |
---|
57 | to entering the parse function and destructed after exiting the parse function. |
---|
58 | These local variables are true local variables that exist on the hardware stack.</p> |
---|
59 | <table width="80%" border="0" align="center"> |
---|
60 | <tr> |
---|
61 | <td class="note_box"><img src="theme/alert.gif" width="16" height="16"> <strong>Closures</strong> |
---|
62 | <strong>and Phoenix</strong><br> <br> |
---|
63 | Spirit v1.8 closure support requires <a href="../phoenix/index.html">Phoenix</a>. |
---|
64 | In the future, Spirit will fully support <a href="../../../libs/lambda/index.html">BLL</a>. |
---|
65 | Currently, work is underway to merge the features of both libraries.</td> |
---|
66 | </tr> |
---|
67 | </table> |
---|
68 | <h2>Example</h2> |
---|
69 | <p>Let's go back to the calculator grammar introduced in the <a href="functional.html">Functional</a> chapter. Here's the full grammar again, plus the closure declarations:</p> |
---|
70 | <pre><span class=special> </span><span class=keyword>struct </span><span class=identifier>calc_closure </span><span class=special>: </span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>spirit</span><span class=special>::</span><span class=identifier>closure</span><span class=special><</span><span class=identifier>calc_closure</span><span class=special>, </span><span class=keyword>double</span><span class=special>> |
---|
71 | </span><span class=special>{ |
---|
72 | </span><span class=identifier>member1 </span><span class=identifier>val</span><span class=special>; |
---|
73 | </span><span class=special>}; |
---|
74 | |
---|
75 | </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=identifier>calc_closure</span><span class=special>::</span><span class=identifier>context_t</span><span class=special>> |
---|
76 | </span><span class=special>{ |
---|
77 | </span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>ScannerT</span><span class=special>> |
---|
78 | </span><span class=keyword>struct </span><span class=identifier>definition |
---|
79 | </span><span class=special>{ |
---|
80 | </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>) |
---|
81 | </span><span class=special>{ |
---|
82 | </span><span class=identifier>top </span><span class=special>= </span><span class=identifier>expression</span><span class=special>[</span><span class=identifier>self</span><span class=special>.</span><span class=identifier>val </span><span class=special>= </span><span class=identifier>arg1</span><span class=special>]; |
---|
83 | |
---|
84 | </span><span class=identifier>expression |
---|
85 | </span><span class=special>= </span><span class=identifier>term</span><span class=special>[</span><span class=identifier>expression</span><span class=special>.</span><span class=identifier>val </span><span class=special>= </span><span class=identifier>arg1</span><span class=special>] |
---|
86 | </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>expression</span><span class=special>.</span><span class=identifier>val </span><span class=special>+= </span><span class=identifier>arg1</span><span class=special>]) |
---|
87 | </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>expression</span><span class=special>.</span><span class=identifier>val </span><span class=special>-= </span><span class=identifier>arg1</span><span class=special>]) |
---|
88 | </span><span class=special>) |
---|
89 | </span><span class=special>; |
---|
90 | |
---|
91 | </span><span class=identifier>term |
---|
92 | </span><span class=special>= </span><span class=identifier>factor</span><span class=special>[</span><span class=identifier>term</span><span class=special>.</span><span class=identifier>val </span><span class=special>= </span><span class=identifier>arg1</span><span class=special>] |
---|
93 | </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>term</span><span class=special>.</span><span class=identifier>val </span><span class=special>*= </span><span class=identifier>arg1</span><span class=special>]) |
---|
94 | </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>term</span><span class=special>.</span><span class=identifier>val </span><span class=special>/= </span><span class=identifier>arg1</span><span class=special>]) |
---|
95 | </span><span class=special>) |
---|
96 | </span><span class=special>; |
---|
97 | |
---|
98 | </span><span class=identifier>factor |
---|
99 | </span><span class=special>= </span><span class=identifier>ureal_p</span><span class=special>[</span><span class=identifier>factor</span><span class=special>.</span><span class=identifier>val </span><span class=special>= </span><span class=identifier>arg1</span><span class=special>] |
---|
100 | </span><span class=special>| </span><span class=literal>'(' </span><span class=special>>> </span><span class=identifier>expression</span><span class=special>[</span><span class=identifier>factor</span><span class=special>.</span><span class=identifier>val </span><span class=special>= </span><span class=identifier>arg1</span><span class=special>] </span><span class=special>>> </span><span class=literal>')' |
---|
101 | </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>factor</span><span class=special>.</span><span class=identifier>val </span><span class=special>= </span><span class=special>-</span><span class=identifier>arg1</span><span class=special>]) |
---|
102 | </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>factor</span><span class=special>.</span><span class=identifier>val </span><span class=special>= </span><span class=identifier>arg1</span><span class=special>]) |
---|
103 | </span><span class=special>; |
---|
104 | </span><span class=special>} |
---|
105 | |
---|
106 | </span><span class=keyword>typedef </span><span class=identifier>rule</span><span class=special><</span><span class=identifier>ScannerT</span><span class=special>, </span><span class=identifier>calc_closure</span><span class=special>::</span><span class=identifier>context_t</span><span class=special>> </span><span class=identifier>rule_t</span><span class=special>; |
---|
107 | </span><span class=identifier>rule_t </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>; |
---|
108 | </span><span class=identifier>rule</span><span class=special><</span><span class=identifier>ScannerT</span><span class=special>> </span><span class=identifier>top</span><span class=special>; |
---|
109 | |
---|
110 | </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>& |
---|
111 | </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>top</span><span class=special>; </span><span class=special>} |
---|
112 | </span><span class=special>}; |
---|
113 | </span><span class=special>};</span></pre> |
---|
114 | <p> <img height="16" width="15" src="theme/lens.gif"> The full source code can be <a href="../example/fundamental/phoenix_calc.cpp">viewed here</a>. This is part of the Spirit distribution.</p> |
---|
115 | <p>Surely, we've come a long way from the original version of this calculator. With inline <a href="phoenix.html#lambda">lambda expressions</a>, we were able to write self contained grammars complete with semantic actions. </p> |
---|
116 | <p>The first thing to notice is the declaration of <tt>calc_closure</tt>. </p> |
---|
117 | <p> <strong>Declaring closures</strong></p> |
---|
118 | <p> The general closure declaration syntax is:</p> |
---|
119 | <pre><code> <span class=keyword>struct </span><span class=identifier>name</span><span class=special></span> <span class=special>: </span><span class=identifier>spirit</span><span class=special>::</span><span class=identifier>closure</span><span class=special><</span><span class=identifier>name</span><span class=special>, </span><span class=keyword>type1, type2, type3,... typeN</span><span class=special>> |
---|
120 | { |
---|
121 | </span><span class=identifier>member1 m_name1</span><span class=special>; |
---|
122 | </span><span class=identifier>member2 m_name2</span><span class=special>; |
---|
123 | </span><span class=identifier>member3 m_name3</span><span class=special>; |
---|
124 | ... |
---|
125 | </span><span class=identifier>memberN m_nameN</span><span class=special>; |
---|
126 | };</span></code></pre> |
---|
127 | <p> <tt>member1</tt>... <tt>memberN</tt> are indirect links to the actual closure variables. Their indirect types correspond to <code><tt>type1</tt></code>... <code><tt>typeN</tt></code>. In our example, we declared <tt>calc_closure</tt>:</p> |
---|
128 | <pre><span class=number> </span><span class=keyword>struct </span><span class=identifier>calc_closure </span><span class=special>: </span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>spirit</span><span class=special>::</span><span class=identifier>closure</span><span class=special><</span><span class=identifier>calc_closure</span><span class=special>, </span><span class=keyword>double</span><span class=special>> |
---|
129 | </span><span class=special>{ |
---|
130 | </span><span class=identifier>member1 </span><span class=identifier>val</span><span class=special>; |
---|
131 | </span><span class=special>};</span></pre> |
---|
132 | <p><tt>calc_closure</tt> has a single variable <tt>val</tt> of type <span class=keyword>double</span><span class=special></span>.</p> |
---|
133 | <table width="80%" border="0" align="center"> |
---|
134 | <tr> |
---|
135 | <td class="note_box"><p><img src="theme/alert.gif" width="16" height="16"> <tt>BOOST_SPIRIT_CLOSURE_LIMIT</tt><br> |
---|
136 | <br> |
---|
137 | Spirit predefined maximum closure limit. This limit defines the maximum number of elements a closure can hold. This number defaults to 3. The actual maximum is rounded up in multiples of 3. Thus, if this value is 4, the actual limit is 6. The ultimate maximum limit in this implementation is 15. It should <strong>NOT</strong> be greater than <tt>PHOENIX_LIMIT</tt> (see <a href="../phoenix/index.html">phoenix</a>). Example:<br> |
---|
138 | <br> |
---|
139 | <span class="comment style1">// Define these before including anything else <br> |
---|
140 | </span><span class="preprocessor style1">#define</span><span class="style1"> PHOENIX_LIMIT 10<br> |
---|
141 | </span><span class="preprocessor">#define</span><span class="style1"> BOOST_SPIRIT_CLOSURE_LIMIT 10</span></p> </td> |
---|
142 | </tr> |
---|
143 | </table> |
---|
144 | <p><strong>Attaching closures</strong></p> |
---|
145 | <p>Closures can be applied to rules, subrules and grammars (non-terminals). The closure has a |
---|
146 | special <a href="indepth_the_parser_context.html">parser context</a> that can be used with these non-terminals. The closure's |
---|
147 | context is its means to hook into the non-terminal. The context of the closure <tt>C</tt> is <tt>C::context_t</tt>. </p> |
---|
148 | <p>We can see in the example that we attached <tt>calc_closure</tt> to the <tt>expression</tt>, <tt>term</tt> and <tt>factor</tt> rules in our grammar:</p> |
---|
149 | <pre><span class=special> </span><span class=keyword>typedef </span><span class=identifier>rule</span><span class=special><</span><span class=identifier>ScannerT</span><span class=special>, </span><span class=identifier>calc_closure</span><span class=special>::</span><span class=identifier>context_t</span><span class=special>> </span><span class=identifier>rule_t</span><span class=special>; |
---|
150 | </span><span class=identifier>rule_t </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> </pre> |
---|
151 | <p>as well as the grammar itself:</p> |
---|
152 | <pre><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=identifier>calc_closure</span><span class=special>::</span><span class=identifier>context_t</span><span class=special>></span></pre> |
---|
153 | <p><strong>Closure return value</strong></p> |
---|
154 | <p>The closure <tt>member1</tt> is the closure's return value. This return value, like the one returned by <tt>anychar_p</tt>, for example, can be used to propagate data up the parser hierarchy or passed to semantic actions. Thus, <tt>expression</tt>, <tt>term</tt> and <tt>factor</tt>, as well as the <tt>calculator</tt> grammar itself, all return a <tt>double</tt>. </p> |
---|
155 | <p><strong>Accessing closure variables</strong></p> |
---|
156 | <p>Closure variables can be accessed from within semantic actions just like you |
---|
157 | would struct members: by qualifying the member name with its owner rule, subrule |
---|
158 | or grammar. In our example above, notice how we referred to the closure member val. Example:</p> |
---|
159 | <pre class="identifier"><code> expression<span class=special>.</span>val <span class="comment">// refer to expression's closure member val</span></code></pre> |
---|
160 | <p><strong>Initializing closure variables </strong></p> |
---|
161 | <p>We didn't use this feature in the example, yet, for completeness... </p> |
---|
162 | <p>Sometimes, we need to initialize our closure variables upon entering a non-terminal (rule, subrule or grammar). Closure enabled non-terminals, by default, default-construct variables upon entering the parse member function. |
---|
163 | If this is not desirable, we can pass constructor arguments to the non-terminal. The syntax mimics a |
---|
164 | function call. </p> |
---|
165 | <p>For (<em>a contrived</em>) example, if you wish to construct <tt>calc_closure</tt>'s variables |
---|
166 | to <tt>3.6</tt>, when we invoke the rule <tt>expression</tt>, we write:</p> |
---|
167 | <pre class="identifier"><code> expression<span class="special">(</span><span class="keyword">3.6</span><span class="special">) </span><span class="comment">// invoke rule expression and set its closure variable to 3.6</span></code></pre> |
---|
168 | <p>The constructor arguments are actually Phoenix lambda expressions, so you can |
---|
169 | use arbitrarily complex expressions. Here's another <em>contrived example<strong>: </strong></em></p> |
---|
170 | <pre class="identifier"><code> <span class="comment">// call rule factor and set its closure variable to (expression.x / 8) * factor.y |
---|
171 | </span> <code>factor</code><span class="special">((</span>expression<span class="special">.</span>x<span class="keyword"> </span><span class="special">/</span><span class="keyword"> 8</span><span class="special">) *</span><span class="keyword"> </span>term<span class="special">.</span>y<span class="special">)</span></code></pre> |
---|
172 | <p><img src="theme/lens.gif" width="15" height="16"> We can pass less arguments than the actual number of variables in the closure. |
---|
173 | The variables at the right with no corresponding constructor arguments are default |
---|
174 | constructed. Passing more arguments than there are closure variables is an error.</p> |
---|
175 | <p><img src="theme/lens.gif" width="15" height="16"> See <a href="../example/intermediate/parameters.cpp">parameters.cpp</a> for a compilable example. This is part of the Spirit distribution.</p> |
---|
176 | <h2>Closures and Dynamic parsing</h2> |
---|
177 | <p>Let's write a very simple parser for an XML/HTML like language with arbitrarily nested tags. The typical approach to this type of nested tag parsing is to delegate the actual tag matching to semantic actions, perhaps using a symbol table. For example, the semantic actions are responsible for ensuring that the tags are nested (e.g. this code: <tt><p><table></p></table></tt> is erroneous).</p> |
---|
178 | <p>Spirit allows us to dynamically modify the parser at runtime. The ability to guide parser behavior through semantic actions makes it possible to ensure the nesting of tags directly in the parser. We shall see how this is possible. here's the grammar in its simplest form:</p> |
---|
179 | <pre><span class=identifier> element </span><span class=special>= </span><span class=identifier>start_tag </span><span class=special>>> </span><span class=special>*</span><span class=identifier>element </span><span class=special>>> </span><span class=identifier>end_tag</span><span class=special>;</span> |
---|
180 | </pre> |
---|
181 | <p>An element is a <tt>start_tag</tt> (e.g. <tt><font></tt>) folowed by zero or more elements, and ended by an <tt>end_tag</tt> (e.g. <tt></font></tt>). Now, here's a first shot at our <tt>start_tag</tt>:</p> |
---|
182 | <pre><span class=special> </span><span class=identifier>start_tag </span><span class=special>= </span><span class=literal>'<' </span><span class=special>>> </span><span class=identifier>lexeme_d</span><span class=special>[</span><span class=special>(+</span><span class=identifier>alpha_p</span><span class=special>)</span><span class=special>] </span><span class=special>>> </span><span class=literal>'>'</span><span class=special>;</span></pre> |
---|
183 | <p>Notice that the <tt>end_tag</tt> is just the same as <tt>start_tag</tt> with the addition of a slash:</p> |
---|
184 | <pre><span class=special> </span><span class=identifier>end_tag </span><span class=special>= </span><span class=literal>"</" </span><span class=special>>> </span>what_we_got_in_the_start_tag <span class=special></span><span class=special>>> </span><span class=literal>'>'</span><span class=special>;</span> |
---|
185 | </pre> |
---|
186 | <p>What we need to do is to temporarily store what we got in our <tt>start_tag</tt> and use that later to parse our <tt>end_tag</tt>. Nifty, we can use the <a href="parametric_parsers.html">parametric parser</a> primitives to parse our <tt>end_tag</tt>: </p> |
---|
187 | <pre><span class=special> </span><span class=identifier>end_tag </span><span class=special>= </span><span class=string>"</" </span><span class=special>>> </span><span class=identifier>f_str_p</span><span class=special>(</span>tag<span class=special>) </span><span class=special>>> </span><span class=literal>'>'</span><span class=special>;</span></pre> |
---|
188 | <p>where we parameterize <tt>f_str_p</tt> with what we stored (tag). </p> |
---|
189 | <p>Be reminded though that our grammar is recursive. The element rule calls itself. Hence, we can't just use a variable and use <tt>phoenix::var</tt> or <tt>boost::ref</tt>. Nested recursion will simply gobble up the variable. Each invocation of element must have a closure variable <tt>tag</tt>. Here now is the complete grammar:</p> |
---|
190 | <pre><span class=number> </span><span class=keyword>struct </span><span class=identifier>tags_closure </span><span class=special>: </span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>spirit</span><span class=special>::</span><span class=identifier>closure</span><span class=special><</span><span class=identifier>tags_closure</span><span class=special>, </span><span class=identifier>string</span><span class=special>> </span><span class=special> |
---|
191 | { |
---|
192 | </span><span class=identifier>member1 </span><span class=identifier>tag</span><span class=special>; |
---|
193 | </span><span class=special>}; |
---|
194 | |
---|
195 | </span><span class=keyword>struct </span><span class=identifier>tags </span><span class=special>: </span><span class=keyword>public </span><span class=identifier>grammar</span><span class=special><</span><span class=identifier>tags</span><span class=special>> |
---|
196 | </span><span class=special>{ |
---|
197 | </span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>ScannerT</span><span class=special>> |
---|
198 | </span><span class=keyword>struct </span><span class=identifier>definition </span><span class=special>{ |
---|
199 | |
---|
200 | </span><span class=identifier>definition</span><span class=special>(</span><span class=identifier>tags </span><span class=keyword>const</span><span class=special>& </span><span class=comment>/*self*/</span><span class=special>) |
---|
201 | </span><span class=special>{ |
---|
202 | </span><span class=identifier>element </span><span class=special>= </span><span class=identifier>start_tag </span><span class=special>>> </span><span class=special>*</span><span class=identifier>element </span><span class=special>>> </span><span class=identifier>end_tag</span><span class=special>; |
---|
203 | |
---|
204 | </span><span class=identifier>start_tag </span><span class=special>= |
---|
205 | </span><span class=literal>'<' |
---|
206 | </span><span class=special>>> </span><span class=identifier>lexeme_d |
---|
207 | </span><span class=special>[ |
---|
208 | </span><span class=special>(+</span><span class=identifier>alpha_p</span><span class=special>) |
---|
209 | </span><span class=special>[ |
---|
210 | </span><span class=comment>// construct string from arg1 and arg2 lazily |
---|
211 | </span><span class=comment>// and assign to element.tag |
---|
212 | |
---|
213 | </span><span class=identifier>element</span><span class=special>.</span><span class=identifier>tag </span><span class=special>= </span><span class=identifier>construct_</span><span class=special><</span><span class=identifier>string</span><span class=special>>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg2</span><span class=special>) |
---|
214 | </span><span class=special>] |
---|
215 | </span><span class=special>] |
---|
216 | </span><span class=special>>> </span><span class=literal>'>'</span><span class=special>; |
---|
217 | |
---|
218 | </span><span class=identifier>end_tag </span><span class=special>= </span><span class=string>"</" </span><span class=special>>> </span><span class=identifier>f_str_p</span><span class=special>(</span><span class=identifier>element</span><span class=special>.</span><span class=identifier>tag</span><span class=special>) </span><span class=special>>> </span><span class=literal>'>'</span><span class=special>; |
---|
219 | </span><span class=special>} |
---|
220 | |
---|
221 | </span><span class=identifier>rule</span><span class=special><</span><span class=identifier>ScannerT</span><span class=special>, </span><span class=identifier>tags_closure</span><span class=special>::</span><span class=identifier>context_t</span><span class=special>> </span><span class=identifier>element</span><span class=special>; |
---|
222 | </span><span class=identifier>rule</span><span class=special><</span><span class=identifier>ScannerT</span><span class=special>> </span><span class=identifier>start_tag</span><span class=special>, </span><span class=identifier>end_tag</span><span class=special>; |
---|
223 | |
---|
224 | </span><span class=identifier>rule</span><span class=special><</span><span class=identifier>ScannerT</span><span class=special>, </span><span class=identifier>tags_closure</span><span class=special>::</span><span class=identifier>context_t</span><span class=special>> </span><span class=keyword>const</span><span class=special>& |
---|
225 | </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>element</span><span class=special>; </span><span class=special>} |
---|
226 | </span><span class=special>}; |
---|
227 | </span><span class=special>};</span></pre> |
---|
228 | <p>We attached a semantic action to the <tt>(+alpha_p)</tt> part of the start_tag. There, we stored the parsed tag in the <tt>element</tt>'s closure variable <tt>tag</tt>. Later, in the <tt>end_tag</tt>, we simply used the <tt>element</tt>'s closure variable <tt>tag</tt> to parameterize our <tt>f_str_p</tt> parser. Simple and elegant. If some of the details begin to look like greek (e.g. what is <tt>construct_</tt>?), please consult the <a href="phoenix.html">Phoenix</a> chapter. </p> |
---|
229 | <p><img height="16" width="15" src="theme/lens.gif"> The full source code can be <a href="../example/fundamental/matching_tags.cpp">viewed here</a>. This is part of the Spirit distribution.</p> |
---|
230 | <h2><img src="theme/lens.gif" width="15" height="16"> Closures in-depth</h2> |
---|
231 | <p><strong>What are Closures?</strong></p> |
---|
232 | <p>The closure is an object that <span class="quotes">"closes"</span> |
---|
233 | over the local variables of a function making them visible and accessible outside |
---|
234 | the function. What is more interesting is that the closure actually packages |
---|
235 | a local context (stack frame where some variables reside) and makes it available |
---|
236 | outside the scope in which they actually exist. The information is essentially |
---|
237 | <span class="quotes">"captured"</span> by the closure allowing it |
---|
238 | to be referred to anywhere and anytime, even prior to the actual creation of |
---|
239 | the variables. </p> |
---|
240 | <p>The following diagram depicts the situation where a function <tt>A</tt> (or |
---|
241 | rule) exposes its closure and another function <tt>B</tt> references <tt>A</tt>'s |
---|
242 | variables through its closure.</p> |
---|
243 | <table width="40%" border="0" align="center"> |
---|
244 | <tr> |
---|
245 | <td><img src="theme/closure1.png"></td> |
---|
246 | </tr> |
---|
247 | <tr> |
---|
248 | <td> <div align="center"><b><font face="Geneva, Arial, Helvetica, san-serif" size="+1" color="#003399">The |
---|
249 | closure as an object that <i>"closes"</i> over the local variables |
---|
250 | of a function making them visible and accessible outside the function</font></b></div></td> |
---|
251 | </tr> |
---|
252 | </table> |
---|
253 | <p>Of course, function <tt>A</tt> should be active when <tt>A.x</tt> is referenced. |
---|
254 | What this means is that function <tt>B</tt> is reliant on function <tt>A</tt> |
---|
255 | (If <tt>B</tt> is a nested function of <tt>A</tt>, this will always be the case). |
---|
256 | The free form nature of Spirit rules allows access to a closure variable anytime, |
---|
257 | anywhere. Accessing <tt>A.x</tt> is equivalent to referring to the topmost stack |
---|
258 | variable <tt>x</tt> of function <tt>A</tt>. If function <tt>A</tt> is not active |
---|
259 | when <tt>A.x</tt> is referenced, a runtime exception will be thrown.</p> |
---|
260 | <p><strong>Nested Functions</strong></p> |
---|
261 | <p>To fully understand the importance of closures, it is best to look at a language |
---|
262 | such as Pascal which allows nested functions. Since we are dealing with C++, |
---|
263 | lets us assume for the moment that C++ allows nested functions. Consider the |
---|
264 | following <b><i>pseudo</i></b> C++ code:</p> |
---|
265 | <pre><span class=identifier> </span><span class=keyword>void </span><span class=identifier>a</span><span class=special>() |
---|
266 | </span><span class=special>{ |
---|
267 | </span><span class=keyword>int </span><span class=identifier>va</span><span class=special>; |
---|
268 | </span><span class=keyword>void </span><span class=identifier>b</span><span class=special>() |
---|
269 | </span><span class=special>{ |
---|
270 | </span><span class=keyword>int </span><span class=identifier>vb</span><span class=special>; |
---|
271 | </span> <span class=keyword>void </span><span class=identifier>c</span><span class=special>() |
---|
272 | </span><span class=special>{ |
---|
273 | </span><span class=keyword>int </span><span class=identifier>vc</span><span class=special>; |
---|
274 | </span><span class=special>} |
---|
275 | |
---|
276 | </span><span class=identifier>c</span><span class=special>()</span><span class=special>; |
---|
277 | </span><span class=special>} |
---|
278 | |
---|
279 | </span><span class=identifier>b</span><span class=special>(); |
---|
280 | </span><span class=special>}</span></pre> |
---|
281 | <p>We have three functions <tt>a</tt>, <tt>b</tt> and <tt>c</tt> where <tt>c</tt> |
---|
282 | is nested in <tt>b</tt> and <tt>b</tt> is nested in <tt>a</tt>. We also have |
---|
283 | three variables <tt>va</tt>, <tt>vb</tt> and <tt>vc</tt>. The lifetime of each |
---|
284 | of these local variables starts when the function where it is declared is entered |
---|
285 | and ends when the function exits. The scope of a local variable spans all nested |
---|
286 | functions inside the enclosing function where the variable is declared.</p> |
---|
287 | <p>Going downstream from function <tt>a</tt> to function <tt>c</tt>, when function |
---|
288 | a is entered, the variable <tt>va</tt> will be created in the stack. When function |
---|
289 | <tt>b</tt> is entered (called by <tt>a</tt>), <tt>va</tt> is very well in scope |
---|
290 | and is visble in <tt>b</tt>. At which point a fresh variable, <tt>vb</tt>, is |
---|
291 | created on the stack. When function <tt>c</tt> is entered, both <tt>va</tt> |
---|
292 | and <tt>vb</tt> are visibly in scope, and a fresh local variable <tt>vc</tt> |
---|
293 | is created. </p> |
---|
294 | <p>Going upstream, <tt>vc</tt> is not and cannot be visible outside the function |
---|
295 | <tt>c</tt>. <tt>vc</tt>'s life has already expired once <tt>c</tt> exits. The |
---|
296 | same is true with <tt>vb</tt>; vb is accessible in function <tt>c</tt> but not |
---|
297 | in function <tt>a</tt>. </p> |
---|
298 | <strong>Nested Mutually Recursive Rules</strong> |
---|
299 | <p>Now consider that <tt>a</tt>, <tt>b</tt> and <tt>c</tt> are rules:</p> |
---|
300 | <pre><span class=identifier> </span><span class=identifier>a </span><span class=special>= </span><span class=identifier>b </span><span class=special>>> </span><span class=special>*((</span><span class=literal>'+' </span><span class=special>>> </span><span class=identifier>b</span><span class=special>) </span><span class=special>| </span><span class=special>(</span><span class=literal>'-' </span><span class=special>>> </span><span class=identifier>b</span><span class=special>)); |
---|
301 | </span><span class=identifier>b </span><span class=special>= </span><span class=identifier>c </span><span class=special>>> </span><span class=special>*((</span><span class=literal>'*' </span><span class=special>>> </span><span class=identifier>c</span><span class=special>) </span><span class=special>| </span><span class=special>(</span><span class=literal>'/' </span><span class=special>>> </span><span class=identifier>c</span><span class=special>)); |
---|
302 | </span><span class=identifier>c </span><span class=special>= </span><span class=identifier>int_p </span><span class=special>| </span><span class=literal>'(' </span><span class=special>>> </span><span class=identifier>a </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>c</span><span class=special>) </span><span class=special>| </span><span class=special>(</span><span class=literal>'+' </span><span class=special>>> </span><span class=identifier>c</span><span class=special>);</span></pre> |
---|
303 | <p>We can visualize <tt>a</tt>, <tt>b</tt> and <tt>c</tt> as mutually recursive |
---|
304 | functions where <tt>a</tt> calls <tt>b</tt>, <tt>b</tt> calls <tt>c</tt> and |
---|
305 | <tt>c</tt> recursively calls <tt>a</tt>. Now, imagine if <tt>a</tt>, <tt>b</tt> |
---|
306 | and <tt>c</tt> each has a local variable named <tt>value</tt> that can be referred |
---|
307 | to in our grammar by explicit qualification:</p> |
---|
308 | <pre><span class=special> </span><span class=identifier>a</span><span class=special>.</span><span class=identifier>value </span><span class=comment>// refer to a's value local variable |
---|
309 | </span><span class=identifier>b</span><span class=special>.</span><span class=identifier>value </span><span class=comment>// refer to b's value local variable |
---|
310 | </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>value </span><span class=comment>// refer to c's value local variable</span> |
---|
311 | </pre> |
---|
312 | <p>Like above, when <tt>a</tt> is entered, a local variable <tt>value</tt> is |
---|
313 | created on the stack. This variable can be referred to by both <tt>b</tt> and |
---|
314 | <tt>c</tt>. Again, when <tt>b</tt> is called by <tt>a</tt>, <tt>b</tt> creates |
---|
315 | a local variable <tt>value</tt>. This variable is accessible by <tt>c</tt> but |
---|
316 | not by <tt>a</tt>. </p> |
---|
317 | <p>Here now is where the analogy with nested functions end: when <tt>c</tt> is |
---|
318 | called, a fresh variable <tt>value</tt> is created which, as usual, lasts the |
---|
319 | whole lifetime of <tt>c</tt>. Pay close attention however that <tt>c</tt> may |
---|
320 | call <tt>a</tt> recursively. When this happens, <tt>a</tt> may now refer to |
---|
321 | the local variable of <tt>c</tt><code><span class=special>.</span></code></p> |
---|
322 | <table border="0"> |
---|
323 | <tr> |
---|
324 | <td width="10"></td> |
---|
325 | <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> |
---|
326 | <td width="30"><a href="phoenix.html"><img src="theme/l_arr.gif" border="0"></a></td> |
---|
327 | <td width="30"><a href="dynamic_parsers.html"><img src="theme/r_arr.gif" border="0"></a></td> |
---|
328 | </tr> |
---|
329 | </table> |
---|
330 | <br> |
---|
331 | <hr size="1"> |
---|
332 | <p class="copyright">Copyright © 1998-2003 Joel de Guzman<br> |
---|
333 | <br> |
---|
334 | <font size="2">Use, modification and distribution is subject to the Boost Software |
---|
335 | License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
---|
336 | http://www.boost.org/LICENSE_1_0.txt) </font> </p> |
---|
337 | </body> |
---|
338 | </html> |
---|