1 | <html> |
---|
2 | <head> |
---|
3 | <title>The Switch Parser</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 | .style3 {font-family: "Courier New", Courier, mono; color: #FF0000; } |
---|
10 | --> |
---|
11 | </style> |
---|
12 | </head> |
---|
13 | |
---|
14 | <body> |
---|
15 | <table width="100%" border="0" background="theme/bkd2.gif" cellspacing="2"> |
---|
16 | <tr> |
---|
17 | <td width="10"> </td> |
---|
18 | <td width="85%"> <font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>The Switch Parser </b></font></td> |
---|
19 | <td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" width="112" height="48" align="right" border="0"></a></td> |
---|
20 | </tr> |
---|
21 | </table> |
---|
22 | <br> |
---|
23 | <table border="0"> |
---|
24 | <tr> |
---|
25 | <td width="10"></td> |
---|
26 | <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> |
---|
27 | <td width="30"><a href="select_parser.html"><img src="theme/l_arr.gif" border="0"></a></td> |
---|
28 | <td width="30"><a href="escape_char_parser.html"><img src="theme/r_arr.gif" border="0"></a></td> |
---|
29 | </tr> |
---|
30 | </table> |
---|
31 | <p>Switch parsers may be used to simplify certain alternation constructs. Consider the following code:</p> |
---|
32 | <pre> rule<span class="special"><></span> rule_overall <span class="special">=</span> |
---|
33 | ch_p<span class="special">(</span><span class="literal">'a'</span><span class="special">)</span> <span class="special">>></span> parser_a |
---|
34 | <span class="special">|</span> ch_p<span class="special">(</span><span class="literal">'b'</span><span class="special">)</span> <span class="special">>></span> parser_b |
---|
35 | <span class="comment">// ...</span> |
---|
36 | <span class="special">|</span> ch_p<span class="special">(</span><span class="literal">'n'</span><span class="special">)</span> <span class="special">>></span> parser_n |
---|
37 | <span class="special">;</span></pre> |
---|
38 | <p>Each of the alternatives are evaluated normally in a sequential manner. This tend to be inefficient, especially for a large number of alternatives. To avoid this inefficiency and to make it possible to write such constructs in a more readable form, Spirit contains the <tt>switch_p</tt> family of parsers. The switch_p parser allows us to rewrite the previous construct as:</p> |
---|
39 | <pre> rule<span class="special"><></span> rule_overall <span class="special">=</span> |
---|
40 | switch_p |
---|
41 | <span class="special">[</span> |
---|
42 | case_p<span class="special"><</span><span class="literal">'a'</span><span class="special">>(</span>parser_a<span class="special">),</span> |
---|
43 | case_p<span class="special"><</span><span class="literal">'b'</span><span class="special">>(</span>parser_b<span class="special">),</span> |
---|
44 | <span class="comment"> // ...</span> |
---|
45 | case_p<span class="special"><</span><span class="literal">'n'</span><span class="special">>(</span>parser_n<span class="special">)</span> |
---|
46 | ] |
---|
47 | ;</pre> |
---|
48 | <p>This <tt>switch_p</tt> parser takes the next character (or token) from the input stream and tries to match it against the given integral compile time constants supplied as the template parameters to the <tt>case_p</tt> parsers. If this character matches one of the <tt>case_p</tt> branches, the associated parser is executed (i.e. if 'a' is matched, <tt>parser_a</tt> is executed, if 'b' is matched, <tt>parser_b</tt> is executed and so on) . If no <tt>case_p</tt> branch matches the next input character, the overall construct does not match at all. </p> |
---|
49 | <table width="80%" border="0" align="center"> |
---|
50 | <tr> |
---|
51 | <td class="note_box"><div align="justify"><img src="theme/bulb.gif" width="13" height="18"><strong> Nabialek trick </strong><br> |
---|
52 | <br> |
---|
53 | The <strong><em><a href="techniques.html#nabialek_trick">"Nabialek trick" </a></em></strong>(from the name of its inventor, Sam Nabialek), can also improve the rule dispatch from linear non-deterministic to deterministic. This is similar to the <tt>switch_p</tt> parser, yet, can handle grammars where a keyword (operator, etc), instead of a single character or token, precedes a production.</div></td> |
---|
54 | </tr> |
---|
55 | </table> |
---|
56 | <p>Sometimes it is desireable to add handling of the default case (none of the <tt>case_p</tt> branches matched). This may be achieved with the help of a <tt>default_p</tt> branch:</p> |
---|
57 | <pre> rule<span class="special"><></span> rule_overall <span class="special">=</span> |
---|
58 | switch_p |
---|
59 | <span class="special">[</span> |
---|
60 | case_p<span class="special"><</span><span class="literal">'a'</span><span class="special">>(</span>parser_a<span class="special">),</span> |
---|
61 | case_p<span class="special"><</span><span class="literal">'b'</span><span class="special">>(</span>parser_b<span class="special">),</span> |
---|
62 | <span class="comment"> // ...</span> |
---|
63 | case_p<span class="special"><</span><span class="literal">'n'</span><span class="special">>(</span>parser_n<span class="special">),</span> |
---|
64 | default_p<span class="special">(</span>parser_default<span class="special">)</span> |
---|
65 | <span class="special">] |
---|
66 | ;</span></pre> |
---|
67 | <p>This form chooses the <tt>parser_default</tt> parser if none of the cases matches the next character from the input stream. Please note that, obviously, only one <tt>default_p</tt> branch may be added to the <tt>switch_p</tt> parser construct. </p> |
---|
68 | <p>Moreover, it is possible to omit the parentheses and body from the <tt>default_p</tt> construct, in which case, no additional parser is executed and the overall <tt>switch_p</tt> construct simply returns a match on any character of the input stream, which does not match any of the <tt>case_p</tt> branches:</p> |
---|
69 | <pre> rule<span class="special"><></span> rule_overall <span class="special">=</span> |
---|
70 | switch_p |
---|
71 | <span class="special">[</span> |
---|
72 | case_p<span class="special"><</span><span class="literal">'a'</span><span class="special">>(</span>parser_a<span class="special">),</span> |
---|
73 | case_p<span class="special"><</span><span class="literal">'b'</span><span class="special">>(</span>parser_b<span class="special">),</span> |
---|
74 | <span class="comment">// ...</span> |
---|
75 | case_p<span class="special"><</span><span class="literal">'n'</span><span class="special">>(</span>parser_n<span class="special">),</span> |
---|
76 | default_p |
---|
77 | <span class="special">]</span> |
---|
78 | ;</pre> |
---|
79 | <p>There is another form of the switch_p construct. This form allows us to explicitly specify the value to be used for matching against the <tt>case_p</tt> branches: </p> |
---|
80 | <pre> rule<span class="special"><></span> rule_overall <span class="special">=</span> |
---|
81 | switch_p<span class="special">(</span>cond<span class="special">)</span> |
---|
82 | <span class="special">[</span> |
---|
83 | case_p<span class="special"><</span><span class="literal">'a'</span><span class="special">>(</span>parser_a<span class="special">),</span> |
---|
84 | case_p<span class="special"><</span><span class="literal">'b'</span><span class="special">>(</span>parser_b<span class="special">),</span> |
---|
85 | <span class="comment"> // ...</span> |
---|
86 | case_p<span class="special"><</span><span class="literal">'n'</span><span class="special">>(</span>parser_n<span class="special">)</span> |
---|
87 | <span class="special">]</span> |
---|
88 | ;</pre> |
---|
89 | <p>where <tt>cond</tt> is a parser or a nullary function or function object (functor). If it is a parser, then it is tried and its return value is used to match against the <tt>case_p</tt> branches. If it is a nullary function or functor, then its return value will be used. </p> |
---|
90 | <p>Please note that during its compilation, the <tt>switch_p</tt> construct is transformed into a real C++ <tt>switch</tt> statement. This makes the runtime execution very efficient. </p> |
---|
91 | <table width="80%" border="0" align="center"> |
---|
92 | <tr> |
---|
93 | <td class="note_box"><p><img src="theme/alert.gif" width="16" height="16"> <tt>BOOST_SPIRIT_SWITCH_CASE_LIMIT</tt><br> |
---|
94 | <br> |
---|
95 | The number of possible <tt>case_p</tt>/<tt>default_p</tt> branches is limited by the Spirit compile time constant <tt>BOOST_SPIRIT_SWITCH_CASE_LIMIT</tt>, which defaults to 3. There is no theoretical upper limit for this constant, but most compilers won't allow you to specify a very large number.</p> |
---|
96 | <p>Example:</p> |
---|
97 | <p class="style1"><span class="comment">// Define these before including switch.hpp <br> |
---|
98 | </span><span class="preprocessor">#define</span> BOOST_SPIRIT_SWITCH_CASE_LIMIT 10 </p></td> |
---|
99 | </tr> |
---|
100 | </table><br> |
---|
101 | <table border="0"> |
---|
102 | <tr> |
---|
103 | <td width="10"></td> |
---|
104 | <td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td> |
---|
105 | <td width="30"><a href="select_parser.html"><img src="theme/l_arr.gif" border="0"></a></td> |
---|
106 | <td width="30"><a href="escape_char_parser.html"><img src="theme/r_arr.gif" border="0"></a></td> |
---|
107 | </tr> |
---|
108 | </table> |
---|
109 | <br> |
---|
110 | <hr size="1"> |
---|
111 | <p class="copyright">Copyright © 2003-2004 Hartmut Kaiser <br> |
---|
112 | <br> |
---|
113 | <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> |
---|
114 | </body> |
---|
115 | </html> |
---|