The Switch Parser |
Switch parsers may be used to simplify certain alternation constructs. Consider the following code:
rule<> rule_overall = ch_p('a') >> parser_a | ch_p('b') >> parser_b // ... | ch_p('n') >> parser_n ;
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 switch_p family of parsers. The switch_p parser allows us to rewrite the previous construct as:
rule<> rule_overall = switch_p [ case_p<'a'>(parser_a), case_p<'b'>(parser_b), // ... case_p<'n'>(parser_n) ] ;
This switch_p 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 case_p parsers. If this character matches one of the case_p branches, the associated parser is executed (i.e. if 'a' is matched, parser_a is executed, if 'b' is matched, parser_b is executed and so on) . If no case_p branch matches the next input character, the overall construct does not match at all.
Nabialek trick The "Nabialek trick" (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 switch_p parser, yet, can handle grammars where a keyword (operator, etc), instead of a single character or token, precedes a production. |
Sometimes it is desirable to add handling of the default case (none of the case_p branches matched). This may be achieved with the help of a default_p branch:
rule<> rule_overall = switch_p [ case_p<'a'>(parser_a), case_p<'b'>(parser_b), // ... case_p<'n'>(parser_n), default_p(parser_default) ] ;
This form chooses the parser_default parser if none of the cases matches the next character from the input stream. Please note that, obviously, only one default_p branch may be added to the switch_p parser construct.
Moreover, it is possible to omit the parentheses and body from the default_p construct, in which case, no additional parser is executed and the overall switch_p construct simply returns a match on any character of the input stream, which does not match any of the case_p branches:
rule<> rule_overall = switch_p [ case_p<'a'>(parser_a), case_p<'b'>(parser_b), // ... case_p<'n'>(parser_n), default_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 case_p branches:
rule<> rule_overall = switch_p(cond) [ case_p<'a'>(parser_a), case_p<'b'>(parser_b), // ... case_p<'n'>(parser_n) ] ;
where cond 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 case_p branches. If it is a nullary function or functor, then its return value will be used.
Please note that during its compilation, the switch_p construct is transformed into a real C++ switch statement. This makes the runtime execution very efficient.
BOOST_SPIRIT_SWITCH_CASE_LIMIT Example: // Define these before including switch.hpp |
Copyright © 2003-2004 Hartmut Kaiser
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)