1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
4 Token sequence analysis and transformation helper functions
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 =============================================================================*/
13 #if !defined(BOOST_CPP_MACROMAP_UTIL_HPP_HK041119)
14 #define BOOST_CPP_MACROMAP_UTIL_HPP_HK041119
16 #include <boost/assert.hpp>
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>
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
28 ///////////////////////////////////////////////////////////////////////////////
30 // This file contains the definition of several token sequence analyze
31 // and transformation utility functions needed during macro handling.
33 ///////////////////////////////////////////////////////////////////////////////
35 ///////////////////////////////////////////////////////////////////////////////
40 ///////////////////////////////////////////////////////////////////////////////
43 ///////////////////////////////////////////////////////////////////////////
45 // On destruction pop the first element of the list given as the argument
47 ///////////////////////////////////////////////////////////////////////////
48 template <typename ContainerT>
51 pop_front(ContainerT &list_) : list(list_) {}
52 ~pop_front() { list.pop_front(); }
58 ///////////////////////////////////////////////////////////////////////////
60 // Append a given list to the list given as argument
61 // On destruction pop the first element of the list given as argument
63 ///////////////////////////////////////////////////////////////////////////
64 template <typename ContainerT>
65 class splice_pop_front {
67 splice_pop_front(ContainerT &list_, ContainerT &queue)
70 list.splice(list.end(), queue);
72 ~splice_pop_front() { list.pop_front(); }
78 ///////////////////////////////////////////////////////////////////////////
80 // On destruction reset a referenced value to its initial state
82 ///////////////////////////////////////////////////////////////////////////
83 template <typename TypeT>
86 reset(TypeT &target_value_, TypeT new_value)
87 : target_value(target_value_), old_value(target_value_)
89 target_value_ = new_value;
91 ~reset() { target_value = old_value; }
98 ///////////////////////////////////////////////////////////////////////////
100 // On destruction assign the given iterator back
102 ///////////////////////////////////////////////////////////////////////////
103 template <typename IteratorT, typename UnputIteratorT>
107 assign(IteratorT &it_, UnputIteratorT const &uit_)
108 : it(it_), uit(uit_) {}
109 ~assign() { it = uit.base(); }
113 UnputIteratorT const &uit;
116 template <typename IteratorT>
117 class assign<IteratorT, IteratorT> {
119 assign(IteratorT &it_, IteratorT const &uit_)
120 : it(it_), uit(uit_) {}
121 ~assign() { it = uit; }
125 IteratorT const &uit;
128 ///////////////////////////////////////////////////////////////////////////////
129 } // namespace on_exit
131 ///////////////////////////////////////////////////////////////////////////////
134 ///////////////////////////////////////////////////////////////////////////////
136 // Test, whether a given identifier resolves to a predefined name
138 ///////////////////////////////////////////////////////////////////////////////
139 template <typename ContextT, typename StringT>
141 is_special_macroname (ContextT const & ctx, StringT const &name)
146 if ("defined" == name)
149 #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0
150 if (boost::wave::need_has_include(ctx.get_language()) &&
151 ("__has_include" == name))
155 if ('_' == name[0] && '_' == name[1]) {
156 StringT str = name.substr(2);
158 if (str == "cplusplus" || str == "STDC__" ||
159 str == "TIME__" || str == "DATE__" ||
160 str == "LINE__" || str == "FILE__" ||
161 str == "INCLUDE_LEVEL__")
169 ///////////////////////////////////////////////////////////////////////////////
171 // Test, whether two tokens are to be considered equal (different sequences
172 // of whitespace are considered to be equal)
174 ///////////////////////////////////////////////////////////////////////////////
175 template <typename TokenT>
177 token_equals(TokenT const &left, TokenT const &right)
179 using namespace boost::wave;
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);
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();
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()
200 ///////////////////////////////////////////////////////////////////////////////
202 // Tests, whether two macro definitions are equal
204 ///////////////////////////////////////////////////////////////////////////////
205 template <typename ContainerT>
207 definition_equals(ContainerT const &definition,
208 ContainerT const &new_definition)
210 typedef typename ContainerT::const_iterator const_iterator_type;
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();
217 while (first1 != last1 && first2 != last2 && token_equals(*first1, *first2))
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);
223 if (IS_CATEGORY(id1, WhiteSpaceTokenType) &&
224 IS_CATEGORY(id2, WhiteSpaceTokenType))
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);
231 else if (!IS_CATEGORY(id1, WhiteSpaceTokenType) &&
232 !IS_CATEGORY(id2, WhiteSpaceTokenType))
238 // the sequences differ
242 return (first1 == last1 && first2 == last2) ? true : false;
245 ///////////////////////////////////////////////////////////////////////////////
247 // Tests, whether two given sets of macro parameters are equal
249 ///////////////////////////////////////////////////////////////////////////////
250 template <typename ContainerT>
252 parameters_equal(ContainerT const ¶meters, ContainerT const &new_parameters)
254 if (parameters.size() != new_parameters.size())
255 return false; // different parameter count
257 typedef typename ContainerT::const_iterator const_iterator_type;
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();
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())
275 return (first1 == last1 && first2 == last2) ? true : false;
278 ///////////////////////////////////////////////////////////////////////////////
280 // Strip leading and trailing whitespace from the given token sequence
282 ///////////////////////////////////////////////////////////////////////////////
283 template <typename ContainerT>
285 trim_replacement_list (ContainerT &replacement_list)
287 using namespace boost::wave;
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();
294 while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
296 if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
297 typename ContainerT::iterator next = it;
299 replacement_list.erase(it);
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();
313 while (rit != rend && IS_CATEGORY(*rit, WhiteSpaceTokenType))
316 typename ContainerT::iterator end = replacement_list.end();
317 typename ContainerT::iterator it = rit.base();
319 while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
321 if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
322 typename ContainerT::iterator next = it;
324 replacement_list.erase(it);
334 ///////////////////////////////////////////////////////////////////////////////
336 // Tests, whether the given token sequence consists out of whitespace only
338 ///////////////////////////////////////////////////////////////////////////////
339 template <typename ContainerT>
341 is_whitespace_only (ContainerT const &argument)
343 typename ContainerT::const_iterator end = argument.end();
344 for (typename ContainerT::const_iterator it = argument.begin();
347 if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
353 ///////////////////////////////////////////////////////////////////////////////
355 // Tests whether the given token sequence consists only of whitespace
358 ///////////////////////////////////////////////////////////////////////////////
359 template <typename ContainerT>
361 is_blank_only (ContainerT const &argument)
363 typename ContainerT::const_iterator end = argument.end();
364 for (typename ContainerT::const_iterator it = argument.begin();
367 if (!IS_CATEGORY(*it, WhiteSpaceTokenType) &&
368 (T_PLACEMARKER != token_id(*it)))
374 ///////////////////////////////////////////////////////////////////////////////
376 // Remove all placeholder tokens from the given token sequence
378 ///////////////////////////////////////////////////////////////////////////////
379 template <typename ContainerT>
381 remove_placeholders (ContainerT &replacement_list)
383 using namespace boost::wave;
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();
392 if (T_PLACEHOLDER == id || T_PLACEMARKER == id) {
393 typename ContainerT::iterator next = it;
395 replacement_list.erase(it);
403 // remove all 'new' leading and trailing whitespace
404 if (is_whitespace_only(replacement_list))
405 trim_replacement_list(replacement_list);
409 ///////////////////////////////////////////////////////////////////////////////
411 // Remove all whitespace tokens on the left side of the given token sequence
413 ///////////////////////////////////////////////////////////////////////////////
414 template <typename ContainerT>
416 trim_sequence_left (ContainerT &argument)
418 using namespace boost::wave;
420 // strip leading whitespace (should be only one token)
421 if (argument.size() > 0 &&
422 IS_CATEGORY(argument.front(), WhiteSpaceTokenType))
424 argument.pop_front();
428 ///////////////////////////////////////////////////////////////////////////////
430 // Remove all whitespace tokens on the right side of the given token sequence
432 ///////////////////////////////////////////////////////////////////////////////
433 template <typename ContainerT>
435 trim_sequence_right (ContainerT &argument)
437 using namespace boost::wave;
439 // strip trailing whitespace (should be only one token)
440 if (argument.size() > 0 &&
441 IS_CATEGORY(argument.back(), WhiteSpaceTokenType))
447 ///////////////////////////////////////////////////////////////////////////////
449 // Remove all whitespace tokens on the left and right sides of the given token
452 ///////////////////////////////////////////////////////////////////////////////
453 template <typename ContainerT>
455 trim_sequence (ContainerT &argument)
457 trim_sequence_left(argument);
458 trim_sequence_right(argument);
461 ///////////////////////////////////////////////////////////////////////////////
462 // call 'skipped_token' preprocessing hook
463 template <typename ContextT>
464 void call_skipped_token_hook(ContextT& ctx,
465 typename ContextT::token_type const& skipped)
467 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
468 ctx.get_hooks().skipped_token(skipped);
470 ctx.get_hooks().skipped_token(ctx.derived(), skipped);
474 ///////////////////////////////////////////////////////////////////////////////
476 // Skip forward to a given token
478 ///////////////////////////////////////////////////////////////////////////////
479 template <typename ContextT, typename IteratorT>
481 skip_to_token(ContextT& ctx, IteratorT &it, IteratorT const &end,
482 token_id id, bool& seen_newline)
484 using namespace boost::wave;
485 if (token_id(*it) == id)
488 // call_skipped_token_hook(ctx, *it);
492 while (IS_CATEGORY(*it, WhiteSpaceTokenType) ||
493 T_NEWLINE == token_id(*it))
495 if (T_NEWLINE == token_id(*it))
498 // call_skipped_token_hook(ctx, *it);
502 return token_id(*it) == id;
505 ///////////////////////////////////////////////////////////////////////////////
507 // Get the full name of a given macro name (concatenate the string
508 // representations of the single tokens).
510 ///////////////////////////////////////////////////////////////////////////////
511 template <typename IteratorT>
513 get_full_name(IteratorT const &begin, IteratorT const &end)
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();
522 ///////////////////////////////////////////////////////////////////////////////
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.
528 ///////////////////////////////////////////////////////////////////////////////
529 class find_concat_operator {
531 find_concat_operator(bool &found_) : found_concat(found_) {}
533 template <typename TokenT>
534 bool operator()(TokenT const &tok)
536 using namespace boost::wave;
537 if (T_POUND_POUND == BASE_TOKEN(token_id(tok)))
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
554 static Target call(Src const& str)
556 return Target(str.c_str());
560 // do nothing if types are equal
561 template <typename Src>
562 struct to_string_helper<Src, Src>
564 typedef Src const& type;
566 static Src const& call(Src const& str)
572 template <typename Target>
573 struct to_string_helper<Target, char const*>
577 static Target call(char const* str)
583 ///////////////////////////////////////////////////////////////////////////////
586 template <typename Target, typename Src>
587 inline typename impl::to_string_helper<Target, Src>::type
588 to_string(Src const& src)
590 return impl::to_string_helper<Target, Src>::call(src);
593 ///////////////////////////////////////////////////////////////////////////////
598 // the suffix header occurs after all of the code
599 #ifdef BOOST_HAS_ABI_HEADERS
600 #include BOOST_ABI_SUFFIX
603 #endif // !defined(BOOST_CPP_MACROMAP_UTIL_HPP_HK041119)