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