]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | <html> |
2 | <head> | |
3 | <title>In-depth: The Parser Context</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 | </head> | |
7 | ||
8 | <body> | |
9 | <table width="100%" border="0" background="theme/bkd2.gif" cellspacing="2"> | |
10 | <tr> | |
11 | <td width="10"> | |
12 | </td> | |
13 | <td width="85%"> <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>In-depth: | |
14 | The Parser Context</b></font></td> | |
15 | <td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" width="112" height="48" align="right" border="0"></a></td> | |
16 | </tr> | |
17 | </table> | |
18 | <br> | |
19 | <table border="0"> | |
20 | <tr> | |
21 | <td width="10"></td> | |
22 | <td width="30"><a href="../index.html"> | |
23 | <img src="theme/u_arr.gif" border="0" width="20" height="19"></a></td> | |
24 | <td width="30"><a href="indepth_the_scanner.html"> | |
25 | <img src="theme/l_arr.gif" border="0" width="20" height="19"></a></td> | |
26 | <td width="30"><a href="predefined_actors.html"> | |
27 | <img src="theme/r_arr.gif" border="0" width="20" height="19"></a></td> | |
28 | </tr> | |
29 | </table> | |
30 | <h2>Overview</h2> | |
31 | <p>The parser's <b>context</b> is yet another concept. An instance (object) of | |
32 | the <tt>context</tt> class is created before a non-terminal starts parsing and | |
33 | is destructed after parsing has concluded. A non-terminal is either a <tt>rule</tt>, | |
34 | a <tt>subrule</tt>, or a <tt>grammar</tt>. Non-terminals have a <tt>ContextT</tt> template parameter. The following pseudo code depicts what's happening when | |
35 | a non-terminal is invoked:</p> | |
36 | <pre><code><font color="#000000"><span class=special> </span><span class=identifier>return_type | |
37 | </span><span class=identifier>a_non_terminal</span><span class=special>::</span><span class=identifier>parse</span><span class=special>(</span><span class=identifier>ScannerT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>scan</span><span class=special>) | |
38 | { | |
39 | </span><span class=identifier>context_t ctx</span><span class=special>(/**/); | |
40 | </span><span class=identifier>ctx</span><span class=special>.</span><span class=identifier>pre_parse</span><span class=special>(/**/); | |
41 | ||
42 | </span><span class=comment>// main parse code of the non-terminal here... | |
43 | ||
44 | </span><span class=keyword>return </span><span class=identifier>ctx</span><span class=special>.</span><span class=identifier>post_parse</span><span class=special>(/**/); | |
45 | }</span></font></code></pre> | |
46 | <p>The context is provided for extensibility. Its main purpose is to expose the | |
47 | start and end of the non-terminal's parse member function to accommodate external | |
48 | hooks. We can extend the non-terminal in a multitude of ways by writing specialized | |
49 | context classes, without modifying the class itself. For example, we can make | |
50 | the non-terminal emit debug diagnostics information by writing a context class | |
51 | that prints out the current state of the scanner at each point in the parse | |
52 | traversal where the non-terminal is invoked.</p> | |
53 | <p>Example of a parser context that prints out debug information:</p> | |
54 | <pre><code><font color="#000000"> pre_parse</font>:<font color="#000000"> non-terminal XXX is entered<font color="#0000ff">.</font> The current state of the input | |
55 | is <font color="#616161"><i>"hello world, this is a test"</i></font> | |
56 | ||
57 | post_parse</font>:<font color="#000000"> non-terminal XXX has concluded<font color="#0000ff">,</font> the non-terminal matched <font color="#616161"><i>"hello world"</i></font><font color="#0000ff">.</font> | |
58 | The current state of the input is <font color="#616161"><i>", this is a test"</i></font></font></code></pre> | |
59 | <p>Most of the time, the context will be invisible from the user's view. In general, | |
60 | clients of the framework need not deal directly nor even know about contexts. | |
61 | Power users, however, might find some use of contexts. Thus, this is part of | |
62 | the public API. Other parts of the framework in other layers above the core | |
63 | take advantage of the context to extend non-terminals. </p> | |
64 | <h2>Class declaration</h2> | |
65 | <p>The <tt>parser_context</tt> class is the default context class that the non-terminal | |
66 | uses. </p> | |
67 | <pre><span class=keyword> </span><span class="identifier">template</span> <span class="special"><</span><span class="keyword">typename</span> <span class="identifier">AttrT</span> <span class="special">=</span> <span class="identifier">nil_t</span><span class="special">></span><span class=keyword><br> struct </span><span class=identifier>parser_context | |
68 | </span><span class=special> { | |
69 | </span><span class=keyword>typedef </span>AttrT <span class=identifier>attr_t</span><span class=special>; | |
70 | </span><span class=keyword>typedef </span><span class=identifier>implementation_defined base_t</span><span class=special>; | |
71 | </span><span class="keyword">typedef</span><span class=special> </span>parser_context_linker<span class="special"><</span>parser_context<span class="special"><</span><span class="identifier">AttrT</span><span class="special">></span> <span class="special">></span> <span class="identifier">context_linker_t</span><span class=special>; | |
72 | ||
73 | </span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>ParserT</span><span class=special>> | |
74 | </span><span class=identifier>parser_context</span><span class=special>(</span><span class=identifier>ParserT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>p</span><span class=special>) {} | |
75 | ||
76 | </span><span class=keyword> template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>ParserT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>ScannerT</span><span class=special>> | |
77 | </span><span class=keyword> void | |
78 | </span><span class=identifier> pre_parse</span><span class=special>(</span><span class=identifier>ParserT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>p</span><span class=special>, </span><span class=identifier>ScannerT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>scan</span><span class=special>) {} | |
79 | ||
80 | </span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>ResultT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>ParserT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>ScannerT</span><span class=special>> | |
81 | </span><span class=identifier>ResultT</span><span class=special>& | |
82 | </span><span class=identifier> post_parse</span><span class=special>(</span><span class=identifier>ResultT</span><span class=special>& </span><span class=identifier>hit</span><span class=special>, </span><span class=identifier>ParserT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>p</span><span class=special>, </span><span class=identifier>ScannerT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>scan</span><span class=special>) | |
83 | { </span><span class=keyword>return </span><span class=identifier>hit</span><span class=special>; } | |
84 | };</span></pre> | |
85 | <p>The non-terminal's <tt>ContextT</tt> template parameter is a concept. The <tt>parser_context</tt> | |
86 | class above is the simplest model of this concept. The default <tt>parser_context</tt>'s<tt> | |
87 | pre_parse</tt> and <tt>post_parse</tt> member functions are simply no-ops. You | |
88 | can think of the non-terminal's <tt>ContextT</tt> template parameter as the | |
89 | policy that governs how the non-terminal will behave before and after parsing. | |
90 | The client can supply her own context policy by passing a user defined context | |
91 | template parameter to a particular non-terminal.</p> | |
92 | <table width="90%" border="0" align="center"> | |
93 | <tr> | |
94 | <td class="table_title" colspan="8"> Parser Context Policies </td> | |
95 | </tr> | |
96 | <tr> | |
97 | <tr> | |
98 | <td class="table_cells"><strong><span class=identifier>attr_t</span></strong></td> | |
99 | <td class="table_cells">typedef: the attribute type of the non-terminal. See | |
100 | the <a href="indepth_the_parser.html#match">match</a>.</td> | |
101 | </tr> | |
102 | <td class="table_cells"><strong><span class=identifier>base_t</span></strong></td> | |
103 | <td class="table_cells">typedef: the base class of the non-terminal. The non-terminal | |
104 | inherits from this class.</td> | |
105 | </tr> | |
106 | <tr> | |
107 | <td class="table_cells"><strong><span class="identifier">context_linker_t</span></strong></td> | |
108 | <td class="table_cells">typedef: this class type opens up the possibility | |
109 | for Spirit to plug in additional functionality into the non-terminal parse | |
110 | function or even bypass the given context. This should simply be typedefed | |
111 | to <tt>parser_context_linker<T></tt> where T is the type of the user | |
112 | defined context class.</td> | |
113 | </tr> | |
114 | <td class="table_cells"><strong>constructor</strong></td> | |
115 | <td class="table_cells">Construct the context. The non-terminal is passed as | |
116 | an argument to the constructor.</td> | |
117 | </tr> | |
118 | <tr> | |
119 | <td class="table_cells"><strong>pre_parse</strong></td> | |
120 | <td class="table_cells">Do something prior to parsing. The non-terminal and | |
121 | the current scanner are passed as arguments.</td> | |
122 | </tr> | |
123 | <tr> | |
124 | <td class="table_cells"><strong>post_parse</strong></td> | |
125 | <td class="table_cells">Do something after parsing. This is called regardless | |
126 | of the parse result. A reference to the parser's result is passed in. The | |
127 | context has the power to modify this. The non-terminal and the current scanner | |
128 | are also passed as arguments.</td> | |
129 | </tr> | |
130 | </table> | |
131 | <p>The <tt>base_t</tt> deserves further explanation. Here goes... The context | |
132 | is strictly a stack based class. It is created before parsing and destructed | |
133 | after the non-terminal's parse member function exits. Sometimes, we need | |
134 | auxiliary | |
135 | data that exists throughout the full lifetime of the non-terminal host. | |
136 | Since the non-terminal inherits from the context's <tt>base_t</tt>, the context | |
137 | itself, when created, gets access to this upon construction when the non-terminal | |
138 | is passed as an argument to the constructor. Ditto on <tt>pre_parse</tt> and | |
139 | <tt>post_parse</tt>.</p> | |
140 | <p>The non-terminal inherits from the context's <tt>base_t</tt> typedef. The sole | |
141 | requirement is that it is a class that is default constructible. The copy-construction | |
142 | and assignment requirements depends on the host. If the host requires it, so | |
143 | does the context's <tt>base_t</tt>. In general, it wouldn't hurt to provide | |
144 | these basic requirements.</p> | |
145 | <h2>Non-default Attribute Type </h2> | |
146 | <p>Right out of the box, the <tt>parser_context</tt> class may be paramaterized with a type other than the default <tt>nil_t</tt>. The following code demonstrates the usage of the <tt>parser_context</tt> template with an explicit argument to declare rules with match results different from <tt>nil_t</tt>:</p> | |
147 | <pre><span class=number> </span><span class=identifier>rule</span><span class=special><</span><span class=identifier>parser_context</span><span class=special><</span><span class=keyword>int</span><span class=special>> </span><span class=special>> </span><span class=identifier>int_rule </span><span class=special>= </span><span class=identifier>int_p</span><span class=special>; | |
148 | ||
149 | </span><span class=identifier>parse</span><span class=special>( | |
150 | </span><span class=string>"123"</span><span class=special>, | |
151 | </span><span class=comment>// Using a returned value in the semantic action | |
152 | </span><span class=identifier>int_rule</span><span class=special>[</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>arg1 </span><span class=special><< </span><span class=identifier>endl</span><span class=special>] | |
153 | </span><span class=special>);</span> </pre> | |
154 | <p>In this example, <tt>int_rule</tt> is declared with <tt>int</tt> attribute type. Hence, the <tt>int_rule</tt> variable can hold any parser which returns an <tt>int</tt> value (for example <tt>int_p</tt> or <tt>bin_p</tt>). The important thing to note is that we can use the returned value in the semantic action bound to the <tt>int_rule</tt>. </p> | |
155 | <p><img src="theme/lens.gif" width="15" height="16"> See <a href="../example/fundamental/parser_context.cpp">parser_context.cpp</a> in the examples. This is part of the Spirit distribution.</p> | |
156 | <h2>An Example </h2> | |
157 | <p>As an example let's have a look at the Spirit parser context, which inserts some debug output to the parsing process:</p> | |
158 | <pre> <span class="keyword">template</span><<span class="keyword">typename</span> ContextT> | |
159 | <span class="keyword">struct</span> parser_context_linker : <span class="keyword">public</span> ContextT | |
160 | <span class="special">{</span> | |
161 | <span class="keyword">typedef</span> ContextT base_t; | |
162 | ||
163 | <span class="keyword">template</span> <<span class="keyword">typename</span> ParserT> | |
164 | parser_context_linker(ParserT const& p) | |
165 | : ContextT(p) {} | |
166 | ||
167 | <span class="comment">// This is called just before parsing of this non-terminal</span> | |
168 | <span class="keyword">template</span> <span class="special"><</span><span class="keyword">typename</span> ParserT<span class="special">,</span> <span class="keyword">typename</span> ScannerT<span class="special">></span> | |
169 | <span class="keyword">void</span> pre_parse<span class="special">(</span>ParserT <span class="keyword">const</span><span class="special">&</span> p<span class="special">,</span> ScannerT <span class="special">&</span>scan<span class="special">)</span> | |
170 | <span class="special">{</span> | |
171 | <span class="comment">// call the pre_parse function of the base class</span> | |
172 | <span class="keyword">this</span><span class="special">-></span>base_t<span class="special">::</span>pre_parse<span class="special">(</span>p<span class="special">,</span> scan<span class="special">);</span> | |
173 | <span class="preprocessor"> | |
174 | #if</span> <span class="identifier">BOOST_SPIRIT_DEBUG_FLAGS</span> <span class="special">&</span> <span class="identifier">BOOST_SPIRIT_DEBUG_FLAGS_NODES</span> | |
175 | <span class="keyword">if</span> <span class="special">(</span>trace_parser<span class="special">(</span>p<span class="special">.</span>derived<span class="special">())) {</span> | |
176 | <span class="comment">// print out pre parse info</span> | |
177 | impl<span class="special">::</span>print_node_info<span class="special">(</span> | |
178 | <span class="keyword">false</span><span class="special">,</span> scan.get_level<span class="special">(),</span> <span class="keyword">false</span><span class="special">,</span> | |
179 | parser_name<span class="special">(</span>p.derived<span class="special">()),</span> | |
180 | scan<span class="special">.</span>first<span class="special">,</span> scan.last<span class="special">);</span> | |
181 | <span class="special">}</span> | |
182 | scan.get_level<span class="special">()++;</span> <span class="comment">// increase nesting level</span> | |
183 | <span class="preprocessor">#endif</span> | |
184 | <span class="special">}</span> | |
185 | <span class="comment">// This is called just after parsing of the current non-terminal</span> | |
186 | <span class="keyword">template</span> <span class="special"><</span><span class="keyword">typename</span> ResultT<span class="special">,</span> <span class="keyword">typename</span> ParserT<span class="special">,</span> <span class="keyword">typename</span> ScannerT<span class="special">></span> | |
187 | ResultT<span class="special">&</span> post_parse<span class="special">(</span> | |
188 | ResultT<span class="special">&</span> hit<span class="special">,</span> ParserT <span class="keyword">const</span><span class="special">&</span> p<span class="special">,</span> ScannerT<span class="special">&</span> scan<span class="special">) | |
189 | {</span> | |
190 | <span class="preprocessor"> | |
191 | #if</span> <span class="identifier">BOOST_SPIRIT_DEBUG_FLAGS</span> <span class="special">&</span> <span class="identifier">BOOST_SPIRIT_DEBUG_FLAGS_NODES</span> | |
192 | <span class="special">--</span>scan.get_level<span class="special">();</span> <span class="comment">// decrease nesting level</span> | |
193 | <span class="keyword">if</span> <span class="special">(</span>trace_parser<span class="special">(</span>p<span class="special">.</span>derived<span class="special">())) {</span> | |
194 | impl<span class="special">::</span>print_node_info<span class="special">(</span> | |
195 | hit<span class="special">,</span> scan<span class="special">.</span>get_level<span class="special">(),</span> <span class="keyword">true</span><span class="special">,</span> | |
196 | parser_name<span class="special">(</span>p<span class="special">.</span>derived<span class="special">()),</span> | |
197 | scan<span class="special">.</span>first<span class="special">,</span> scan<span class="special">.</span>last<span class="special">); | |
198 | }</span> | |
199 | <span class="preprocessor">#endif</span> | |
200 | <span class="comment">// call the post_parse function of the base class</span> | |
201 | <span class="keyword">return</span> <span class="keyword">this</span><span class="special">-></span>base_t<span class="special">::</span>post_parse<span class="special">(</span>hit<span class="special">,</span> p<span class="special">,</span> scan<span class="special">); | |
202 | } | |
203 | };</span> | |
204 | </pre> | |
205 | <p>During debugging (<tt>BOOST_SPIRIT_DEBUG</tt> is defined) this parser context is injected into the derivation hierarchy of the current <tt>parser_context</tt>, which was originally specified to be used for a concrete parser, so the template parameter <tt>ContextT</tt> represents the original <tt>parser_context</tt>. For this reason the <tt>pre_parse</tt> and <tt>post_parse</tt> functions call it's counterparts from the base class. Additionally these functions call a special <tt>print_node_info</tt> function, which does the actual output of the parser state info of the current non-terminal. For more info about the printed information, you may want to have a look at the topic <a href="debugging.html">Debugging</a>.</p> | |
206 | <table border="0"> | |
207 | <tr> | |
208 | <td width="10"></td> | |
209 | <td width="30"><a href="../index.html"> | |
210 | <img src="theme/u_arr.gif" border="0" width="20" height="19"></a></td> | |
211 | <td width="30"><a href="indepth_the_scanner.html"> | |
212 | <img src="theme/l_arr.gif" border="0" width="20" height="19"></a></td> | |
213 | <td width="30"><a href="predefined_actors.html"> | |
214 | <img src="theme/r_arr.gif" border="0" width="20" height="19"></a></td> | |
215 | </tr> | |
216 | </table> | |
217 | <br> | |
218 | <hr size="1"> | |
219 | <p class="copyright">Copyright © 1998-2003 Joel de Guzman<br> | |
220 | <br> | |
221 | <font size="2">Use, modification and distribution is subject to the Boost Software | |
222 | License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
223 | http://www.boost.org/LICENSE_1_0.txt)</font></p> | |
224 | <p class="copyright"> </p> | |
225 | </body> | |
226 | </html> |