/*============================================================================= Boost.Wave: A Standard compliant C++ preprocessor library Token sequence analysis and transformation helper functions http://www.boost.org/ Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #if !defined(BOOST_CPP_MACROMAP_UTIL_HPP_HK041119) #define BOOST_CPP_MACROMAP_UTIL_HPP_HK041119 #include #include #include #include #include // this must occur after all of the includes and before any code appears #ifdef BOOST_HAS_ABI_HEADERS #include BOOST_ABI_PREFIX #endif /////////////////////////////////////////////////////////////////////////////// // // This file contains the definition of several token sequence analyze // and transformation utility functions needed during macro handling. // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace wave { namespace util { /////////////////////////////////////////////////////////////////////////////// namespace on_exit { /////////////////////////////////////////////////////////////////////////// // // On destruction pop the first element of the list given as the argument // /////////////////////////////////////////////////////////////////////////// template class pop_front { public: pop_front(ContainerT &list_) : list(list_) {} ~pop_front() { list.pop_front(); } private: ContainerT &list; }; /////////////////////////////////////////////////////////////////////////// // // Append a given list to the list given as argument // On destruction pop the first element of the list given as argument // /////////////////////////////////////////////////////////////////////////// template class splice_pop_front { public: splice_pop_front(ContainerT &list_, ContainerT &queue) : list(list_) { list.splice(list.end(), queue); } ~splice_pop_front() { list.pop_front(); } private: ContainerT &list; }; /////////////////////////////////////////////////////////////////////////// // // On destruction reset a referenced value to its initial state // /////////////////////////////////////////////////////////////////////////// template class reset { public: reset(TypeT &target_value_, TypeT new_value) : target_value(target_value_), old_value(target_value_) { target_value_ = new_value; } ~reset() { target_value = old_value; } private: TypeT &target_value; TypeT old_value; }; /////////////////////////////////////////////////////////////////////////// // // On destruction assign the given iterator back // /////////////////////////////////////////////////////////////////////////// template class assign { public: assign(IteratorT &it_, UnputIteratorT const &uit_) : it(it_), uit(uit_) {} ~assign() { it = uit.base(); } private: IteratorT ⁢ UnputIteratorT const &uit; }; template class assign { public: assign(IteratorT &it_, IteratorT const &uit_) : it(it_), uit(uit_) {} ~assign() { it = uit; } private: IteratorT ⁢ IteratorT const &uit; }; /////////////////////////////////////////////////////////////////////////////// } // namespace on_exit /////////////////////////////////////////////////////////////////////////////// namespace impl { /////////////////////////////////////////////////////////////////////////////// // // Test, whether a given identifier resolves to a predefined name // /////////////////////////////////////////////////////////////////////////////// template inline bool is_special_macroname (ContextT const & ctx, StringT const &name) { if (name.size() < 7) return false; if ("defined" == name) return true; #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0 if (boost::wave::need_has_include(ctx.get_language()) && ("__has_include" == name)) return true; #endif if ('_' == name[0] && '_' == name[1]) { StringT str = name.substr(2); if (str == "cplusplus" || str == "STDC__" || str == "TIME__" || str == "DATE__" || str == "LINE__" || str == "FILE__" || str == "INCLUDE_LEVEL__") { return true; } } return false; } /////////////////////////////////////////////////////////////////////////////// // // Test, whether two tokens are to be considered equal (different sequences // of whitespace are considered to be equal) // /////////////////////////////////////////////////////////////////////////////// template inline bool token_equals(TokenT const &left, TokenT const &right) { using namespace boost::wave; if (IS_CATEGORY(left, ParameterTokenType)) { // if the existing token is of type T_PARAMETERBASE, then the right token // must be of type T_IDENTIFIER or a keyword token_id id = token_id(right); return (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType) || IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) || IS_CATEGORY(id, BoolLiteralTokenType)) && left.get_value() == right.get_value(); } // if the left token has whitespace, the value is irrelevant return token_id(left) == token_id(right) && ( IS_CATEGORY(left, WhiteSpaceTokenType) || left.get_value() == right.get_value() ); } /////////////////////////////////////////////////////////////////////////////// // // Tests, whether two macro definitions are equal // /////////////////////////////////////////////////////////////////////////////// template inline bool definition_equals(ContainerT const &definition, ContainerT const &new_definition) { typedef typename ContainerT::const_iterator const_iterator_type; const_iterator_type first1 = definition.begin(); const_iterator_type last1 = definition.end(); const_iterator_type first2 = new_definition.begin(); const_iterator_type last2 = new_definition.end(); while (first1 != last1 && first2 != last2 && token_equals(*first1, *first2)) { // skip whitespace, if both sequences have a whitespace next token_id id1 = next_token::peek(first1, last1, false); token_id id2 = next_token::peek(first2, last2, false); if (IS_CATEGORY(id1, WhiteSpaceTokenType) && IS_CATEGORY(id2, WhiteSpaceTokenType)) { // all consecutive whitespace tokens count as one whitespace // adjust first1 and first2 accordingly skip_whitespace(first1, last1); skip_whitespace(first2, last2); } else if (!IS_CATEGORY(id1, WhiteSpaceTokenType) && !IS_CATEGORY(id2, WhiteSpaceTokenType)) { ++first1; ++first2; } else { // the sequences differ break; } } return (first1 == last1 && first2 == last2) ? true : false; } /////////////////////////////////////////////////////////////////////////////// // // Tests, whether two given sets of macro parameters are equal // /////////////////////////////////////////////////////////////////////////////// template inline bool parameters_equal(ContainerT const ¶meters, ContainerT const &new_parameters) { if (parameters.size() != new_parameters.size()) return false; // different parameter count typedef typename ContainerT::const_iterator const_iterator_type; const_iterator_type first1 = parameters.begin(); const_iterator_type last1 = parameters.end(); const_iterator_type first2 = new_parameters.begin(); const_iterator_type last2 = new_parameters.end(); while (first1 != last1 && first2 != last2) { // parameters are different, if the corresponding tokens are different using namespace boost::wave; if (token_id(*first1) != token_id(*first2) || (*first1).get_value() != (*first2).get_value()) { break; } ++first1; ++first2; } return (first1 == last1 && first2 == last2) ? true : false; } /////////////////////////////////////////////////////////////////////////////// // // Strip leading and trailing whitespace from the given token sequence // /////////////////////////////////////////////////////////////////////////////// template inline void trim_replacement_list (ContainerT &replacement_list) { using namespace boost::wave; // strip leading whitespace if (replacement_list.size() > 0) { typename ContainerT::iterator end = replacement_list.end(); typename ContainerT::iterator it = replacement_list.begin(); while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) { token_id id(*it); if (T_PLACEHOLDER != id && T_PLACEMARKER != id) { typename ContainerT::iterator next = it; ++next; replacement_list.erase(it); it = next; } else { ++it; } } } // strip trailing whitespace if (replacement_list.size() > 0) { typename ContainerT::reverse_iterator rend = replacement_list.rend(); typename ContainerT::reverse_iterator rit = replacement_list.rbegin(); while (rit != rend && IS_CATEGORY(*rit, WhiteSpaceTokenType)) ++rit; typename ContainerT::iterator end = replacement_list.end(); typename ContainerT::iterator it = rit.base(); while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) { token_id id(*it); if (T_PLACEHOLDER != id && T_PLACEMARKER != id) { typename ContainerT::iterator next = it; ++next; replacement_list.erase(it); it = next; } else { ++it; } } } } /////////////////////////////////////////////////////////////////////////////// // // Tests, whether the given token sequence consists out of whitespace only // /////////////////////////////////////////////////////////////////////////////// template inline bool is_whitespace_only (ContainerT const &argument) { typename ContainerT::const_iterator end = argument.end(); for (typename ContainerT::const_iterator it = argument.begin(); it != end; ++it) { if (!IS_CATEGORY(*it, WhiteSpaceTokenType)) return false; } return true; } /////////////////////////////////////////////////////////////////////////////// // // Tests whether the given token sequence consists only of whitespace // and placemarkers // /////////////////////////////////////////////////////////////////////////////// template inline bool is_blank_only (ContainerT const &argument) { typename ContainerT::const_iterator end = argument.end(); for (typename ContainerT::const_iterator it = argument.begin(); it != end; ++it) { if (!IS_CATEGORY(*it, WhiteSpaceTokenType) && (T_PLACEMARKER != token_id(*it))) return false; } return true; } /////////////////////////////////////////////////////////////////////////////// // // Remove all placeholder tokens from the given token sequence // /////////////////////////////////////////////////////////////////////////////// template inline void remove_placeholders (ContainerT &replacement_list) { using namespace boost::wave; // strip leading whitespace if (replacement_list.size() > 0) { typename ContainerT::iterator end = replacement_list.end(); typename ContainerT::iterator it = replacement_list.begin(); while (it != end) { token_id id(*it); if (T_PLACEHOLDER == id || T_PLACEMARKER == id) { typename ContainerT::iterator next = it; ++next; replacement_list.erase(it); it = next; } else { ++it; } } // remove all 'new' leading and trailing whitespace if (is_whitespace_only(replacement_list)) trim_replacement_list(replacement_list); } } /////////////////////////////////////////////////////////////////////////////// // // Remove all whitespace tokens on the left side of the given token sequence // /////////////////////////////////////////////////////////////////////////////// template inline void trim_sequence_left (ContainerT &argument) { using namespace boost::wave; // strip leading whitespace (should be only one token) if (argument.size() > 0 && IS_CATEGORY(argument.front(), WhiteSpaceTokenType)) { argument.pop_front(); } } /////////////////////////////////////////////////////////////////////////////// // // Remove all whitespace tokens on the right side of the given token sequence // /////////////////////////////////////////////////////////////////////////////// template inline void trim_sequence_right (ContainerT &argument) { using namespace boost::wave; // strip trailing whitespace (should be only one token) if (argument.size() > 0 && IS_CATEGORY(argument.back(), WhiteSpaceTokenType)) { argument.pop_back(); } } /////////////////////////////////////////////////////////////////////////////// // // Remove all whitespace tokens on the left and right sides of the given token // sequence // /////////////////////////////////////////////////////////////////////////////// template inline void trim_sequence (ContainerT &argument) { trim_sequence_left(argument); trim_sequence_right(argument); } /////////////////////////////////////////////////////////////////////////////// // call 'skipped_token' preprocessing hook template void call_skipped_token_hook(ContextT& ctx, typename ContextT::token_type const& skipped) { ctx.get_hooks().skipped_token(ctx.derived(), skipped); } /////////////////////////////////////////////////////////////////////////////// // // Skip forward to a given token // /////////////////////////////////////////////////////////////////////////////// template inline bool skip_to_token(ContextT& ctx, IteratorT &it, IteratorT const &end, token_id id, bool& seen_newline) { using namespace boost::wave; if (token_id(*it) == id) return true; // call_skipped_token_hook(ctx, *it); if (++it == end) return false; while (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == token_id(*it)) { if (T_NEWLINE == token_id(*it)) seen_newline = true; // call_skipped_token_hook(ctx, *it); if (++it == end) return false; } return token_id(*it) == id; } /////////////////////////////////////////////////////////////////////////////// // // Get the full name of a given macro name (concatenate the string // representations of the single tokens). // /////////////////////////////////////////////////////////////////////////////// template inline std::string get_full_name(IteratorT const &begin, IteratorT const &end) { std::string full_name; for (IteratorT err_it = begin; err_it != end; ++err_it) full_name += (*err_it).get_value().c_str(); return full_name; } /////////////////////////////////////////////////////////////////////////////// // // The following predicate is used in conjunction with the remove_copy_if // algorithm to allow the detection of an eventually copied operator ##. // No removal is performed in any case. // /////////////////////////////////////////////////////////////////////////////// class find_concat_operator { public: find_concat_operator(bool &found_) : found_concat(found_) {} template bool operator()(TokenT const &tok) { using namespace boost::wave; if (T_POUND_POUND == BASE_TOKEN(token_id(tok))) found_concat = true; return false; } private: bool &found_concat; }; /////////////////////////////////////////////////////////////////////////////// // Convert a string of an arbitrary string compatible type to a internal // string (BOOST_WAVE_STRING) template struct to_string_helper { typedef Target type; static Target call(Src const& str) { return Target(str.c_str()); } }; // do nothing if types are equal template struct to_string_helper { typedef Src const& type; static Src const& call(Src const& str) { return str; } }; template struct to_string_helper { typedef Target type; static Target call(char const* str) { return Target(str); } }; /////////////////////////////////////////////////////////////////////////////// } // namespace impl template inline typename impl::to_string_helper::type to_string(Src const& src) { return impl::to_string_helper::call(src); } /////////////////////////////////////////////////////////////////////////////// } // namespace util } // namespace wave } // namespace boost // the suffix header occurs after all of the code #ifdef BOOST_HAS_ABI_HEADERS #include BOOST_ABI_SUFFIX #endif #endif // !defined(BOOST_CPP_MACROMAP_UTIL_HPP_HK041119)