indepth_the_parser_context.html 19 KB

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