]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
f67539c2 TL |
27 | #include <boost/proto/extends.hpp> |
28 | #include <boost/proto/traits.hpp> | |
7c673cae FG |
29 | #include <boost/type_traits/is_same.hpp> |
30 | #include <boost/variant.hpp> | |
31 | ||
92f5a8d4 | 32 | #include <iterator> // for std::iterator_traits |
7c673cae FG |
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 | |
92f5a8d4 | 97 | std::iterator_traits<Iterator>::value_type |
7c673cae FG |
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 |