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