Chris@16
|
1 /*=============================================================================
|
Chris@16
|
2 Boost.Wave: A Standard compliant C++ preprocessor library
|
Chris@16
|
3
|
Chris@16
|
4 Token sequence analysis and transformation helper functions
|
Chris@16
|
5
|
Chris@16
|
6 http://www.boost.org/
|
Chris@16
|
7
|
Chris@16
|
8 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
|
Chris@16
|
9 Software License, Version 1.0. (See accompanying file
|
Chris@16
|
10 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
11 =============================================================================*/
|
Chris@16
|
12
|
Chris@16
|
13 #if !defined(CPP_MACROMAP_UTIL_HPP_HK041119)
|
Chris@16
|
14 #define CPP_MACROMAP_UTIL_HPP_HK041119
|
Chris@16
|
15
|
Chris@16
|
16 #include <boost/assert.hpp>
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/wave/wave_config.hpp>
|
Chris@16
|
19 #include <boost/wave/token_ids.hpp>
|
Chris@16
|
20 #include <boost/wave/util/unput_queue_iterator.hpp>
|
Chris@16
|
21
|
Chris@16
|
22 // this must occur after all of the includes and before any code appears
|
Chris@16
|
23 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
24 #include BOOST_ABI_PREFIX
|
Chris@16
|
25 #endif
|
Chris@16
|
26
|
Chris@16
|
27 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
28 //
|
Chris@16
|
29 // This file contains the definition of several token sequence analyze
|
Chris@16
|
30 // and transformation utility functions needed during macro handling.
|
Chris@16
|
31 //
|
Chris@16
|
32 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
33
|
Chris@16
|
34 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
35 namespace boost {
|
Chris@16
|
36 namespace wave {
|
Chris@16
|
37 namespace util {
|
Chris@16
|
38
|
Chris@16
|
39 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
40 namespace on_exit {
|
Chris@16
|
41
|
Chris@16
|
42 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
43 //
|
Chris@16
|
44 // On destruction pop the first element of the list given as the argument
|
Chris@16
|
45 //
|
Chris@16
|
46 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
47 template <typename ContainerT>
|
Chris@16
|
48 class pop_front {
|
Chris@16
|
49 public:
|
Chris@16
|
50 pop_front(ContainerT &list_) : list(list_) {}
|
Chris@16
|
51 ~pop_front() { list.pop_front(); }
|
Chris@16
|
52
|
Chris@16
|
53 private:
|
Chris@16
|
54 ContainerT &list;
|
Chris@16
|
55 };
|
Chris@16
|
56
|
Chris@16
|
57 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
58 //
|
Chris@16
|
59 // Append a given list to the list given as argument
|
Chris@16
|
60 // On destruction pop the first element of the list given as argument
|
Chris@16
|
61 //
|
Chris@16
|
62 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
63 template <typename ContainerT>
|
Chris@16
|
64 class splice_pop_front {
|
Chris@16
|
65 public:
|
Chris@16
|
66 splice_pop_front(ContainerT &list_, ContainerT &queue)
|
Chris@16
|
67 : list(list_)
|
Chris@16
|
68 {
|
Chris@16
|
69 list.splice(list.end(), queue);
|
Chris@16
|
70 }
|
Chris@16
|
71 ~splice_pop_front() { list.pop_front(); }
|
Chris@16
|
72
|
Chris@16
|
73 private:
|
Chris@16
|
74 ContainerT &list;
|
Chris@16
|
75 };
|
Chris@16
|
76
|
Chris@16
|
77 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
78 //
|
Chris@16
|
79 // On destruction reset a referenced value to its initial state
|
Chris@16
|
80 //
|
Chris@16
|
81 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
82 template <typename TypeT>
|
Chris@16
|
83 class reset {
|
Chris@16
|
84 public:
|
Chris@16
|
85 reset(TypeT &target_value_, TypeT new_value)
|
Chris@16
|
86 : target_value(target_value_), old_value(target_value_)
|
Chris@16
|
87 {
|
Chris@16
|
88 target_value_ = new_value;
|
Chris@16
|
89 }
|
Chris@16
|
90 ~reset() { target_value = old_value; }
|
Chris@16
|
91
|
Chris@16
|
92 private:
|
Chris@16
|
93 TypeT &target_value;
|
Chris@16
|
94 TypeT old_value;
|
Chris@16
|
95 };
|
Chris@16
|
96
|
Chris@16
|
97 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
98 //
|
Chris@16
|
99 // On destruction assign the given iterator back
|
Chris@16
|
100 //
|
Chris@16
|
101 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
102 template <typename IteratorT, typename UnputIteratorT>
|
Chris@16
|
103 class assign
|
Chris@16
|
104 {
|
Chris@16
|
105 public:
|
Chris@16
|
106 assign(IteratorT &it_, UnputIteratorT const &uit_)
|
Chris@16
|
107 : it(it_), uit(uit_) {}
|
Chris@16
|
108 ~assign() { it = uit.base(); }
|
Chris@16
|
109
|
Chris@16
|
110 private:
|
Chris@16
|
111 IteratorT ⁢
|
Chris@16
|
112 UnputIteratorT const &uit;
|
Chris@16
|
113 };
|
Chris@16
|
114
|
Chris@16
|
115 template <typename IteratorT>
|
Chris@16
|
116 class assign<IteratorT, IteratorT> {
|
Chris@16
|
117 public:
|
Chris@16
|
118 assign(IteratorT &it_, IteratorT const &uit_)
|
Chris@16
|
119 : it(it_), uit(uit_) {}
|
Chris@16
|
120 ~assign() { it = uit; }
|
Chris@16
|
121
|
Chris@16
|
122 private:
|
Chris@16
|
123 IteratorT ⁢
|
Chris@16
|
124 IteratorT const &uit;
|
Chris@16
|
125 };
|
Chris@16
|
126
|
Chris@16
|
127 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
128 } // namespace on_exit
|
Chris@16
|
129
|
Chris@16
|
130 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
131 namespace impl {
|
Chris@16
|
132
|
Chris@16
|
133 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
134 //
|
Chris@16
|
135 // Test, whether a given identifier resolves to a predefined name
|
Chris@16
|
136 //
|
Chris@16
|
137 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
138 template <typename StringT>
|
Chris@16
|
139 inline bool
|
Chris@16
|
140 is_special_macroname (StringT const &name)
|
Chris@16
|
141 {
|
Chris@16
|
142 if (name.size() < 7)
|
Chris@16
|
143 return false;
|
Chris@16
|
144
|
Chris@16
|
145 if ("defined" == name)
|
Chris@16
|
146 return true;
|
Chris@16
|
147
|
Chris@16
|
148 if ('_' == name[0] && '_' == name[1]) {
|
Chris@16
|
149 StringT str = name.substr(2);
|
Chris@16
|
150
|
Chris@16
|
151 if (str == "cplusplus" || str == "STDC__" ||
|
Chris@16
|
152 str == "TIME__" || str == "DATE__" ||
|
Chris@16
|
153 str == "LINE__" || str == "FILE__" ||
|
Chris@16
|
154 str == "INCLUDE_LEVEL__")
|
Chris@16
|
155 {
|
Chris@16
|
156 return true;
|
Chris@16
|
157 }
|
Chris@16
|
158 }
|
Chris@16
|
159 return false;
|
Chris@16
|
160 }
|
Chris@16
|
161
|
Chris@16
|
162 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
163 //
|
Chris@16
|
164 // Test, whether two tokens are to be considered equal (different sequences
|
Chris@16
|
165 // of whitespace are considered to be equal)
|
Chris@16
|
166 //
|
Chris@16
|
167 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
168 template <typename TokenT>
|
Chris@16
|
169 inline bool
|
Chris@16
|
170 token_equals(TokenT const &left, TokenT const &right)
|
Chris@16
|
171 {
|
Chris@16
|
172 using namespace boost::wave;
|
Chris@16
|
173
|
Chris@16
|
174 if (IS_CATEGORY(left, ParameterTokenType)) {
|
Chris@16
|
175 // if the existing token is of type T_PARAMETERBASE, then the right token
|
Chris@16
|
176 // must be of type T_IDENTIFIER or a keyword
|
Chris@16
|
177 token_id id = token_id(right);
|
Chris@16
|
178
|
Chris@16
|
179 return (T_IDENTIFIER == id ||
|
Chris@16
|
180 IS_CATEGORY(id, KeywordTokenType) ||
|
Chris@16
|
181 IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
|
Chris@16
|
182 IS_CATEGORY(id, BoolLiteralTokenType)) &&
|
Chris@16
|
183 left.get_value() == right.get_value();
|
Chris@16
|
184 }
|
Chris@16
|
185
|
Chris@16
|
186 // if the left token has whitespace, the value is irrelevant
|
Chris@16
|
187 return token_id(left) == token_id(right) && (
|
Chris@16
|
188 IS_CATEGORY(left, WhiteSpaceTokenType) ||
|
Chris@16
|
189 left.get_value() == right.get_value()
|
Chris@16
|
190 );
|
Chris@16
|
191 }
|
Chris@16
|
192
|
Chris@16
|
193 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
194 //
|
Chris@16
|
195 // Tests, whether two macro definitions are equal
|
Chris@16
|
196 //
|
Chris@16
|
197 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
198 template <typename ContainerT>
|
Chris@16
|
199 inline bool
|
Chris@16
|
200 definition_equals(ContainerT const &definition,
|
Chris@16
|
201 ContainerT const &new_definition)
|
Chris@16
|
202 {
|
Chris@16
|
203 typedef typename ContainerT::const_iterator const_iterator_type;
|
Chris@16
|
204
|
Chris@16
|
205 const_iterator_type first1 = definition.begin();
|
Chris@16
|
206 const_iterator_type last1 = definition.end();
|
Chris@16
|
207 const_iterator_type first2 = new_definition.begin();
|
Chris@16
|
208 const_iterator_type last2 = new_definition.end();
|
Chris@16
|
209
|
Chris@16
|
210 while (first1 != last1 && first2 != last2 && token_equals(*first1, *first2))
|
Chris@16
|
211 {
|
Chris@16
|
212 // skip whitespace, if both sequences have a whitespace next
|
Chris@16
|
213 token_id id1 = next_token<const_iterator_type>::peek(first1, last1, false);
|
Chris@16
|
214 token_id id2 = next_token<const_iterator_type>::peek(first2, last2, false);
|
Chris@16
|
215
|
Chris@16
|
216 if (IS_CATEGORY(id1, WhiteSpaceTokenType) &&
|
Chris@16
|
217 IS_CATEGORY(id2, WhiteSpaceTokenType))
|
Chris@16
|
218 {
|
Chris@16
|
219 // all consecutive whitespace tokens count as one whitespace
|
Chris@16
|
220 // adjust first1 and first2 accordingly
|
Chris@16
|
221 skip_whitespace(first1, last1);
|
Chris@16
|
222 skip_whitespace(first2, last2);
|
Chris@16
|
223 }
|
Chris@16
|
224 else if (!IS_CATEGORY(id1, WhiteSpaceTokenType) &&
|
Chris@16
|
225 !IS_CATEGORY(id2, WhiteSpaceTokenType))
|
Chris@16
|
226 {
|
Chris@16
|
227 ++first1;
|
Chris@16
|
228 ++first2;
|
Chris@16
|
229 }
|
Chris@16
|
230 else {
|
Chris@16
|
231 // the sequences differ
|
Chris@16
|
232 break;
|
Chris@16
|
233 }
|
Chris@16
|
234 }
|
Chris@16
|
235 return (first1 == last1 && first2 == last2) ? true : false;
|
Chris@16
|
236 }
|
Chris@16
|
237
|
Chris@16
|
238 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
239 //
|
Chris@16
|
240 // Tests, whether two given sets of macro parameters are equal
|
Chris@16
|
241 //
|
Chris@16
|
242 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
243 template <typename ContainerT>
|
Chris@16
|
244 inline bool
|
Chris@16
|
245 parameters_equal(ContainerT const ¶meters, ContainerT const &new_parameters)
|
Chris@16
|
246 {
|
Chris@16
|
247 if (parameters.size() != new_parameters.size())
|
Chris@16
|
248 return false; // different parameter count
|
Chris@16
|
249
|
Chris@16
|
250 typedef typename ContainerT::const_iterator const_iterator_type;
|
Chris@16
|
251
|
Chris@16
|
252 const_iterator_type first1 = parameters.begin();
|
Chris@16
|
253 const_iterator_type last1 = parameters.end();
|
Chris@16
|
254 const_iterator_type first2 = new_parameters.begin();
|
Chris@16
|
255 const_iterator_type last2 = new_parameters.end();
|
Chris@16
|
256
|
Chris@16
|
257 while (first1 != last1 && first2 != last2) {
|
Chris@16
|
258 // parameters are different, if the corresponding tokens are different
|
Chris@16
|
259 using namespace boost::wave;
|
Chris@16
|
260 if (token_id(*first1) != token_id(*first2) ||
|
Chris@16
|
261 (*first1).get_value() != (*first2).get_value())
|
Chris@16
|
262 {
|
Chris@16
|
263 break;
|
Chris@16
|
264 }
|
Chris@16
|
265 ++first1;
|
Chris@16
|
266 ++first2;
|
Chris@16
|
267 }
|
Chris@16
|
268 return (first1 == last1 && first2 == last2) ? true : false;
|
Chris@16
|
269 }
|
Chris@16
|
270
|
Chris@16
|
271 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
272 //
|
Chris@16
|
273 // Strip leading and trailing whitespace from the given token sequence
|
Chris@16
|
274 //
|
Chris@16
|
275 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
276 template <typename ContainerT>
|
Chris@16
|
277 inline void
|
Chris@16
|
278 trim_replacement_list (ContainerT &replacement_list)
|
Chris@16
|
279 {
|
Chris@16
|
280 using namespace boost::wave;
|
Chris@16
|
281
|
Chris@16
|
282 // strip leading whitespace
|
Chris@16
|
283 if (replacement_list.size() > 0) {
|
Chris@16
|
284 typename ContainerT::iterator end = replacement_list.end();
|
Chris@16
|
285 typename ContainerT::iterator it = replacement_list.begin();
|
Chris@16
|
286
|
Chris@16
|
287 while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
|
Chris@16
|
288 token_id id(*it);
|
Chris@16
|
289 if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
|
Chris@16
|
290 typename ContainerT::iterator next = it;
|
Chris@16
|
291 ++next;
|
Chris@16
|
292 replacement_list.erase(it);
|
Chris@16
|
293 it = next;
|
Chris@16
|
294 }
|
Chris@16
|
295 else {
|
Chris@16
|
296 ++it;
|
Chris@16
|
297 }
|
Chris@16
|
298 }
|
Chris@16
|
299 }
|
Chris@16
|
300
|
Chris@16
|
301 // strip trailing whitespace
|
Chris@16
|
302 if (replacement_list.size() > 0) {
|
Chris@16
|
303 typename ContainerT::reverse_iterator rend = replacement_list.rend();
|
Chris@16
|
304 typename ContainerT::reverse_iterator rit = replacement_list.rbegin();
|
Chris@16
|
305
|
Chris@16
|
306 while (rit != rend && IS_CATEGORY(*rit, WhiteSpaceTokenType))
|
Chris@16
|
307 ++rit;
|
Chris@16
|
308
|
Chris@16
|
309 typename ContainerT::iterator end = replacement_list.end();
|
Chris@16
|
310 typename ContainerT::iterator it = rit.base();
|
Chris@16
|
311
|
Chris@16
|
312 while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
|
Chris@16
|
313 token_id id(*it);
|
Chris@16
|
314 if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
|
Chris@16
|
315 typename ContainerT::iterator next = it;
|
Chris@16
|
316 ++next;
|
Chris@16
|
317 replacement_list.erase(it);
|
Chris@16
|
318 it = next;
|
Chris@16
|
319 }
|
Chris@16
|
320 else {
|
Chris@16
|
321 ++it;
|
Chris@16
|
322 }
|
Chris@16
|
323 }
|
Chris@16
|
324 }
|
Chris@16
|
325 }
|
Chris@16
|
326
|
Chris@16
|
327 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
328 //
|
Chris@16
|
329 // Tests, whether the given token sequence consists out of whitespace only
|
Chris@16
|
330 //
|
Chris@16
|
331 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
332 template <typename ContainerT>
|
Chris@16
|
333 inline bool
|
Chris@16
|
334 is_whitespace_only (ContainerT const &argument)
|
Chris@16
|
335 {
|
Chris@16
|
336 typename ContainerT::const_iterator end = argument.end();
|
Chris@16
|
337 for (typename ContainerT::const_iterator it = argument.begin();
|
Chris@16
|
338 it != end; ++it)
|
Chris@16
|
339 {
|
Chris@16
|
340 if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
|
Chris@16
|
341 return false;
|
Chris@16
|
342 }
|
Chris@16
|
343 return true;
|
Chris@16
|
344 }
|
Chris@16
|
345
|
Chris@16
|
346 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
347 //
|
Chris@16
|
348 // Remove all placeholder tokens from the given token sequence
|
Chris@16
|
349 //
|
Chris@16
|
350 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
351 template <typename ContainerT>
|
Chris@16
|
352 inline void
|
Chris@16
|
353 remove_placeholders (ContainerT &replacement_list)
|
Chris@16
|
354 {
|
Chris@16
|
355 using namespace boost::wave;
|
Chris@16
|
356
|
Chris@16
|
357 // strip leading whitespace
|
Chris@16
|
358 if (replacement_list.size() > 0) {
|
Chris@16
|
359 typename ContainerT::iterator end = replacement_list.end();
|
Chris@16
|
360 typename ContainerT::iterator it = replacement_list.begin();
|
Chris@16
|
361
|
Chris@16
|
362 while (it != end) {
|
Chris@16
|
363 token_id id(*it);
|
Chris@16
|
364 if (T_PLACEHOLDER == id || T_PLACEMARKER == id) {
|
Chris@16
|
365 typename ContainerT::iterator next = it;
|
Chris@16
|
366 ++next;
|
Chris@16
|
367 replacement_list.erase(it);
|
Chris@16
|
368 it = next;
|
Chris@16
|
369 }
|
Chris@16
|
370 else {
|
Chris@16
|
371 ++it;
|
Chris@16
|
372 }
|
Chris@16
|
373 }
|
Chris@16
|
374
|
Chris@16
|
375 // remove all 'new' leading and trailing whitespace
|
Chris@16
|
376 if (is_whitespace_only(replacement_list))
|
Chris@16
|
377 trim_replacement_list(replacement_list);
|
Chris@16
|
378 }
|
Chris@16
|
379 }
|
Chris@16
|
380
|
Chris@16
|
381 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
382 //
|
Chris@16
|
383 // Remove all whitespace tokens on the left side of the given token sequence
|
Chris@16
|
384 //
|
Chris@16
|
385 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
386 template <typename ContainerT>
|
Chris@16
|
387 inline void
|
Chris@16
|
388 trim_sequence_left (ContainerT &argument)
|
Chris@16
|
389 {
|
Chris@16
|
390 using namespace boost::wave;
|
Chris@16
|
391
|
Chris@16
|
392 // strip leading whitespace (should be only one token)
|
Chris@16
|
393 if (argument.size() > 0 &&
|
Chris@16
|
394 IS_CATEGORY(argument.front(), WhiteSpaceTokenType))
|
Chris@16
|
395 {
|
Chris@16
|
396 argument.pop_front();
|
Chris@16
|
397 }
|
Chris@16
|
398 }
|
Chris@16
|
399
|
Chris@16
|
400 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
401 //
|
Chris@16
|
402 // Remove all whitespace tokens on the right side of the given token sequence
|
Chris@16
|
403 //
|
Chris@16
|
404 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
405 template <typename ContainerT>
|
Chris@16
|
406 inline void
|
Chris@16
|
407 trim_sequence_right (ContainerT &argument)
|
Chris@16
|
408 {
|
Chris@16
|
409 using namespace boost::wave;
|
Chris@16
|
410
|
Chris@16
|
411 // strip trailing whitespace (should be only one token)
|
Chris@16
|
412 if (argument.size() > 0 &&
|
Chris@16
|
413 IS_CATEGORY(argument.back(), WhiteSpaceTokenType))
|
Chris@16
|
414 {
|
Chris@16
|
415 argument.pop_back();
|
Chris@16
|
416 }
|
Chris@16
|
417 }
|
Chris@16
|
418
|
Chris@16
|
419 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
420 //
|
Chris@16
|
421 // Remove all whitespace tokens on the left and right sides of the given token
|
Chris@16
|
422 // sequence
|
Chris@16
|
423 //
|
Chris@16
|
424 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
425 template <typename ContainerT>
|
Chris@16
|
426 inline void
|
Chris@16
|
427 trim_sequence (ContainerT &argument)
|
Chris@16
|
428 {
|
Chris@16
|
429 trim_sequence_left(argument);
|
Chris@16
|
430 trim_sequence_right(argument);
|
Chris@16
|
431 }
|
Chris@16
|
432
|
Chris@16
|
433 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
434 // call 'skipped_token' preprocessing hook
|
Chris@16
|
435 template <typename ContextT>
|
Chris@16
|
436 void call_skipped_token_hook(ContextT& ctx,
|
Chris@16
|
437 typename ContextT::token_type const& skipped)
|
Chris@16
|
438 {
|
Chris@16
|
439 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
|
Chris@16
|
440 ctx.get_hooks().skipped_token(skipped);
|
Chris@16
|
441 #else
|
Chris@16
|
442 ctx.get_hooks().skipped_token(ctx.derived(), skipped);
|
Chris@16
|
443 #endif
|
Chris@16
|
444 }
|
Chris@16
|
445
|
Chris@16
|
446 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
447 //
|
Chris@16
|
448 // Skip forward to a given token
|
Chris@16
|
449 //
|
Chris@16
|
450 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
451 template <typename ContextT, typename IteratorT>
|
Chris@16
|
452 inline bool
|
Chris@16
|
453 skip_to_token(ContextT& ctx, IteratorT &it, IteratorT const &end,
|
Chris@16
|
454 token_id id, bool& seen_newline)
|
Chris@16
|
455 {
|
Chris@16
|
456 using namespace boost::wave;
|
Chris@16
|
457 if (token_id(*it) == id)
|
Chris@16
|
458 return true;
|
Chris@16
|
459
|
Chris@16
|
460 // call_skipped_token_hook(ctx, *it);
|
Chris@16
|
461 if (++it == end)
|
Chris@16
|
462 return false;
|
Chris@16
|
463
|
Chris@16
|
464 while (IS_CATEGORY(*it, WhiteSpaceTokenType) ||
|
Chris@16
|
465 T_NEWLINE == token_id(*it))
|
Chris@16
|
466 {
|
Chris@16
|
467 if (T_NEWLINE == token_id(*it))
|
Chris@16
|
468 seen_newline = true;
|
Chris@16
|
469
|
Chris@16
|
470 // call_skipped_token_hook(ctx, *it);
|
Chris@16
|
471 if (++it == end)
|
Chris@16
|
472 return false;
|
Chris@16
|
473 }
|
Chris@16
|
474 return token_id(*it) == id;
|
Chris@16
|
475 }
|
Chris@16
|
476
|
Chris@16
|
477 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
478 //
|
Chris@16
|
479 // Get the full name of a given macro name (concatenate the string
|
Chris@16
|
480 // representations of the single tokens).
|
Chris@16
|
481 //
|
Chris@16
|
482 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
483 template <typename IteratorT>
|
Chris@16
|
484 inline std::string
|
Chris@16
|
485 get_full_name(IteratorT const &begin, IteratorT const &end)
|
Chris@16
|
486 {
|
Chris@16
|
487 std::string full_name;
|
Chris@16
|
488 for (IteratorT err_it = begin; err_it != end; ++err_it)
|
Chris@16
|
489 full_name += (*err_it).get_value().c_str();
|
Chris@16
|
490
|
Chris@16
|
491 return full_name;
|
Chris@16
|
492 }
|
Chris@16
|
493
|
Chris@16
|
494 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
495 //
|
Chris@16
|
496 // The following predicate is used in conjunction with the remove_copy_if
|
Chris@16
|
497 // algorithm to allow the detection of an eventually copied operator ##.
|
Chris@16
|
498 // No removal is performed in any case.
|
Chris@16
|
499 //
|
Chris@16
|
500 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
501 class find_concat_operator {
|
Chris@16
|
502 public:
|
Chris@16
|
503 find_concat_operator(bool &found_) : found_concat(found_) {}
|
Chris@16
|
504
|
Chris@16
|
505 template <typename TokenT>
|
Chris@16
|
506 bool operator()(TokenT const &tok)
|
Chris@16
|
507 {
|
Chris@16
|
508 using namespace boost::wave;
|
Chris@16
|
509 if (T_POUND_POUND == BASE_TOKEN(token_id(tok)))
|
Chris@16
|
510 found_concat = true;
|
Chris@16
|
511 return false;
|
Chris@16
|
512 }
|
Chris@16
|
513
|
Chris@16
|
514 private:
|
Chris@16
|
515 bool &found_concat;
|
Chris@16
|
516 };
|
Chris@16
|
517
|
Chris@16
|
518 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
519 // Convert a string of an arbitrary string compatible type to a internal
|
Chris@16
|
520 // string (BOOST_WAVE_STRING)
|
Chris@16
|
521 template <typename Target, typename Src>
|
Chris@16
|
522 struct to_string_helper
|
Chris@16
|
523 {
|
Chris@16
|
524 typedef Target type;
|
Chris@16
|
525
|
Chris@16
|
526 static Target call(Src const& str)
|
Chris@16
|
527 {
|
Chris@16
|
528 return Target(str.c_str());
|
Chris@16
|
529 }
|
Chris@16
|
530 };
|
Chris@16
|
531
|
Chris@16
|
532 // do nothing if types are equal
|
Chris@16
|
533 template <typename Src>
|
Chris@16
|
534 struct to_string_helper<Src, Src>
|
Chris@16
|
535 {
|
Chris@16
|
536 typedef Src const& type;
|
Chris@16
|
537
|
Chris@16
|
538 static Src const& call(Src const& str)
|
Chris@16
|
539 {
|
Chris@16
|
540 return str;
|
Chris@16
|
541 }
|
Chris@16
|
542 };
|
Chris@16
|
543
|
Chris@16
|
544 template <typename Target>
|
Chris@16
|
545 struct to_string_helper<Target, char const*>
|
Chris@16
|
546 {
|
Chris@16
|
547 typedef Target type;
|
Chris@16
|
548
|
Chris@16
|
549 static Target call(char const* str)
|
Chris@16
|
550 {
|
Chris@16
|
551 return Target(str);
|
Chris@16
|
552 }
|
Chris@16
|
553 };
|
Chris@16
|
554
|
Chris@16
|
555 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
556 } // namespace impl
|
Chris@16
|
557
|
Chris@16
|
558 template <typename Target, typename Src>
|
Chris@16
|
559 inline typename impl::to_string_helper<Target, Src>::type
|
Chris@16
|
560 to_string(Src const& src)
|
Chris@16
|
561 {
|
Chris@16
|
562 return impl::to_string_helper<Target, Src>::call(src);
|
Chris@16
|
563 }
|
Chris@16
|
564
|
Chris@16
|
565 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
566 } // namespace util
|
Chris@16
|
567 } // namespace wave
|
Chris@16
|
568 } // namespace boost
|
Chris@16
|
569
|
Chris@16
|
570 // the suffix header occurs after all of the code
|
Chris@16
|
571 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
572 #include BOOST_ABI_SUFFIX
|
Chris@16
|
573 #endif
|
Chris@16
|
574
|
Chris@16
|
575 #endif // !defined(CPP_MACROMAP_UTIL_HPP_HK041119)
|