You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
575 lines
17 KiB
575 lines
17 KiB
/*============================================================================= |
|
Boost.Wave: A Standard compliant C++ preprocessor library |
|
|
|
Token sequence analysis and transformation helper functions |
|
|
|
http://www.boost.org/ |
|
|
|
Copyright (c) 2001-2011 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(CPP_MACROMAP_UTIL_HPP_HK041119) |
|
#define CPP_MACROMAP_UTIL_HPP_HK041119 |
|
|
|
#include <boost/assert.hpp> |
|
|
|
#include <boost/wave/wave_config.hpp> |
|
#include <boost/wave/token_ids.hpp> |
|
#include <boost/wave/util/unput_queue_iterator.hpp> |
|
|
|
// 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 <typename ContainerT> |
|
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 <typename ContainerT> |
|
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 <typename TypeT> |
|
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 <typename IteratorT, typename UnputIteratorT> |
|
class assign |
|
{ |
|
public: |
|
assign(IteratorT &it_, UnputIteratorT const &uit_) |
|
: it(it_), uit(uit_) {} |
|
~assign() { it = uit.base(); } |
|
|
|
private: |
|
IteratorT ⁢ |
|
UnputIteratorT const &uit; |
|
}; |
|
|
|
template <typename IteratorT> |
|
class assign<IteratorT, IteratorT> { |
|
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 <typename StringT> |
|
inline bool |
|
is_special_macroname (StringT const &name) |
|
{ |
|
if (name.size() < 7) |
|
return false; |
|
|
|
if ("defined" == name) |
|
return true; |
|
|
|
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 <typename TokenT> |
|
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 <typename ContainerT> |
|
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<const_iterator_type>::peek(first1, last1, false); |
|
token_id id2 = next_token<const_iterator_type>::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 <typename ContainerT> |
|
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 <typename ContainerT> |
|
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 <typename ContainerT> |
|
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; |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Remove all placeholder tokens from the given token sequence |
|
// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
template <typename ContainerT> |
|
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 <typename ContainerT> |
|
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 <typename ContainerT> |
|
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 <typename ContainerT> |
|
inline void |
|
trim_sequence (ContainerT &argument) |
|
{ |
|
trim_sequence_left(argument); |
|
trim_sequence_right(argument); |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
// call 'skipped_token' preprocessing hook |
|
template <typename ContextT> |
|
void call_skipped_token_hook(ContextT& ctx, |
|
typename ContextT::token_type const& skipped) |
|
{ |
|
#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 |
|
ctx.get_hooks().skipped_token(skipped); |
|
#else |
|
ctx.get_hooks().skipped_token(ctx.derived(), skipped); |
|
#endif |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Skip forward to a given token |
|
// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
template <typename ContextT, typename IteratorT> |
|
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 <typename IteratorT> |
|
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 <typename TokenT> |
|
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 <typename Target, typename Src> |
|
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 <typename Src> |
|
struct to_string_helper<Src, Src> |
|
{ |
|
typedef Src const& type; |
|
|
|
static Src const& call(Src const& str) |
|
{ |
|
return str; |
|
} |
|
}; |
|
|
|
template <typename Target> |
|
struct to_string_helper<Target, char const*> |
|
{ |
|
typedef Target type; |
|
|
|
static Target call(char const* str) |
|
{ |
|
return Target(str); |
|
} |
|
}; |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
} // namespace impl |
|
|
|
template <typename Target, typename Src> |
|
inline typename impl::to_string_helper<Target, Src>::type |
|
to_string(Src const& src) |
|
{ |
|
return impl::to_string_helper<Target, Src>::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(CPP_MACROMAP_UTIL_HPP_HK041119)
|
|
|