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