The Switch Parser

| 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 desireable 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.

The number of possible `case_p`/`default_p` branches is limited by the Spirit compile time constant `BOOST_SPIRIT_SWITCH_CASE_LIMIT`, which defaults to 3. There is no theoretical upper limit for this constant, but most compilers won't allow to specify a very large number.

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)