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(CPP_MACROMAP_UTIL_HPP_HK041119)
14 #define 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>
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
27 ///////////////////////////////////////////////////////////////////////////////
29 // This file contains the definition of several token sequence analyze
30 // and transformation utility functions needed during macro handling.
32 ///////////////////////////////////////////////////////////////////////////////
34 ///////////////////////////////////////////////////////////////////////////////
39 ///////////////////////////////////////////////////////////////////////////////
42 ///////////////////////////////////////////////////////////////////////////
44 // On destruction pop the first element of the list given as the argument
46 ///////////////////////////////////////////////////////////////////////////
47 template <typename ContainerT>
50 pop_front(ContainerT &list_) : list(list_) {}
51 ~pop_front() { list.pop_front(); }
57 ///////////////////////////////////////////////////////////////////////////
59 // Append a given list to the list given as argument
60 // On destruction pop the first element of the list given as argument
62 ///////////////////////////////////////////////////////////////////////////
63 template <typename ContainerT>
64 class splice_pop_front {
66 splice_pop_front(ContainerT &list_, ContainerT &queue)
69 list.splice(list.end(), queue);
71 ~splice_pop_front() { list.pop_front(); }
77 ///////////////////////////////////////////////////////////////////////////
79 // On destruction reset a referenced value to its initial state
81 ///////////////////////////////////////////////////////////////////////////
82 template <typename TypeT>
85 reset(TypeT &target_value_, TypeT new_value)
86 : target_value(target_value_), old_value(target_value_)
88 target_value_ = new_value;
90 ~reset() { target_value = old_value; }
97 ///////////////////////////////////////////////////////////////////////////
99 // On destruction assign the given iterator back
101 ///////////////////////////////////////////////////////////////////////////
102 template <typename IteratorT, typename UnputIteratorT>
106 assign(IteratorT &it_, UnputIteratorT const &uit_)
107 : it(it_), uit(uit_) {}
108 ~assign() { it = uit.base(); }
112 UnputIteratorT const &uit;
115 template <typename IteratorT>
116 class assign<IteratorT, IteratorT> {
118 assign(IteratorT &it_, IteratorT const &uit_)
119 : it(it_), uit(uit_) {}
120 ~assign() { it = uit; }
124 IteratorT const &uit;
127 ///////////////////////////////////////////////////////////////////////////////
128 } // namespace on_exit
130 ///////////////////////////////////////////////////////////////////////////////
133 ///////////////////////////////////////////////////////////////////////////////
135 // Test, whether a given identifier resolves to a predefined name
137 ///////////////////////////////////////////////////////////////////////////////
138 template <typename StringT>
140 is_special_macroname (StringT const &name)
145 if ("defined" == name)
148 if ('_' == name[0] && '_' == name[1]) {
149 StringT str = name.substr(2);
151 if (str == "cplusplus" || str == "STDC__" ||
152 str == "TIME__" || str == "DATE__" ||
153 str == "LINE__" || str == "FILE__" ||
154 str == "INCLUDE_LEVEL__")
162 ///////////////////////////////////////////////////////////////////////////////
164 // Test, whether two tokens are to be considered equal (different sequences
165 // of whitespace are considered to be equal)
167 ///////////////////////////////////////////////////////////////////////////////
168 template <typename TokenT>
170 token_equals(TokenT const &left, TokenT const &right)
172 using namespace boost::wave;
174 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 token_id id = token_id(right);
179 return (T_IDENTIFIER == id ||
180 IS_CATEGORY(id, KeywordTokenType) ||
181 IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
182 IS_CATEGORY(id, BoolLiteralTokenType)) &&
183 left.get_value() == right.get_value();
186 // if the left token has whitespace, the value is irrelevant
187 return token_id(left) == token_id(right) && (
188 IS_CATEGORY(left, WhiteSpaceTokenType) ||
189 left.get_value() == right.get_value()
193 ///////////////////////////////////////////////////////////////////////////////
195 // Tests, whether two macro definitions are equal
197 ///////////////////////////////////////////////////////////////////////////////
198 template <typename ContainerT>
200 definition_equals(ContainerT const &definition,
201 ContainerT const &new_definition)
203 typedef typename ContainerT::const_iterator const_iterator_type;
205 const_iterator_type first1 = definition.begin();
206 const_iterator_type last1 = definition.end();
207 const_iterator_type first2 = new_definition.begin();
208 const_iterator_type last2 = new_definition.end();
210 while (first1 != last1 && first2 != last2 && token_equals(*first1, *first2))
212 // skip whitespace, if both sequences have a whitespace next
213 token_id id1 = next_token<const_iterator_type>::peek(first1, last1, false);
214 token_id id2 = next_token<const_iterator_type>::peek(first2, last2, false);
216 if (IS_CATEGORY(id1, WhiteSpaceTokenType) &&
217 IS_CATEGORY(id2, WhiteSpaceTokenType))
219 // all consecutive whitespace tokens count as one whitespace
220 // adjust first1 and first2 accordingly
221 skip_whitespace(first1, last1);
222 skip_whitespace(first2, last2);
224 else if (!IS_CATEGORY(id1, WhiteSpaceTokenType) &&
225 !IS_CATEGORY(id2, WhiteSpaceTokenType))
231 // the sequences differ
235 return (first1 == last1 && first2 == last2) ? true : false;
238 ///////////////////////////////////////////////////////////////////////////////
240 // Tests, whether two given sets of macro parameters are equal
242 ///////////////////////////////////////////////////////////////////////////////
243 template <typename ContainerT>
245 parameters_equal(ContainerT const ¶meters, ContainerT const &new_parameters)
247 if (parameters.size() != new_parameters.size())
248 return false; // different parameter count
250 typedef typename ContainerT::const_iterator const_iterator_type;
252 const_iterator_type first1 = parameters.begin();
253 const_iterator_type last1 = parameters.end();
254 const_iterator_type first2 = new_parameters.begin();
255 const_iterator_type last2 = new_parameters.end();
257 while (first1 != last1 && first2 != last2) {
258 // parameters are different, if the corresponding tokens are different
259 using namespace boost::wave;
260 if (token_id(*first1) != token_id(*first2) ||
261 (*first1).get_value() != (*first2).get_value())
268 return (first1 == last1 && first2 == last2) ? true : false;
271 ///////////////////////////////////////////////////////////////////////////////
273 // Strip leading and trailing whitespace from the given token sequence
275 ///////////////////////////////////////////////////////////////////////////////
276 template <typename ContainerT>
278 trim_replacement_list (ContainerT &replacement_list)
280 using namespace boost::wave;
282 // strip leading whitespace
283 if (replacement_list.size() > 0) {
284 typename ContainerT::iterator end = replacement_list.end();
285 typename ContainerT::iterator it = replacement_list.begin();
287 while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
289 if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
290 typename ContainerT::iterator next = it;
292 replacement_list.erase(it);
301 // strip trailing whitespace
302 if (replacement_list.size() > 0) {
303 typename ContainerT::reverse_iterator rend = replacement_list.rend();
304 typename ContainerT::reverse_iterator rit = replacement_list.rbegin();
306 while (rit != rend && IS_CATEGORY(*rit, WhiteSpaceTokenType))
309 typename ContainerT::iterator end = replacement_list.end();
310 typename ContainerT::iterator it = rit.base();
312 while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
314 if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
315 typename ContainerT::iterator next = it;
317 replacement_list.erase(it);
327 ///////////////////////////////////////////////////////////////////////////////
329 // Tests, whether the given token sequence consists out of whitespace only
331 ///////////////////////////////////////////////////////////////////////////////
332 template <typename ContainerT>
334 is_whitespace_only (ContainerT const &argument)
336 typename ContainerT::const_iterator end = argument.end();
337 for (typename ContainerT::const_iterator it = argument.begin();
340 if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
346 ///////////////////////////////////////////////////////////////////////////////
348 // Remove all placeholder tokens from the given token sequence
350 ///////////////////////////////////////////////////////////////////////////////
351 template <typename ContainerT>
353 remove_placeholders (ContainerT &replacement_list)
355 using namespace boost::wave;
357 // strip leading whitespace
358 if (replacement_list.size() > 0) {
359 typename ContainerT::iterator end = replacement_list.end();
360 typename ContainerT::iterator it = replacement_list.begin();
364 if (T_PLACEHOLDER == id || T_PLACEMARKER == id) {
365 typename ContainerT::iterator next = it;
367 replacement_list.erase(it);
375 // remove all 'new' leading and trailing whitespace
376 if (is_whitespace_only(replacement_list))
377 trim_replacement_list(replacement_list);
381 ///////////////////////////////////////////////////////////////////////////////
383 // Remove all whitespace tokens on the left side of the given token sequence
385 ///////////////////////////////////////////////////////////////////////////////
386 template <typename ContainerT>
388 trim_sequence_left (ContainerT &argument)
390 using namespace boost::wave;
392 // strip leading whitespace (should be only one token)
393 if (argument.size() > 0 &&
394 IS_CATEGORY(argument.front(), WhiteSpaceTokenType))
396 argument.pop_front();
400 ///////////////////////////////////////////////////////////////////////////////
402 // Remove all whitespace tokens on the right side of the given token sequence
404 ///////////////////////////////////////////////////////////////////////////////
405 template <typename ContainerT>
407 trim_sequence_right (ContainerT &argument)
409 using namespace boost::wave;
411 // strip trailing whitespace (should be only one token)
412 if (argument.size() > 0 &&
413 IS_CATEGORY(argument.back(), WhiteSpaceTokenType))
419 ///////////////////////////////////////////////////////////////////////////////
421 // Remove all whitespace tokens on the left and right sides of the given token
424 ///////////////////////////////////////////////////////////////////////////////
425 template <typename ContainerT>
427 trim_sequence (ContainerT &argument)
429 trim_sequence_left(argument);
430 trim_sequence_right(argument);
433 ///////////////////////////////////////////////////////////////////////////////
434 // call 'skipped_token' preprocessing hook
435 template <typename ContextT>
436 void call_skipped_token_hook(ContextT& ctx,
437 typename ContextT::token_type const& skipped)
439 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
440 ctx.get_hooks().skipped_token(skipped);
442 ctx.get_hooks().skipped_token(ctx.derived(), skipped);
446 ///////////////////////////////////////////////////////////////////////////////
448 // Skip forward to a given token
450 ///////////////////////////////////////////////////////////////////////////////
451 template <typename ContextT, typename IteratorT>
453 skip_to_token(ContextT& ctx, IteratorT &it, IteratorT const &end,
454 token_id id, bool& seen_newline)
456 using namespace boost::wave;
457 if (token_id(*it) == id)
460 // call_skipped_token_hook(ctx, *it);
464 while (IS_CATEGORY(*it, WhiteSpaceTokenType) ||
465 T_NEWLINE == token_id(*it))
467 if (T_NEWLINE == token_id(*it))
470 // call_skipped_token_hook(ctx, *it);
474 return token_id(*it) == id;
477 ///////////////////////////////////////////////////////////////////////////////
479 // Get the full name of a given macro name (concatenate the string
480 // representations of the single tokens).
482 ///////////////////////////////////////////////////////////////////////////////
483 template <typename IteratorT>
485 get_full_name(IteratorT const &begin, IteratorT const &end)
487 std::string full_name;
488 for (IteratorT err_it = begin; err_it != end; ++err_it)
489 full_name += (*err_it).get_value().c_str();
494 ///////////////////////////////////////////////////////////////////////////////
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.
500 ///////////////////////////////////////////////////////////////////////////////
501 class find_concat_operator {
503 find_concat_operator(bool &found_) : found_concat(found_) {}
505 template <typename TokenT>
506 bool operator()(TokenT const &tok)
508 using namespace boost::wave;
509 if (T_POUND_POUND == BASE_TOKEN(token_id(tok)))
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
526 static Target call(Src const& str)
528 return Target(str.c_str());
532 // do nothing if types are equal
533 template <typename Src>
534 struct to_string_helper<Src, Src>
536 typedef Src const& type;
538 static Src const& call(Src const& str)
544 template <typename Target>
545 struct to_string_helper<Target, char const*>
549 static Target call(char const* str)
555 ///////////////////////////////////////////////////////////////////////////////
558 template <typename Target, typename Src>
559 inline typename impl::to_string_helper<Target, Src>::type
560 to_string(Src const& src)
562 return impl::to_string_helper<Target, Src>::call(src);
565 ///////////////////////////////////////////////////////////////////////////////
570 // the suffix header occurs after all of the code
571 #ifdef BOOST_HAS_ABI_HEADERS
572 #include BOOST_ABI_SUFFIX
575 #endif // !defined(CPP_MACROMAP_UTIL_HPP_HK041119)