Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:53:41

0001 /*=============================================================================
0002     Boost.Wave: A Standard compliant C++ preprocessor library
0003 
0004     Token sequence analysis and transformation helper functions
0005 
0006     http://www.boost.org/
0007 
0008     Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
0009     Software License, Version 1.0. (See accompanying file
0010     LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0011 =============================================================================*/
0012 
0013 #if !defined(BOOST_CPP_MACROMAP_UTIL_HPP_HK041119)
0014 #define BOOST_CPP_MACROMAP_UTIL_HPP_HK041119
0015 
0016 #include <boost/assert.hpp>
0017 
0018 #include <boost/wave/wave_config.hpp>
0019 #include <boost/wave/token_ids.hpp>
0020 #include <boost/wave/util/unput_queue_iterator.hpp>
0021 #include <boost/wave/language_support.hpp>
0022 
0023 // this must occur after all of the includes and before any code appears
0024 #ifdef BOOST_HAS_ABI_HEADERS
0025 #include BOOST_ABI_PREFIX
0026 #endif
0027 
0028 ///////////////////////////////////////////////////////////////////////////////
0029 //
0030 // This file contains the definition of several token sequence analyze
0031 // and transformation utility functions needed during macro handling.
0032 //
0033 ///////////////////////////////////////////////////////////////////////////////
0034 
0035 ///////////////////////////////////////////////////////////////////////////////
0036 namespace boost {
0037 namespace wave {
0038 namespace util {
0039 
0040 ///////////////////////////////////////////////////////////////////////////////
0041 namespace on_exit {
0042 
0043     ///////////////////////////////////////////////////////////////////////////
0044     //
0045     //  On destruction pop the first element of the list given as the argument
0046     //
0047     ///////////////////////////////////////////////////////////////////////////
0048     template <typename ContainerT>
0049     class pop_front {
0050     public:
0051         pop_front(ContainerT &list_) : list(list_) {}
0052         ~pop_front() { list.pop_front(); }
0053 
0054     private:
0055         ContainerT &list;
0056     };
0057 
0058     ///////////////////////////////////////////////////////////////////////////
0059     //
0060     //  Append a given list to the list given as argument
0061     //  On destruction pop the first element of the list given as argument
0062     //
0063     ///////////////////////////////////////////////////////////////////////////
0064     template <typename ContainerT>
0065     class splice_pop_front {
0066     public:
0067         splice_pop_front(ContainerT &list_, ContainerT &queue)
0068         :   list(list_)
0069         {
0070             list.splice(list.end(), queue);
0071         }
0072         ~splice_pop_front() { list.pop_front(); }
0073 
0074     private:
0075         ContainerT &list;
0076     };
0077 
0078     ///////////////////////////////////////////////////////////////////////////
0079     //
0080     //  On destruction reset a referenced value to its initial state
0081     //
0082     ///////////////////////////////////////////////////////////////////////////
0083     template <typename TypeT>
0084     class reset {
0085     public:
0086         reset(TypeT &target_value_, TypeT new_value)
0087         :   target_value(target_value_), old_value(target_value_)
0088         {
0089             target_value_ = new_value;
0090         }
0091         ~reset() { target_value = old_value; }
0092 
0093     private:
0094         TypeT &target_value;
0095         TypeT old_value;
0096     };
0097 
0098     ///////////////////////////////////////////////////////////////////////////
0099     //
0100     //  On destruction assign the given iterator back
0101     //
0102     ///////////////////////////////////////////////////////////////////////////
0103     template <typename IteratorT, typename UnputIteratorT>
0104     class assign
0105     {
0106     public:
0107         assign(IteratorT &it_, UnputIteratorT const &uit_)
0108         :   it(it_), uit(uit_) {}
0109         ~assign() { it = uit.base(); }
0110 
0111     private:
0112         IteratorT &it;
0113         UnputIteratorT const &uit;
0114     };
0115 
0116     template <typename IteratorT>
0117     class assign<IteratorT, IteratorT> {
0118     public:
0119         assign(IteratorT &it_, IteratorT const &uit_)
0120         :   it(it_), uit(uit_) {}
0121         ~assign() { it = uit; }
0122 
0123     private:
0124         IteratorT &it;
0125         IteratorT const &uit;
0126     };
0127 
0128 ///////////////////////////////////////////////////////////////////////////////
0129 }   // namespace on_exit
0130 
0131 ///////////////////////////////////////////////////////////////////////////////
0132 namespace impl {
0133 
0134 ///////////////////////////////////////////////////////////////////////////////
0135 //
0136 //  Test, whether a given identifier resolves to a predefined name
0137 //
0138 ///////////////////////////////////////////////////////////////////////////////
0139 template <typename ContextT, typename StringT>
0140 inline bool
0141 is_special_macroname (ContextT const & ctx, StringT const &name)
0142 {
0143     if (name.size() < 7)
0144         return false;
0145 
0146     if ("defined" == name)
0147         return true;
0148 
0149 #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0
0150     if (boost::wave::need_has_include(ctx.get_language()) &&
0151         ("__has_include" == name))
0152         return true;
0153 #endif
0154 
0155     if ('_' == name[0] && '_' == name[1]) {
0156         StringT str = name.substr(2);
0157 
0158         if (str == "cplusplus"  || str == "STDC__" ||
0159             str == "TIME__"     || str == "DATE__" ||
0160             str == "LINE__"     || str == "FILE__" ||
0161             str == "INCLUDE_LEVEL__")
0162         {
0163             return true;
0164         }
0165     }
0166     return false;
0167 }
0168 
0169 ///////////////////////////////////////////////////////////////////////////////
0170 //
0171 //  Test, whether two tokens are to be considered equal (different sequences
0172 //  of whitespace are considered to be equal)
0173 //
0174 ///////////////////////////////////////////////////////////////////////////////
0175 template <typename TokenT>
0176 inline bool
0177 token_equals(TokenT const &left, TokenT const &right)
0178 {
0179     using namespace boost::wave;
0180 
0181     if (IS_CATEGORY(left, ParameterTokenType)) {
0182         //  if the existing token is of type T_PARAMETERBASE, then the right token
0183         //  must be of type T_IDENTIFIER or a keyword
0184         token_id id = token_id(right);
0185 
0186         return (T_IDENTIFIER == id ||
0187                 IS_CATEGORY(id, KeywordTokenType) ||
0188                 IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
0189                 IS_CATEGORY(id, BoolLiteralTokenType)) &&
0190             left.get_value() == right.get_value();
0191     }
0192 
0193     // if the left token has whitespace, the value is irrelevant
0194     return token_id(left) == token_id(right) && (
0195             IS_CATEGORY(left, WhiteSpaceTokenType) ||
0196             left.get_value() == right.get_value()
0197         );
0198 }
0199 
0200 ///////////////////////////////////////////////////////////////////////////////
0201 //
0202 //  Tests, whether two macro definitions are equal
0203 //
0204 ///////////////////////////////////////////////////////////////////////////////
0205 template <typename ContainerT>
0206 inline bool
0207 definition_equals(ContainerT const &definition,
0208     ContainerT const &new_definition)
0209 {
0210     typedef typename ContainerT::const_iterator const_iterator_type;
0211 
0212     const_iterator_type first1 = definition.begin();
0213     const_iterator_type last1 = definition.end();
0214     const_iterator_type first2 = new_definition.begin();
0215     const_iterator_type last2 = new_definition.end();
0216 
0217     while (first1 != last1 && first2 != last2 && token_equals(*first1, *first2))
0218     {
0219         // skip whitespace, if both sequences have a whitespace next
0220         token_id id1 = next_token<const_iterator_type>::peek(first1, last1, false);
0221         token_id id2 = next_token<const_iterator_type>::peek(first2, last2, false);
0222 
0223         if (IS_CATEGORY(id1, WhiteSpaceTokenType) &&
0224             IS_CATEGORY(id2, WhiteSpaceTokenType))
0225         {
0226             // all consecutive whitespace tokens count as one whitespace
0227             // adjust first1 and first2 accordingly
0228             skip_whitespace(first1, last1);
0229             skip_whitespace(first2, last2);
0230         }
0231         else if (!IS_CATEGORY(id1, WhiteSpaceTokenType) &&
0232                  !IS_CATEGORY(id2, WhiteSpaceTokenType))
0233         {
0234             ++first1;
0235             ++first2;
0236         }
0237         else {
0238             // the sequences differ
0239             break;
0240         }
0241     }
0242     return (first1 == last1 && first2 == last2) ? true : false;
0243 }
0244 
0245 ///////////////////////////////////////////////////////////////////////////////
0246 //
0247 //  Tests, whether two given sets of macro parameters are equal
0248 //
0249 ///////////////////////////////////////////////////////////////////////////////
0250 template <typename ContainerT>
0251 inline bool
0252 parameters_equal(ContainerT const &parameters, ContainerT const &new_parameters)
0253 {
0254     if (parameters.size() != new_parameters.size())
0255         return false;   // different parameter count
0256 
0257     typedef typename ContainerT::const_iterator const_iterator_type;
0258 
0259     const_iterator_type first1 = parameters.begin();
0260     const_iterator_type last1 = parameters.end();
0261     const_iterator_type first2 = new_parameters.begin();
0262     const_iterator_type last2 = new_parameters.end();
0263 
0264     while (first1 != last1 && first2 != last2) {
0265         // parameters are different, if the corresponding tokens are different
0266         using namespace boost::wave;
0267         if (token_id(*first1) != token_id(*first2) ||
0268             (*first1).get_value() != (*first2).get_value())
0269         {
0270             break;
0271         }
0272         ++first1;
0273         ++first2;
0274     }
0275     return (first1 == last1 && first2 == last2) ? true : false;
0276 }
0277 
0278 ///////////////////////////////////////////////////////////////////////////////
0279 //
0280 //  Strip leading and trailing whitespace from the given token sequence
0281 //
0282 ///////////////////////////////////////////////////////////////////////////////
0283 template <typename ContainerT>
0284 inline void
0285 trim_replacement_list (ContainerT &replacement_list)
0286 {
0287     using namespace boost::wave;
0288 
0289     // strip leading whitespace
0290     if (replacement_list.size() > 0) {
0291         typename ContainerT::iterator end = replacement_list.end();
0292         typename ContainerT::iterator it = replacement_list.begin();
0293 
0294         while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
0295             token_id id(*it);
0296             if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
0297                 typename ContainerT::iterator next = it;
0298                 ++next;
0299                 replacement_list.erase(it);
0300                 it = next;
0301             }
0302             else {
0303                 ++it;
0304             }
0305         }
0306     }
0307 
0308     // strip trailing whitespace
0309     if (replacement_list.size() > 0) {
0310         typename ContainerT::reverse_iterator rend = replacement_list.rend();
0311         typename ContainerT::reverse_iterator rit = replacement_list.rbegin();
0312 
0313         while (rit != rend && IS_CATEGORY(*rit, WhiteSpaceTokenType))
0314             ++rit;
0315 
0316         typename ContainerT::iterator end = replacement_list.end();
0317         typename ContainerT::iterator it = rit.base();
0318 
0319         while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
0320             token_id id(*it);
0321             if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
0322                 typename ContainerT::iterator next = it;
0323                 ++next;
0324                 replacement_list.erase(it);
0325                 it = next;
0326             }
0327             else {
0328                 ++it;
0329             }
0330         }
0331     }
0332 }
0333 
0334 ///////////////////////////////////////////////////////////////////////////////
0335 //
0336 //  Tests, whether the given token sequence consists out of whitespace only
0337 //
0338 ///////////////////////////////////////////////////////////////////////////////
0339 template <typename ContainerT>
0340 inline bool
0341 is_whitespace_only (ContainerT const &argument)
0342 {
0343     typename ContainerT::const_iterator end = argument.end();
0344     for (typename ContainerT::const_iterator it = argument.begin();
0345           it != end; ++it)
0346     {
0347         if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
0348             return false;
0349     }
0350     return true;
0351 }
0352 
0353 ///////////////////////////////////////////////////////////////////////////////
0354 //
0355 //  Tests whether the given token sequence consists only of whitespace
0356 //  and placemarkers
0357 //
0358 ///////////////////////////////////////////////////////////////////////////////
0359 template <typename ContainerT>
0360 inline bool
0361 is_blank_only (ContainerT const &argument)
0362 {
0363     typename ContainerT::const_iterator end = argument.end();
0364     for (typename ContainerT::const_iterator it = argument.begin();
0365           it != end; ++it)
0366     {
0367         if (!IS_CATEGORY(*it, WhiteSpaceTokenType) &&
0368             (T_PLACEMARKER != token_id(*it)))
0369             return false;
0370     }
0371     return true;
0372 }
0373 
0374 ///////////////////////////////////////////////////////////////////////////////
0375 //
0376 //  Remove all placeholder tokens from the given token sequence
0377 //
0378 ///////////////////////////////////////////////////////////////////////////////
0379 template <typename ContainerT>
0380 inline void
0381 remove_placeholders (ContainerT &replacement_list)
0382 {
0383     using namespace boost::wave;
0384 
0385     // strip leading whitespace
0386     if (replacement_list.size() > 0) {
0387         typename ContainerT::iterator end = replacement_list.end();
0388         typename ContainerT::iterator it = replacement_list.begin();
0389 
0390         while (it != end) {
0391             token_id id(*it);
0392             if (T_PLACEHOLDER == id || T_PLACEMARKER == id) {
0393                 typename ContainerT::iterator next = it;
0394                 ++next;
0395                 replacement_list.erase(it);
0396                 it = next;
0397             }
0398             else {
0399                 ++it;
0400             }
0401         }
0402 
0403         // remove all 'new' leading and trailing whitespace
0404         if (is_whitespace_only(replacement_list))
0405             trim_replacement_list(replacement_list);
0406     }
0407 }
0408 
0409 ///////////////////////////////////////////////////////////////////////////////
0410 //
0411 //  Remove all whitespace tokens on the left side of the given token sequence
0412 //
0413 ///////////////////////////////////////////////////////////////////////////////
0414 template <typename ContainerT>
0415 inline void
0416 trim_sequence_left (ContainerT &argument)
0417 {
0418     using namespace boost::wave;
0419 
0420     // strip leading whitespace (should be only one token)
0421     if (argument.size() > 0 &&
0422         IS_CATEGORY(argument.front(), WhiteSpaceTokenType))
0423     {
0424         argument.pop_front();
0425     }
0426 }
0427 
0428 ///////////////////////////////////////////////////////////////////////////////
0429 //
0430 //  Remove all whitespace tokens on the right side of the given token sequence
0431 //
0432 ///////////////////////////////////////////////////////////////////////////////
0433 template <typename ContainerT>
0434 inline void
0435 trim_sequence_right (ContainerT &argument)
0436 {
0437     using namespace boost::wave;
0438 
0439     // strip trailing whitespace (should be only one token)
0440     if (argument.size() > 0 &&
0441         IS_CATEGORY(argument.back(), WhiteSpaceTokenType))
0442     {
0443         argument.pop_back();
0444     }
0445 }
0446 
0447 ///////////////////////////////////////////////////////////////////////////////
0448 //
0449 //  Remove all whitespace tokens on the left and right sides of the given token
0450 //  sequence
0451 //
0452 ///////////////////////////////////////////////////////////////////////////////
0453 template <typename ContainerT>
0454 inline void
0455 trim_sequence (ContainerT &argument)
0456 {
0457     trim_sequence_left(argument);
0458     trim_sequence_right(argument);
0459 }
0460 
0461 ///////////////////////////////////////////////////////////////////////////////
0462 // call 'skipped_token' preprocessing hook
0463 template <typename ContextT>
0464 void call_skipped_token_hook(ContextT& ctx,
0465     typename ContextT::token_type const& skipped)
0466 {
0467     ctx.get_hooks().skipped_token(ctx.derived(), skipped);
0468 }
0469 
0470 ///////////////////////////////////////////////////////////////////////////////
0471 //
0472 //  Skip forward to a given token
0473 //
0474 ///////////////////////////////////////////////////////////////////////////////
0475 template <typename ContextT, typename IteratorT>
0476 inline bool
0477 skip_to_token(ContextT& ctx, IteratorT &it, IteratorT const &end,
0478     token_id id, bool& seen_newline)
0479 {
0480     using namespace boost::wave;
0481     if (token_id(*it) == id)
0482         return true;
0483 
0484 //     call_skipped_token_hook(ctx, *it);
0485     if (++it == end)
0486         return false;
0487 
0488     while (IS_CATEGORY(*it, WhiteSpaceTokenType) ||
0489            T_NEWLINE == token_id(*it))
0490     {
0491         if (T_NEWLINE == token_id(*it))
0492             seen_newline = true;
0493 
0494 //         call_skipped_token_hook(ctx, *it);
0495         if (++it == end)
0496             return false;
0497     }
0498     return token_id(*it) == id;
0499 }
0500 
0501 ///////////////////////////////////////////////////////////////////////////////
0502 //
0503 //  Get the full name of a given macro name (concatenate the string
0504 //  representations of the single tokens).
0505 //
0506 ///////////////////////////////////////////////////////////////////////////////
0507 template <typename IteratorT>
0508 inline std::string
0509 get_full_name(IteratorT const &begin, IteratorT const &end)
0510 {
0511     std::string full_name;
0512     for (IteratorT err_it = begin; err_it != end; ++err_it)
0513         full_name += (*err_it).get_value().c_str();
0514 
0515     return full_name;
0516 }
0517 
0518 ///////////////////////////////////////////////////////////////////////////////
0519 //
0520 //  The following predicate is used in conjunction with the remove_copy_if
0521 //  algorithm to allow the detection of an eventually copied operator ##.
0522 //  No removal is performed in any case.
0523 //
0524 ///////////////////////////////////////////////////////////////////////////////
0525 class find_concat_operator {
0526 public:
0527     find_concat_operator(bool &found_) : found_concat(found_) {}
0528 
0529     template <typename TokenT>
0530     bool operator()(TokenT const &tok)
0531     {
0532         using namespace boost::wave;
0533         if (T_POUND_POUND == BASE_TOKEN(token_id(tok)))
0534             found_concat = true;
0535         return false;
0536     }
0537 
0538 private:
0539     bool &found_concat;
0540 };
0541 
0542 ///////////////////////////////////////////////////////////////////////////////
0543 //  Convert a string of an arbitrary string compatible type to a internal
0544 //  string (BOOST_WAVE_STRING)
0545 template <typename Target, typename Src>
0546 struct to_string_helper
0547 {
0548     typedef Target type;
0549 
0550     static Target call(Src const& str)
0551     {
0552         return Target(str.c_str());
0553     }
0554 };
0555 
0556 // do nothing if types are equal
0557 template <typename Src>
0558 struct to_string_helper<Src, Src>
0559 {
0560     typedef Src const& type;
0561 
0562     static Src const& call(Src const& str)
0563     {
0564         return str;
0565     }
0566 };
0567 
0568 template <typename Target>
0569 struct to_string_helper<Target, char const*>
0570 {
0571     typedef Target type;
0572 
0573     static Target call(char const* str)
0574     {
0575         return Target(str);
0576     }
0577 };
0578 
0579 ///////////////////////////////////////////////////////////////////////////////
0580 }   // namespace impl
0581 
0582 template <typename Target, typename Src>
0583 inline typename impl::to_string_helper<Target, Src>::type
0584 to_string(Src const& src)
0585 {
0586     return impl::to_string_helper<Target, Src>::call(src);
0587 }
0588 
0589 ///////////////////////////////////////////////////////////////////////////////
0590 }   // namespace util
0591 }   // namespace wave
0592 }   // namespace boost
0593 
0594 // the suffix header occurs after all of the code
0595 #ifdef BOOST_HAS_ABI_HEADERS
0596 #include BOOST_ABI_SUFFIX
0597 #endif
0598 
0599 #endif // !defined(BOOST_CPP_MACROMAP_UTIL_HPP_HK041119)