source: NonGTP/Boost/boost/spirit/dynamic/switch.hpp @ 857

Revision 857, 8.8 KB checked in by igarcia, 18 years ago (diff)
Line 
1/*=============================================================================
2    Copyright (c) 2003 Hartmut Kaiser
3    http://spirit.sourceforge.net/
4
5    Use, modification and distribution is subject to the Boost Software
6    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7    http://www.boost.org/LICENSE_1_0.txt)
8=============================================================================*/
9#ifndef BOOST_SPIRIT_SWITCH_HPP
10#define BOOST_SPIRIT_SWITCH_HPP
11
12///////////////////////////////////////////////////////////////////////////////
13//
14//  The default_p parser generator template uses the following magic number
15//  as the corresponding case label value inside the generated switch()
16//  statements. If this number conflicts with your code, please pick a
17//  different one.
18//
19///////////////////////////////////////////////////////////////////////////////
20#if !defined(BOOST_SPIRIT_DEFAULTCASE_MAGIC)
21#define BOOST_SPIRIT_DEFAULTCASE_MAGIC 0x15F97A7
22#endif
23
24///////////////////////////////////////////////////////////////////////////////
25//
26//  Spirit predefined maximum number of possible case_p/default_p case branch
27//  parsers.
28//
29///////////////////////////////////////////////////////////////////////////////
30#if !defined(BOOST_SPIRIT_SWITCH_CASE_LIMIT)
31#define BOOST_SPIRIT_SWITCH_CASE_LIMIT 3
32#endif // !defined(BOOST_SPIRIT_SWITCH_CASE_LIMIT)
33
34///////////////////////////////////////////////////////////////////////////////
35#include <boost/static_assert.hpp>
36
37///////////////////////////////////////////////////////////////////////////////
38//
39// Ensure   BOOST_SPIRIT_SELECT_LIMIT > 0
40//
41///////////////////////////////////////////////////////////////////////////////
42BOOST_STATIC_ASSERT(BOOST_SPIRIT_SWITCH_CASE_LIMIT > 0);
43
44#include <boost/spirit/core/config.hpp>
45#include <boost/type_traits/is_same.hpp>
46#include <boost/spirit/core/parser.hpp>
47#include <boost/spirit/core/composite/epsilon.hpp>
48#include <boost/spirit/dynamic/impl/switch.ipp>
49
50///////////////////////////////////////////////////////////////////////////////
51namespace boost { namespace spirit {
52
53///////////////////////////////////////////////////////////////////////////////
54//
55//  The switch_parser allows to build switch like parsing constructs, which
56//  will have much better perfomance as comparable straight solutions.
57//
58//  Input stream driven syntax:
59//
60//      switch_p
61//      [
62//          case_p<'a'>
63//              (...parser to use, if the next character is 'a'...),
64//          case_p<'b'>
65//              (...parser to use, if the next character is 'b'...),
66//          default_p
67//              (...parser to use, if nothing was matched before...)
68//      ]
69//
70//  General syntax:
71//
72//      switch_p(...lazy expression returning the switch condition value...)
73//      [
74//          case_p<1>
75//              (...parser to use, if the switch condition value is 1...),
76//          case_p<2>
77//              (...parser to use, if the switch condition value is 2...),
78//          default_p
79//              (...parser to use, if nothing was matched before...)
80//      ]
81//
82//  The maximum number of possible case_p branches is defined by the p constant
83//  BOOST_SPIRIT_SWITCH_CASE_LIMIT (this value defaults to 3 if not otherwise
84//  defined).
85//
86///////////////////////////////////////////////////////////////////////////////
87template <typename CaseT, typename CondT = impl::get_next_token_cond>
88struct switch_parser
89:   public unary<CaseT, parser<switch_parser<CaseT, CondT> > >
90{
91    typedef switch_parser<CaseT, CondT>     self_t;
92    typedef unary_parser_category           parser_category_t;
93    typedef unary<CaseT, parser<self_t> >   base_t;
94
95    switch_parser(CaseT const &case_)
96    :   base_t(case_), cond(CondT())
97    {}
98
99    switch_parser(CaseT const &case_, CondT const &cond_)
100    :   base_t(case_), cond(cond_)
101    {}
102
103    template <typename ScannerT>
104    struct result
105    {
106        typedef typename match_result<ScannerT, nil_t>::type type;
107    };
108
109    template <typename ScannerT>
110    typename parser_result<self_t, ScannerT>::type
111    parse(ScannerT const& scan) const
112    {
113        return this->subject().parse(scan,
114            impl::make_cond_functor<CondT>::do_(cond));
115    }
116
117    CondT cond;
118};
119
120///////////////////////////////////////////////////////////////////////////////
121template <typename CondT>
122struct switch_cond_parser
123{
124    switch_cond_parser(CondT const &cond_)
125    :   cond(cond_)
126    {}
127
128    template <typename ParserT>
129    switch_parser<ParserT, CondT>
130    operator[](parser<ParserT> const &p) const
131    {
132        return switch_parser<ParserT, CondT>(p.derived(), cond);
133    }
134
135    CondT const &cond;
136};
137
138///////////////////////////////////////////////////////////////////////////////
139template <int N, typename ParserT, bool IsDefault>
140struct case_parser
141:   public unary<ParserT, parser<case_parser<N, ParserT, IsDefault> > >
142{
143    typedef case_parser<N, ParserT, IsDefault> self_t;
144    typedef unary_parser_category               parser_category_t;
145    typedef unary<ParserT, parser<self_t> >     base_t;
146
147    typedef typename base_t::subject_t          self_subject_t;
148
149    BOOST_STATIC_CONSTANT(int, value = N);
150    BOOST_STATIC_CONSTANT(bool, is_default = IsDefault);
151    BOOST_STATIC_CONSTANT(bool, is_simple = true);
152    BOOST_STATIC_CONSTANT(bool, is_epsilon = (
153        is_default && boost::is_same<self_subject_t, epsilon_parser>::value
154    ));
155
156    case_parser(parser<ParserT> const &p)
157    :   base_t(p.derived())
158    {}
159
160    template <typename ScannerT>
161    struct result
162    {
163        typedef typename match_result<ScannerT, nil_t>::type type;
164    };
165
166    template <typename ScannerT, typename CondT>
167    typename parser_result<self_t, ScannerT>::type
168    parse(ScannerT const& scan, CondT const &cond) const
169    {
170        typedef impl::default_case<self_t> default_t;
171
172        if (!scan.at_end()) {
173            typedef impl::default_delegate_parse<
174                value, is_default, default_t::value> default_parse_t;
175
176            typename ScannerT::iterator_t const save(scan.first);
177            return default_parse_t::parse(cond(scan), *this,
178                *this, scan, save);
179        }
180
181        return default_t::is_epsilon ? scan.empty_match() : scan.no_match();
182    }
183
184    template <int N1, typename ParserT1, bool IsDefault1>
185    impl::compound_case_parser<
186        self_t, case_parser<N1, ParserT1, IsDefault1>, IsDefault1
187    >
188    operator, (case_parser<N1, ParserT1, IsDefault1> const &p) const
189    {
190        //  If the following compile time assertion fires, you've probably used
191        //  more than one default_p case inside the switch_p parser construct.
192        BOOST_STATIC_ASSERT(!is_default || !IsDefault1);
193
194        typedef case_parser<N1, ParserT1, IsDefault1> right_t;
195        return impl::compound_case_parser<self_t, right_t, IsDefault1>(*this, p);
196    }
197};
198
199///////////////////////////////////////////////////////////////////////////////
200struct switch_parser_gen {
201
202//  This generates a switch parser, which is driven by the condition value
203//  returned by the lazy parameter expression 'cond'. This may be a parser,
204//  which result is used or a phoenix actor, which will be dereferenced to
205//  obtain the switch condition value.
206    template <typename CondT>
207    switch_cond_parser<CondT>
208    operator()(CondT const &cond) const
209    {
210        return switch_cond_parser<CondT>(cond);
211    }
212
213//  This generates a switch parser, which is driven by the next character/token
214//  found in the input stream.
215    template <typename CaseT>
216    switch_parser<CaseT>
217    operator[](parser<CaseT> const &p) const
218    {
219        return switch_parser<CaseT>(p.derived());
220    }
221};
222
223switch_parser_gen const switch_p = switch_parser_gen();
224
225///////////////////////////////////////////////////////////////////////////////
226template <int N, typename ParserT>
227inline case_parser<N, ParserT, false>
228case_p(parser<ParserT> const &p)
229{
230    return case_parser<N, ParserT, false>(p);
231}
232
233///////////////////////////////////////////////////////////////////////////////
234struct default_parser_gen
235:   public case_parser<BOOST_SPIRIT_DEFAULTCASE_MAGIC, epsilon_parser, true>
236{
237    default_parser_gen()
238    :   case_parser<BOOST_SPIRIT_DEFAULTCASE_MAGIC, epsilon_parser, true>
239            (epsilon_p)
240    {}
241
242    template <typename ParserT>
243    case_parser<BOOST_SPIRIT_DEFAULTCASE_MAGIC, ParserT, true>
244    operator()(parser<ParserT> const &p) const
245    {
246        return case_parser<BOOST_SPIRIT_DEFAULTCASE_MAGIC, ParserT, true>(p);
247    }
248};
249
250default_parser_gen const default_p = default_parser_gen();
251
252///////////////////////////////////////////////////////////////////////////////
253}}  // namespace boost::spirit
254
255#endif // BOOST_SPIRIT_SWITCH_HPP
Note: See TracBrowser for help on using the repository browser.