1 | // Copyright (c) 2001-2011 Hartmut Kaiser |
2 | // |
3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
5 | |
6 | #if !defined(BOOST_SPIRIT_LEX_TOKEN_DEF_MAR_13_2007_0145PM) |
7 | #define BOOST_SPIRIT_LEX_TOKEN_DEF_MAR_13_2007_0145PM |
8 | |
9 | #if defined(_MSC_VER) |
10 | #pragma once |
11 | #endif |
12 | |
13 | #include <boost/spirit/home/support/unused.hpp> |
14 | #include <boost/spirit/home/support/argument.hpp> |
15 | #include <boost/spirit/home/support/info.hpp> |
16 | #include <boost/spirit/home/support/handles_container.hpp> |
17 | #include <boost/spirit/home/qi/parser.hpp> |
18 | #include <boost/spirit/home/qi/skip_over.hpp> |
19 | #include <boost/spirit/home/qi/detail/construct.hpp> |
20 | #include <boost/spirit/home/qi/detail/assign_to.hpp> |
21 | #include <boost/spirit/home/lex/reference.hpp> |
22 | #include <boost/spirit/home/lex/lexer_type.hpp> |
23 | #include <boost/spirit/home/lex/lexer/terminals.hpp> |
24 | |
25 | #include <boost/fusion/include/vector.hpp> |
26 | #include <boost/mpl/if.hpp> |
27 | #include <boost/proto/extends.hpp> |
28 | #include <boost/proto/traits.hpp> |
29 | #include <boost/type_traits/is_same.hpp> |
30 | #include <boost/variant.hpp> |
31 | |
32 | #include <iterator> // for std::iterator_traits |
33 | #include <string> |
34 | #include <cstdlib> |
35 | |
36 | #if defined(BOOST_MSVC) |
37 | # pragma warning(push) |
38 | # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning |
39 | #endif |
40 | |
41 | namespace boost { namespace spirit { namespace lex |
42 | { |
43 | /////////////////////////////////////////////////////////////////////////// |
44 | // This component represents a token definition |
45 | /////////////////////////////////////////////////////////////////////////// |
46 | template<typename Attribute = unused_type |
47 | , typename Char = char |
48 | , typename Idtype = std::size_t> |
49 | struct token_def |
50 | : proto::extends< |
51 | typename proto::terminal< |
52 | lex::reference<token_def<Attribute, Char, Idtype> const, Idtype> |
53 | >::type |
54 | , token_def<Attribute, Char, Idtype> > |
55 | , qi::parser<token_def<Attribute, Char, Idtype> > |
56 | , lex::lexer_type<token_def<Attribute, Char, Idtype> > |
57 | { |
58 | private: |
59 | // initialize proto base class |
60 | typedef lex::reference<token_def const, Idtype> reference_; |
61 | typedef typename proto::terminal<reference_>::type terminal_type; |
62 | typedef proto::extends<terminal_type, token_def> proto_base_type; |
63 | |
64 | static std::size_t const all_states_id = static_cast<std::size_t>(-2); |
65 | |
66 | public: |
67 | // Qi interface: meta-function calculating parser return type |
68 | template <typename Context, typename Iterator> |
69 | struct attribute |
70 | { |
71 | // The return value of the token_def is either the specified |
72 | // attribute type, or the pair of iterators from the match of the |
73 | // corresponding token (if no attribute type has been specified), |
74 | // or unused_type (if omit has been specified). |
75 | typedef typename Iterator::base_iterator_type iterator_type; |
76 | typedef typename mpl::if_< |
77 | traits::not_is_unused<Attribute> |
78 | , typename mpl::if_< |
79 | is_same<Attribute, lex::omit>, unused_type, Attribute |
80 | >::type |
81 | , iterator_range<iterator_type> |
82 | >::type type; |
83 | }; |
84 | |
85 | public: |
86 | // Qi interface: parse functionality |
87 | template <typename Iterator, typename Context |
88 | , typename Skipper, typename Attribute_> |
89 | bool parse(Iterator& first, Iterator const& last |
90 | , Context& /*context*/, Skipper const& skipper |
91 | , Attribute_& attr) const |
92 | { |
93 | qi::skip_over(first, last, skipper); // always do a pre-skip |
94 | |
95 | if (first != last) { |
96 | typedef typename |
97 | std::iterator_traits<Iterator>::value_type |
98 | token_type; |
99 | |
100 | // If the following assertion fires you probably forgot to |
101 | // associate this token definition with a lexer instance. |
102 | BOOST_ASSERT(std::size_t(~0) != token_state_); |
103 | |
104 | token_type const& t = *first; |
105 | if (token_id_ == t.id() && |
106 | (all_states_id == token_state_ || token_state_ == t.state())) |
107 | { |
108 | spirit::traits::assign_to(t, attr); |
109 | ++first; |
110 | return true; |
111 | } |
112 | } |
113 | return false; |
114 | } |
115 | |
116 | template <typename Context> |
117 | info what(Context& /*context*/) const |
118 | { |
119 | if (0 == def_.which()) |
120 | return info("token_def" , boost::get<string_type>(def_)); |
121 | |
122 | return info("token_def" , boost::get<char_type>(def_)); |
123 | } |
124 | |
125 | /////////////////////////////////////////////////////////////////////// |
126 | // Lex interface: collect token definitions and put it into the |
127 | // provided lexer def |
128 | template <typename LexerDef, typename String> |
129 | void collect(LexerDef& lexdef, String const& state |
130 | , String const& targetstate) const |
131 | { |
132 | std::size_t state_id = lexdef.add_state(state.c_str()); |
133 | |
134 | // If the following assertion fires you are probably trying to use |
135 | // a single token_def instance in more than one lexer state. This |
136 | // is not possible. Please create a separate token_def instance |
137 | // from the same regular expression for each lexer state it needs |
138 | // to be associated with. |
139 | BOOST_ASSERT( |
140 | (std::size_t(~0) == token_state_ || state_id == token_state_) && |
141 | "Can't use single token_def with more than one lexer state" ); |
142 | |
143 | char_type const* target = targetstate.empty() ? 0 : targetstate.c_str(); |
144 | if (target) |
145 | lexdef.add_state(target); |
146 | |
147 | token_state_ = state_id; |
148 | if (0 == token_id_) |
149 | token_id_ = lexdef.get_next_id(); |
150 | |
151 | if (0 == def_.which()) { |
152 | unique_id_ = lexdef.add_token(state.c_str() |
153 | , boost::get<string_type>(def_), token_id_, target); |
154 | } |
155 | else { |
156 | unique_id_ = lexdef.add_token(state.c_str() |
157 | , boost::get<char_type>(def_), token_id_, target); |
158 | } |
159 | } |
160 | |
161 | template <typename LexerDef> |
162 | void add_actions(LexerDef&) const {} |
163 | |
164 | public: |
165 | typedef Char char_type; |
166 | typedef Idtype id_type; |
167 | typedef std::basic_string<char_type> string_type; |
168 | |
169 | // Lex interface: constructing token definitions |
170 | token_def() |
171 | : proto_base_type(terminal_type::make(reference_(*this))) |
172 | , def_('\0'), token_id_() |
173 | , unique_id_(std::size_t(~0)), token_state_(std::size_t(~0)) {} |
174 | |
175 | token_def(token_def const& rhs) |
176 | : proto_base_type(terminal_type::make(reference_(*this))) |
177 | , def_(rhs.def_), token_id_(rhs.token_id_) |
178 | , unique_id_(rhs.unique_id_), token_state_(rhs.token_state_) {} |
179 | |
180 | explicit token_def(char_type def_, Idtype id_ = Idtype()) |
181 | : proto_base_type(terminal_type::make(reference_(*this))) |
182 | , def_(def_) |
183 | , token_id_(Idtype() == id_ ? Idtype(def_) : id_) |
184 | , unique_id_(std::size_t(~0)), token_state_(std::size_t(~0)) {} |
185 | |
186 | explicit token_def(string_type const& def_, Idtype id_ = Idtype()) |
187 | : proto_base_type(terminal_type::make(reference_(*this))) |
188 | , def_(def_), token_id_(id_) |
189 | , unique_id_(std::size_t(~0)), token_state_(std::size_t(~0)) {} |
190 | |
191 | template <typename String> |
192 | token_def& operator= (String const& definition) |
193 | { |
194 | def_ = definition; |
195 | token_id_ = Idtype(); |
196 | unique_id_ = std::size_t(~0); |
197 | token_state_ = std::size_t(~0); |
198 | return *this; |
199 | } |
200 | token_def& operator= (token_def const& rhs) |
201 | { |
202 | def_ = rhs.def_; |
203 | token_id_ = rhs.token_id_; |
204 | unique_id_ = rhs.unique_id_; |
205 | token_state_ = rhs.token_state_; |
206 | return *this; |
207 | } |
208 | |
209 | // general accessors |
210 | Idtype const& id() const { return token_id_; } |
211 | void id(Idtype const& id) { token_id_ = id; } |
212 | std::size_t unique_id() const { return unique_id_; } |
213 | |
214 | string_type definition() const |
215 | { |
216 | return (0 == def_.which()) ? |
217 | boost::get<string_type>(def_) : |
218 | string_type(1, boost::get<char_type>(def_)); |
219 | } |
220 | std::size_t state() const { return token_state_; } |
221 | |
222 | private: |
223 | variant<string_type, char_type> def_; |
224 | mutable Idtype token_id_; |
225 | mutable std::size_t unique_id_; |
226 | mutable std::size_t token_state_; |
227 | }; |
228 | }}} |
229 | |
230 | namespace boost { namespace spirit { namespace traits |
231 | { |
232 | /////////////////////////////////////////////////////////////////////////// |
233 | template<typename Attribute, typename Char, typename Idtype |
234 | , typename Attr, typename Context, typename Iterator> |
235 | struct handles_container< |
236 | lex::token_def<Attribute, Char, Idtype>, Attr, Context, Iterator> |
237 | : traits::is_container< |
238 | typename attribute_of< |
239 | lex::token_def<Attribute, Char, Idtype>, Context, Iterator |
240 | >::type> |
241 | {}; |
242 | }}} |
243 | |
244 | #if defined(BOOST_MSVC) |
245 | # pragma warning(pop) |
246 | #endif |
247 | |
248 | #endif |
249 | |