• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  Copyright (c) 2001-2011 Hartmut Kaiser
2 //  Copyright (c)      2010 Bryce Lelbach
3 //
4 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
5 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 #if !defined(BOOST_SPIRIT_LEX_STATE_SWITCHER_SEP_23_2007_0714PM)
8 #define BOOST_SPIRIT_LEX_STATE_SWITCHER_SEP_23_2007_0714PM
9 
10 #if defined(_MSC_VER)
11 #pragma once
12 #endif
13 
14 #include <boost/spirit/home/support/info.hpp>
15 #include <boost/spirit/home/qi/detail/attributes.hpp>
16 #include <boost/spirit/home/support/common_terminals.hpp>
17 #include <boost/spirit/home/support/string_traits.hpp>
18 #include <boost/spirit/home/support/has_semantic_action.hpp>
19 #include <boost/spirit/home/support/handles_container.hpp>
20 #include <boost/spirit/home/qi/skip_over.hpp>
21 #include <boost/spirit/home/qi/domain.hpp>
22 #include <boost/spirit/home/qi/parser.hpp>
23 #include <boost/spirit/home/qi/meta_compiler.hpp>
24 #include <boost/mpl/print.hpp>
25 
26 namespace boost { namespace spirit
27 {
28     ///////////////////////////////////////////////////////////////////////////
29     // Enablers
30     ///////////////////////////////////////////////////////////////////////////
31 
32     // enables set_state(s)
33     template <typename A0>
34     struct use_terminal<qi::domain
35       , terminal_ex<tag::set_state, fusion::vector1<A0> >
36     > : traits::is_string<A0> {};
37 
38     // enables *lazy* set_state(s)
39     template <>
40     struct use_lazy_terminal<
41         qi::domain, tag::set_state, 1
42     > : mpl::true_ {};
43 
44     // enables in_state(s)[p]
45     template <typename A0>
46     struct use_directive<qi::domain
47       , terminal_ex<tag::in_state, fusion::vector1<A0> >
48     > : traits::is_string<A0> {};
49 
50     // enables *lazy* in_state(s)[p]
51     template <>
52     struct use_lazy_directive<
53         qi::domain, tag::in_state, 1
54     > : mpl::true_ {};
55 
56 }}
57 
58 namespace boost { namespace spirit { namespace qi
59 {
60 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
61     using spirit::set_state;
62     using spirit::in_state;
63 #endif
64     using spirit::set_state_type;
65     using spirit::in_state_type;
66 
67     ///////////////////////////////////////////////////////////////////////////
68     namespace detail
69     {
70         template <typename Iterator>
71         inline std::size_t
set_lexer_state(Iterator & it,std::size_t state)72         set_lexer_state(Iterator& it, std::size_t state)
73         {
74             return it.set_state(state);
75         }
76 
77         template <typename Iterator, typename Char>
78         inline std::size_t
set_lexer_state(Iterator & it,Char const * statename)79         set_lexer_state(Iterator& it, Char const* statename)
80         {
81             std::size_t state = it.map_state(statename);
82 
83             //  If the following assertion fires you probably used the
84             //  set_state(...) or in_state(...)[...] lexer state switcher with
85             //  a lexer state name unknown to the lexer (no token definitions
86             //  have been associated with this lexer state).
87             BOOST_ASSERT(std::size_t(~0) != state);
88             return it.set_state(state);
89         }
90     }
91 
92     ///////////////////////////////////////////////////////////////////////////
93     //  Parser switching the state of the underlying lexer component.
94     //  This parser gets used for the set_state(...) construct.
95     ///////////////////////////////////////////////////////////////////////////
96     template <typename State>
97     struct state_switcher
98       : primitive_parser<state_switcher<State> >
99     {
100         typedef typename
101             remove_const<typename traits::char_type_of<State>::type>::type
102         char_type;
103         typedef std::basic_string<char_type> string_type;
104 
105         template <typename Context, typename Iterator>
106         struct attribute
107         {
108             typedef unused_type type;
109         };
110 
state_switcherboost::spirit::qi::state_switcher111         state_switcher(char_type const* state)
112           : state(state) {}
113 
114         template <typename Iterator, typename Context
115           , typename Skipper, typename Attribute>
parseboost::spirit::qi::state_switcher116         bool parse(Iterator& first, Iterator const& last
117           , Context& /*context*/, Skipper const& skipper
118           , Attribute& /*attr*/) const
119         {
120             qi::skip_over(first, last, skipper);   // always do a pre-skip
121 
122             // just switch the state and return success
123             detail::set_lexer_state(first, state.c_str());
124             return true;
125         }
126 
127         template <typename Context>
whatboost::spirit::qi::state_switcher128         info what(Context& /*context*/) const
129         {
130             return info("set_state");
131         }
132 
133         string_type state;
134     };
135 
136     ///////////////////////////////////////////////////////////////////////////
137     namespace detail
138     {
139         template <typename Iterator>
140         struct reset_state_on_exit
141         {
142             template <typename State>
reset_state_on_exitboost::spirit::qi::detail::reset_state_on_exit143             reset_state_on_exit(Iterator& it_, State state_)
144               : it(it_)
145               , state(set_lexer_state(it_, traits::get_c_string(state_)))
146             {}
147 
~reset_state_on_exitboost::spirit::qi::detail::reset_state_on_exit148             ~reset_state_on_exit()
149             {
150                 // reset the state of the underlying lexer instance
151                 set_lexer_state(it, state);
152             }
153 
154             Iterator& it;
155             std::size_t state;
156 
157             // silence MSVC warning C4512: assignment operator could not be generated
158             BOOST_DELETED_FUNCTION(reset_state_on_exit& operator= (reset_state_on_exit const&))
159         };
160     }
161 
162     ///////////////////////////////////////////////////////////////////////////
163     // Parser, which switches the state of the underlying lexer component
164     // for the execution of the embedded sub-parser, switching the state back
165     // afterwards. This parser gets used for the in_state(...)[p] construct.
166     ///////////////////////////////////////////////////////////////////////////
167     template <typename Subject, typename State>
168     struct state_switcher_context
169       : unary_parser<state_switcher_context<Subject, State> >
170     {
171         typedef Subject subject_type;
172         typedef typename traits::char_type_of<State>::type char_type;
173         typedef typename remove_const<char_type>::type non_const_char_type;
174 
175         template <typename Context, typename Iterator>
176         struct attribute
177         {
178             typedef typename
179                 traits::attribute_of<subject_type, Context, Iterator>::type
180             type;
181         };
182 
state_switcher_contextboost::spirit::qi::state_switcher_context183         state_switcher_context(Subject const& subject
184               , typename add_reference<State>::type state)
185           : subject(subject), state(state) {}
186 
187         // The following conversion constructors are needed to make the
188         // in_state_switcher template usable
189         template <typename String>
state_switcher_contextboost::spirit::qi::state_switcher_context190         state_switcher_context(
191                 state_switcher_context<Subject, String> const& rhs)
192           : subject(rhs.subject), state(traits::get_c_string(rhs.state)) {}
193 
194         template <typename Iterator, typename Context
195           , typename Skipper, typename Attribute>
parseboost::spirit::qi::state_switcher_context196         bool parse(Iterator& first, Iterator const& last
197           , Context& context, Skipper const& skipper
198           , Attribute& attr) const
199         {
200             qi::skip_over(first, last, skipper);   // always do a pre-skip
201 
202             // the state has to be reset at exit in any case
203             detail::reset_state_on_exit<Iterator> guard(first, state);
204             return subject.parse(first, last, context, skipper, attr);
205         }
206 
207         template <typename Context>
whatboost::spirit::qi::state_switcher_context208         info what(Context& context) const
209         {
210             return info("in_state", subject.what(context));
211         }
212 
213         Subject subject;
214         State state;
215 
216         // silence MSVC warning C4512: assignment operator could not be generated
217         BOOST_DELETED_FUNCTION(state_switcher_context& operator= (state_switcher_context const&))
218     };
219 
220     ///////////////////////////////////////////////////////////////////////////
221     // Parser generators: make_xxx function (objects)
222     ///////////////////////////////////////////////////////////////////////////
223     template <typename Modifiers, typename State>
224     struct make_primitive<terminal_ex<tag::set_state, fusion::vector1<State> >
225       , Modifiers, typename enable_if<traits::is_string<State> >::type>
226     {
227         typedef typename add_const<State>::type const_string;
228         typedef state_switcher<const_string> result_type;
229 
230         template <typename Terminal>
operator ()boost::spirit::qi::make_primitive231         result_type operator()(Terminal const& term, unused_type) const
232         {
233             return result_type(traits::get_c_string(fusion::at_c<0>(term.args)));
234         }
235     };
236 
237     template <typename State, typename Subject, typename Modifiers>
238     struct make_directive<terminal_ex<tag::in_state, fusion::vector1<State> >
239       , Subject, Modifiers>
240     {
241         typedef typename add_const<State>::type const_string;
242         typedef state_switcher_context<Subject, const_string> result_type;
243 
244         template <typename Terminal>
operator ()boost::spirit::qi::make_directive245         result_type operator()(Terminal const& term, Subject const& subject
246           , unused_type) const
247         {
248             return result_type(subject, fusion::at_c<0>(term.args));
249         }
250     };
251 }}}
252 
253 namespace boost { namespace spirit { namespace traits
254 {
255     ///////////////////////////////////////////////////////////////////////////
256     template <typename Subject, typename State>
257     struct has_semantic_action<qi::state_switcher_context<Subject, State> >
258       : unary_has_semantic_action<Subject> {};
259 
260     ///////////////////////////////////////////////////////////////////////////
261     template <typename Subject, typename State, typename Attribute
262         , typename Context, typename Iterator>
263     struct handles_container<qi::state_switcher_context<Subject, State>
264           , Attribute, Context, Iterator>
265       : unary_handles_container<Subject, Attribute, Context, Iterator> {};
266 }}}
267 
268 #endif
269