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     Macro expansion engine
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_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED)
0014 #define BOOST_CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED
0015 
0016 #include <cstdlib>
0017 #include <ctime>
0018 
0019 #include <list>
0020 #include <map>
0021 #include <set>
0022 #include <vector>
0023 #include <iterator>
0024 #include <algorithm>
0025 #include <string>
0026 
0027 #include <boost/assert.hpp>
0028 #include <boost/wave/wave_config.hpp>
0029 #if BOOST_WAVE_SERIALIZATION != 0
0030 #include <boost/serialization/serialization.hpp>
0031 #include <boost/serialization/shared_ptr.hpp>
0032 #endif
0033 
0034 #include <boost/filesystem/path.hpp>
0035 #include <boost/lexical_cast.hpp>
0036 #include <boost/optional.hpp>
0037 
0038 #include <boost/wave/util/time_conversion_helper.hpp>
0039 #include <boost/wave/util/unput_queue_iterator.hpp>
0040 #include <boost/wave/util/macro_helpers.hpp>
0041 #include <boost/wave/util/macro_definition.hpp>
0042 #include <boost/wave/util/symbol_table.hpp>
0043 #include <boost/wave/util/cpp_macromap_utils.hpp>
0044 #include <boost/wave/util/cpp_macromap_predef.hpp>
0045 #include <boost/wave/util/filesystem_compatibility.hpp>
0046 #include <boost/wave/grammars/cpp_defined_grammar_gen.hpp>
0047 #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0
0048 #include <boost/wave/grammars/cpp_has_include_grammar_gen.hpp>
0049 #endif
0050 
0051 #include <boost/wave/wave_version.hpp>
0052 #include <boost/wave/cpp_exceptions.hpp>
0053 #include <boost/wave/language_support.hpp>
0054 
0055 // this must occur after all of the includes and before any code appears
0056 #ifdef BOOST_HAS_ABI_HEADERS
0057 #include BOOST_ABI_PREFIX
0058 #endif
0059 
0060 ///////////////////////////////////////////////////////////////////////////////
0061 namespace boost { namespace wave { namespace util {
0062 
0063 ///////////////////////////////////////////////////////////////////////////////
0064 //
0065 //  macromap
0066 //
0067 //      This class holds all currently defined macros and on demand expands
0068 //      those macro definitions
0069 //
0070 ///////////////////////////////////////////////////////////////////////////////
0071 template <typename ContextT>
0072 class macromap {
0073 
0074     typedef macromap<ContextT>                      self_type;
0075     typedef typename ContextT::token_type           token_type;
0076     typedef typename token_type::string_type        string_type;
0077     typedef typename token_type::position_type      position_type;
0078 
0079     typedef typename ContextT::token_sequence_type  definition_container_type;
0080     typedef std::vector<token_type>                 parameter_container_type;
0081 
0082     typedef macro_definition<token_type, definition_container_type>
0083         macro_definition_type;
0084     typedef symbol_table<string_type, macro_definition_type>
0085         defined_macros_type;
0086     typedef typename defined_macros_type::value_type::second_type
0087         macro_ref_type;
0088 
0089 public:
0090     macromap(ContextT &ctx_)
0091     :   current_macros(0), defined_macros(new defined_macros_type(1)),
0092         main_pos("", 0), ctx(ctx_), macro_uid(1)
0093     {
0094         current_macros = defined_macros.get();
0095     }
0096     ~macromap() {}
0097 
0098     //  Add a new macro to the given macro scope
0099     bool add_macro(token_type const &name, bool has_parameters,
0100         parameter_container_type &parameters,
0101         definition_container_type &definition, bool is_predefined = false,
0102         defined_macros_type *scope = 0);
0103 
0104     //  Tests, whether the given macro name is defined in the given macro scope
0105     bool is_defined(string_type const &name,
0106         typename defined_macros_type::iterator &it,
0107         defined_macros_type *scope = 0) const;
0108 
0109     // expects a token sequence as its parameters
0110     template <typename IteratorT>
0111     bool is_defined(IteratorT const &begin, IteratorT const &end) const;
0112 
0113     // expects an arbitrary string as its parameter
0114     bool is_defined(string_type const &str) const;
0115 
0116 #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0
0117     // expects a token sequence as its parameters
0118     template <typename IteratorT>
0119     bool has_include(IteratorT const &begin, IteratorT const &end,
0120                      bool is_quoted_filename, bool is_system) const;
0121 #endif
0122 
0123     //  Get the macro definition for the given macro scope
0124     bool get_macro(string_type const &name, bool &has_parameters,
0125         bool &is_predefined, position_type &pos,
0126         parameter_container_type &parameters,
0127         definition_container_type &definition,
0128         defined_macros_type *scope = 0) const;
0129 
0130     //  Remove a macro name from the given macro scope
0131     bool remove_macro(string_type const &name, position_type const& pos,
0132         bool even_predefined = false);
0133 
0134     template <typename IteratorT, typename ContainerT>
0135     token_type const &expand_tokensequence(IteratorT &first,
0136         IteratorT const &last, ContainerT &pending, ContainerT &expanded,
0137         bool& seen_newline, bool expand_operator_defined,
0138         bool expand_operator_has_include);
0139 
0140     //  Expand all macros inside the given token sequence
0141     template <typename IteratorT, typename ContainerT>
0142     void expand_whole_tokensequence(ContainerT &expanded,
0143         IteratorT &first, IteratorT const &last,
0144         bool expand_operator_defined,
0145         bool expand_operator_has_include);
0146 
0147     //  Init the predefined macros (add them to the given scope)
0148     void init_predefined_macros(char const *fname = "<Unknown>",
0149         defined_macros_type *scope = 0, bool at_global_scope = true);
0150     void predefine_macro(defined_macros_type *scope, string_type const &name,
0151         token_type const &t);
0152 
0153     //  Init the internal macro symbol namespace
0154     void reset_macromap();
0155 
0156     position_type &get_main_pos() { return main_pos; }
0157     position_type const& get_main_pos() const { return main_pos; }
0158 
0159     //  interface for macro name introspection
0160     typedef typename defined_macros_type::name_iterator name_iterator;
0161     typedef typename defined_macros_type::const_name_iterator const_name_iterator;
0162 
0163     name_iterator begin()
0164         { return defined_macros_type::make_iterator(current_macros->begin()); }
0165     name_iterator end()
0166         { return defined_macros_type::make_iterator(current_macros->end()); }
0167     const_name_iterator begin() const
0168         { return defined_macros_type::make_iterator(current_macros->begin()); }
0169     const_name_iterator end() const
0170         { return defined_macros_type::make_iterator(current_macros->end()); }
0171 
0172 protected:
0173     //  Helper functions for expanding all macros in token sequences
0174     template <typename IteratorT, typename ContainerT>
0175     token_type const &expand_tokensequence_worker(ContainerT &pending,
0176         unput_queue_iterator<IteratorT, token_type, ContainerT> &first,
0177         unput_queue_iterator<IteratorT, token_type, ContainerT> const &last,
0178         bool& seen_newline, bool expand_operator_defined,
0179         bool expand_operator_has_include,
0180         boost::optional<position_type> expanding_pos);
0181 
0182 //  Collect all arguments supplied to a macro invocation
0183     template <typename IteratorT, typename ContainerT, typename SizeT>
0184     typename std::vector<ContainerT>::size_type collect_arguments (
0185         token_type const curr_token, std::vector<ContainerT> &arguments,
0186         IteratorT &next, IteratorT &endparen, IteratorT const &end,
0187         SizeT const &parameter_count, bool& seen_newline);
0188 
0189     //  Expand a single macro name
0190     template <typename IteratorT, typename ContainerT>
0191     bool expand_macro(ContainerT &pending, token_type const &name,
0192         typename defined_macros_type::iterator it,
0193         IteratorT &first, IteratorT const &last,
0194         bool& seen_newline, bool expand_operator_defined,
0195         bool expand_operator_has_include,
0196         boost::optional<position_type> expanding_pos,
0197         defined_macros_type *scope = 0, ContainerT *queue_symbol = 0);
0198 
0199     //  Expand a predefined macro (__LINE__, __FILE__ and __INCLUDE_LEVEL__)
0200     template <typename ContainerT>
0201     bool expand_predefined_macro(token_type const &curr_token,
0202         ContainerT &expanded);
0203 
0204     //  Expand a single macro argument
0205     template <typename ContainerT>
0206     void expand_argument (typename std::vector<ContainerT>::size_type arg,
0207         std::vector<ContainerT> &arguments,
0208         std::vector<ContainerT> &expanded_args, bool expand_operator_defined,
0209         bool expand_operator_has_include,
0210         std::vector<bool> &has_expanded_args);
0211 
0212     //  Expand the replacement list (replaces parameters with arguments)
0213     template <typename ContainerT>
0214     void expand_replacement_list(
0215         typename macro_definition_type::const_definition_iterator_t cbeg,
0216         typename macro_definition_type::const_definition_iterator_t cend,
0217         std::vector<ContainerT> &arguments,
0218         bool expand_operator_defined,
0219         bool expand_operator_has_include,
0220         ContainerT &expanded);
0221 
0222     //  Rescans the replacement list for macro expansion
0223     template <typename IteratorT, typename ContainerT>
0224     void rescan_replacement_list(token_type const &curr_token,
0225         macro_definition_type &macrodef, ContainerT &replacement_list,
0226         ContainerT &expanded, bool expand_operator_defined,
0227         bool expand_operator_has_include,
0228         IteratorT &nfirst, IteratorT const &nlast);
0229 
0230     //  Resolves the operator defined() and replaces the token with "0" or "1"
0231     template <typename IteratorT, typename ContainerT>
0232     token_type const &resolve_defined(IteratorT &first, IteratorT const &last,
0233         ContainerT &expanded);
0234 
0235 #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0
0236     //  Resolves the operator __has_include() and replaces the token with "0" or "1"
0237     template <typename IteratorT, typename ContainerT>
0238     token_type const &resolve_has_include(IteratorT &first, IteratorT const &last,
0239         ContainerT &expanded);
0240 #endif
0241 
0242     //  Resolve operator _Pragma or the #pragma directive
0243     template <typename IteratorT, typename ContainerT>
0244     bool resolve_operator_pragma(IteratorT &first,
0245         IteratorT const &last, ContainerT &expanded, bool& seen_newline);
0246 
0247     //  Handle the concatenation operator '##'
0248     template <typename ContainerT>
0249     bool concat_tokensequence(ContainerT &expanded);
0250 
0251     template <typename ContainerT>
0252     bool is_valid_concat(string_type new_value,
0253         position_type const &pos, ContainerT &rescanned);
0254 
0255     static bool is_space(char);
0256 
0257     // batch update tokens with a single expand position
0258     template <typename ContainerT>
0259     static void set_expand_positions(ContainerT &tokens, position_type pos);
0260 
0261 #if BOOST_WAVE_SERIALIZATION != 0
0262 public:
0263     BOOST_STATIC_CONSTANT(unsigned int, version = 0x10);
0264     BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f);
0265 
0266 private:
0267     friend class boost::serialization::access;
0268     template<typename Archive>
0269     void save(Archive &ar, const unsigned int version) const
0270     {
0271         using namespace boost::serialization;
0272         ar & make_nvp("defined_macros", defined_macros);
0273     }
0274     template<typename Archive>
0275     void load(Archive &ar, const unsigned int loaded_version)
0276     {
0277         using namespace boost::serialization;
0278         if (version != (loaded_version & ~version_mask)) {
0279             BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
0280                 "cpp_context state version", get_main_pos());
0281         }
0282         ar & make_nvp("defined_macros", defined_macros);
0283         current_macros = defined_macros.get();
0284     }
0285     BOOST_SERIALIZATION_SPLIT_MEMBER()
0286 #endif
0287 
0288 private:
0289     defined_macros_type *current_macros;                   // current symbol table
0290     boost::shared_ptr<defined_macros_type> defined_macros; // global symbol table
0291 
0292     token_type act_token;       // current token
0293     position_type main_pos;     // last token position in the pp_iterator
0294     string_type base_name;      // the name to be expanded by __BASE_FILE__
0295     ContextT &ctx;              // context object associated with the macromap
0296     long macro_uid;
0297     predefined_macros predef;   // predefined macro support
0298 };
0299 ///////////////////////////////////////////////////////////////////////////////
0300 
0301 ///////////////////////////////////////////////////////////////////////////////
0302 //
0303 //  add_macro(): adds a new macro to the macromap
0304 //
0305 ///////////////////////////////////////////////////////////////////////////////
0306 template <typename ContextT>
0307 inline bool
0308 macromap<ContextT>::add_macro(token_type const &name, bool has_parameters,
0309     parameter_container_type &parameters, definition_container_type &definition,
0310     bool is_predefined, defined_macros_type *scope)
0311 {
0312     if (!is_predefined && impl::is_special_macroname (ctx, name.get_value())) {
0313         // exclude special macro names
0314         BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
0315             illegal_redefinition, name.get_value().c_str(), main_pos,
0316             name.get_value().c_str());
0317         return false;
0318     }
0319     if (boost::wave::need_variadics(ctx.get_language()) &&
0320         "__VA_ARGS__" == name.get_value())
0321     {
0322         // can't use __VA_ARGS__ as a macro name
0323         BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
0324             bad_define_statement_va_args, name.get_value().c_str(), main_pos,
0325             name.get_value().c_str());
0326         return false;
0327     }
0328     if (boost::wave::need_variadics(ctx.get_language()) &&
0329         "__VA_OPT__" == name.get_value())
0330     {
0331         // can't use __VA_OPT__ as a macro name
0332         BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
0333             bad_define_statement_va_opt, name.get_value().c_str(), main_pos,
0334             name.get_value().c_str());
0335         return false;
0336     }
0337 #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0
0338     if (boost::wave::need_has_include(ctx.get_language()) &&
0339         "__has_include" == name.get_value())
0340     {
0341         // can't use __has_include as a macro name
0342         BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
0343             bad_define_statement_va_opt, name.get_value().c_str(), main_pos,
0344             name.get_value().c_str());
0345         return false;
0346     }
0347 #endif
0348     if (AltExtTokenType == (token_id(name) & ExtTokenOnlyMask)) {
0349         // exclude special operator names
0350         BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
0351             illegal_operator_redefinition, name.get_value().c_str(), main_pos,
0352             name.get_value().c_str());
0353         return false;
0354     }
0355 
0356     // try to define the new macro
0357     defined_macros_type* current_scope = scope ? scope : current_macros;
0358     typename defined_macros_type::iterator it = current_scope->find(name.get_value());
0359 
0360     if (it != current_scope->end()) {
0361         // redefinition, should not be different
0362         macro_definition_type* macrodef = (*it).second.get();
0363         if (macrodef->is_functionlike != has_parameters ||
0364             !impl::parameters_equal(macrodef->macroparameters, parameters) ||
0365             !impl::definition_equals(macrodef->macrodefinition, definition))
0366         {
0367             BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
0368                 macro_redefinition, name.get_value().c_str(), main_pos,
0369                 name.get_value().c_str());
0370         }
0371         return false;
0372     }
0373 
0374     // test the validity of the parameter names
0375     if (has_parameters) {
0376         std::set<typename token_type::string_type> names;
0377 
0378         typedef typename parameter_container_type::iterator
0379             parameter_iterator_type;
0380         typedef typename std::set<typename token_type::string_type>::iterator
0381             name_iterator_type;
0382 
0383         parameter_iterator_type end = parameters.end();
0384         for (parameter_iterator_type itp = parameters.begin(); itp != end; ++itp)
0385         {
0386         name_iterator_type pit = names.find((*itp).get_value());
0387 
0388             if (pit != names.end()) {
0389                 // duplicate parameter name
0390                 BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
0391                     duplicate_parameter_name, (*pit).c_str(), main_pos,
0392                     name.get_value().c_str());
0393                 return false;
0394             }
0395             names.insert((*itp).get_value());
0396         }
0397     }
0398 
0399 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
0400     // check that __VA_OPT__ is used as a function macro
0401     if (boost::wave::need_va_opt(ctx.get_language())) {
0402         // __VA_OPT__, if present, must be followed by an lparen
0403         typedef typename macro_definition_type::const_definition_iterator_t iter_t;
0404         iter_t mdit = definition.begin();
0405         iter_t mdend = definition.end();
0406         for (; mdit != mdend; ++mdit) {
0407             // is this va_opt?
0408             if ((IS_EXTCATEGORY((*mdit), OptParameterTokenType)) ||  // if params replaced
0409                 ("__VA_OPT__" == (*mdit).get_value())) {             // if not
0410                 iter_t va_opt_it = mdit;
0411                 // next must be lparen
0412                 if ((++mdit == mdend) ||                             // no further tokens
0413                     (T_LEFTPAREN != token_id(*mdit))) {              // not lparen
0414                     BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
0415                         bad_define_statement_va_opt_parens,
0416                         name.get_value().c_str(), main_pos,
0417                         name.get_value().c_str());
0418                     return false;
0419                 }
0420                 // check that no __VA_OPT__ appears inside
0421                 iter_t va_opt_end = va_opt_it;
0422                 if (!impl::find_va_opt_args(va_opt_end, mdend)) {
0423                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
0424                         improperly_terminated_macro, "missing ')' in __VA_OPT__",
0425                         main_pos);
0426                     return false;
0427                 }
0428                 // skip initial __VA_OPT__ and lparen
0429                 ++va_opt_it; ++va_opt_it;
0430                 for (;va_opt_it != va_opt_end; ++va_opt_it) {
0431                     if ((IS_EXTCATEGORY((*va_opt_it), OptParameterTokenType)) ||
0432                         ("__VA_OPT__" == (*va_opt_it).get_value())) {
0433                         BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
0434                             bad_define_statement_va_opt_recurse,
0435                             name.get_value().c_str(), (*va_opt_it).get_position(),
0436                             name.get_value().c_str());
0437                     }
0438                 }
0439             }
0440         }
0441     }
0442 #endif
0443 
0444     // insert a new macro node
0445     std::pair<typename defined_macros_type::iterator, bool> p =
0446         current_scope->insert(
0447             typename defined_macros_type::value_type(
0448                 name.get_value(),
0449                 macro_ref_type(new macro_definition_type(name,
0450                     has_parameters, is_predefined, ++macro_uid)
0451                 )
0452             )
0453         );
0454 
0455     if (!p.second) {
0456         BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
0457             macro_insertion_error, name.get_value().c_str(), main_pos,
0458             name.get_value().c_str());
0459         return false;
0460     }
0461 
0462     // add the parameters and the definition
0463     std::swap((*p.first).second->macroparameters, parameters);
0464     std::swap((*p.first).second->macrodefinition, definition);
0465 
0466 // call the context supplied preprocessing hook
0467     ctx.get_hooks().defined_macro(ctx.derived(), name, has_parameters,
0468         (*p.first).second->macroparameters,
0469         (*p.first).second->macrodefinition, is_predefined);
0470     return true;
0471 }
0472 
0473 ///////////////////////////////////////////////////////////////////////////////
0474 //
0475 //  is_defined(): returns, whether a given macro is already defined
0476 //
0477 ///////////////////////////////////////////////////////////////////////////////
0478 template <typename ContextT>
0479 inline bool
0480 macromap<ContextT>::is_defined(typename token_type::string_type const &name,
0481     typename defined_macros_type::iterator &it,
0482     defined_macros_type *scope) const
0483 {
0484     if (0 == scope) scope = current_macros;
0485 
0486     if ((it = scope->find(name)) != scope->end())
0487         return true;        // found in symbol table
0488 
0489     // quick pre-check
0490     if (name.size() < 8 || '_' != name[0] || '_' != name[1])
0491         return false;       // quick check failed
0492 
0493     if (name == "__LINE__" || name == "__FILE__" ||
0494         name == "__INCLUDE_LEVEL__")
0495         return true;
0496 
0497 #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0
0498     return (boost::wave::need_has_include(ctx.get_language()) &&
0499             (name == "__has_include"));
0500 #else
0501     return false;
0502 #endif
0503 }
0504 
0505 template <typename ContextT>
0506 template <typename IteratorT>
0507 inline bool
0508 macromap<ContextT>::is_defined(IteratorT const &begin,
0509     IteratorT const &end) const
0510 {
0511     // in normal mode the name under inspection should consist of an identifier
0512     // only
0513     token_id id = token_id(*begin);
0514 
0515     if (T_IDENTIFIER != id &&
0516         !IS_CATEGORY(id, KeywordTokenType) &&
0517         !IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) &&
0518         !IS_CATEGORY(id, BoolLiteralTokenType))
0519     {
0520         std::string msg(impl::get_full_name(begin, end));
0521         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_macroname,
0522             msg.c_str(), main_pos);
0523         return false;
0524     }
0525 
0526     IteratorT it = begin;
0527     string_type name((*it).get_value());
0528     typename defined_macros_type::iterator cit;
0529 
0530     if (++it != end) {
0531         // there should be only one token as the inspected name
0532         std::string msg(impl::get_full_name(begin, end));
0533         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_macroname,
0534             msg.c_str(), main_pos);
0535         return false;
0536     }
0537     return is_defined(name, cit, 0);
0538 }
0539 
0540 ///////////////////////////////////////////////////////////////////////////////
0541 //  same as above, only takes an arbitrary string type as its parameter
0542 template <typename ContextT>
0543 inline bool
0544 macromap<ContextT>::is_defined(string_type const &str) const
0545 {
0546     typename defined_macros_type::iterator cit;
0547     return is_defined(str, cit, 0);
0548 }
0549 
0550 #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0
0551 ///////////////////////////////////////////////////////////////////////////////
0552 //
0553 //  has_include(): returns whether a path expression is an valid include file
0554 //
0555 ///////////////////////////////////////////////////////////////////////////////
0556 template <typename ContextT>
0557 template <typename IteratorT>
0558 inline bool
0559 macromap<ContextT>::has_include(
0560     IteratorT const &begin, IteratorT const &end,
0561     bool is_quoted_filename, bool is_system) const
0562 {
0563     typename ContextT::token_sequence_type filetoks;
0564 
0565     if (is_quoted_filename) {
0566         filetoks = typename ContextT::token_sequence_type(begin, end);
0567     } else {
0568         IteratorT first = begin;
0569         IteratorT last = end;
0570         ctx.expand_whole_tokensequence(first, last, filetoks);
0571     }
0572 
0573     // extract tokens into string and trim whitespace
0574     using namespace boost::wave::util::impl;
0575     std::string fn(trim_whitespace(as_string(filetoks)).c_str());
0576 
0577     // verify and remove initial and final delimiters
0578     if (!((fn.size() >= 3) &&
0579           (((fn[0] == '"') && (*fn.rbegin() == '"')) ||
0580            ((fn[0] == '<') && (*fn.rbegin() == '>')))))
0581         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_has_include_expression,
0582                              fn.c_str(), ctx.get_main_pos());
0583 
0584     fn = fn.substr(1, fn.size() - 2);
0585 
0586     // test header existence
0587     std::string dir_path;
0588     std::string native_path;
0589     return ctx.get_hooks().locate_include_file(
0590         ctx, fn, is_system, 0, dir_path, native_path);
0591 
0592 }
0593 #endif
0594 
0595 ///////////////////////////////////////////////////////////////////////////////
0596 //
0597 //  Get the macro definition for the given macro scope
0598 //
0599 ///////////////////////////////////////////////////////////////////////////////
0600 template <typename ContextT>
0601 inline bool
0602 macromap<ContextT>::get_macro(string_type const &name, bool &has_parameters,
0603     bool &is_predefined, position_type &pos,
0604     parameter_container_type &parameters,
0605     definition_container_type &definition,
0606     defined_macros_type *scope) const
0607 {
0608     typename defined_macros_type::iterator it;
0609     if (!is_defined(name, it, scope))
0610         return false;
0611 
0612     macro_definition_type& macro_def = *(*it).second.get();
0613 
0614     has_parameters = macro_def.is_functionlike;
0615     is_predefined = macro_def.is_predefined;
0616     pos = macro_def.macroname.get_position();
0617     parameters = macro_def.macroparameters;
0618     definition = macro_def.macrodefinition;
0619     return true;
0620 }
0621 
0622 ///////////////////////////////////////////////////////////////////////////////
0623 //
0624 //  remove_macro(): remove a macro from the macromap
0625 //
0626 ///////////////////////////////////////////////////////////////////////////////
0627 template <typename ContextT>
0628 inline bool
0629 macromap<ContextT>::remove_macro(string_type const &name,
0630     position_type const& pos, bool even_predefined)
0631 {
0632     typename defined_macros_type::iterator it = current_macros->find(name);
0633 
0634     if (it != current_macros->end()) {
0635         if ((*it).second->is_predefined) {
0636             if (!even_predefined || impl::is_special_macroname(ctx, name)) {
0637                 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
0638                     bad_undefine_statement, name.c_str(), main_pos);
0639                 return false;
0640             }
0641         }
0642         current_macros->erase(it);
0643 
0644         // call the context supplied preprocessing hook function
0645         token_type tok(T_IDENTIFIER, name, pos);
0646 
0647         ctx.get_hooks().undefined_macro(ctx.derived(), tok);
0648         return true;
0649     }
0650     else if (impl::is_special_macroname(ctx, name)) {
0651         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_undefine_statement,
0652             name.c_str(), pos);
0653     }
0654     return false;       // macro was not defined
0655 }
0656 
0657 ///////////////////////////////////////////////////////////////////////////////
0658 //
0659 //  expand_tokensequence
0660 //
0661 //      This function is a helper function which wraps the given iterator
0662 //      range into corresponding unput_iterator's and calls the main workhorse
0663 //      of the macro expansion engine (the function expand_tokensequence_worker)
0664 //
0665 //      This is the top level macro expansion function called from the
0666 //      preprocessing iterator component only.
0667 //
0668 ///////////////////////////////////////////////////////////////////////////////
0669 template <typename ContextT>
0670 template <typename IteratorT, typename ContainerT>
0671 inline typename ContextT::token_type const &
0672 macromap<ContextT>::expand_tokensequence(IteratorT &first,
0673     IteratorT const &last, ContainerT &pending, ContainerT &expanded,
0674     bool& seen_newline, bool expand_operator_defined,
0675     bool expand_operator_has_include)
0676 {
0677     typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT>
0678         gen_type;
0679     typedef typename gen_type::return_type iterator_type;
0680 
0681     iterator_type first_it = gen_type::generate(expanded, first);
0682     iterator_type last_it = gen_type::generate(last);
0683 
0684     on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
0685 
0686     return expand_tokensequence_worker(pending, first_it, last_it,
0687         seen_newline, expand_operator_defined, expand_operator_has_include,
0688         boost::none);
0689 }
0690 
0691 ///////////////////////////////////////////////////////////////////////////////
0692 //
0693 //  expand_tokensequence_worker
0694 //
0695 //      This function is the main workhorse of the macro expansion engine. It
0696 //      expands as much tokens as needed to identify the next preprocessed
0697 //      token to return to the caller.
0698 //      It returns the next preprocessed token.
0699 //
0700 //      The iterator 'first' is adjusted accordingly.
0701 //
0702 ///////////////////////////////////////////////////////////////////////////////
0703 template <typename ContextT>
0704 template <typename IteratorT, typename ContainerT>
0705 inline typename ContextT::token_type const &
0706 macromap<ContextT>::expand_tokensequence_worker(
0707     ContainerT &pending,
0708     unput_queue_iterator<IteratorT, token_type, ContainerT> &first,
0709     unput_queue_iterator<IteratorT, token_type, ContainerT> const &last,
0710     bool& seen_newline, bool expand_operator_defined,
0711     bool expand_operator_has_include,
0712     boost::optional<position_type> expanding_pos)
0713 {
0714     // if there exist pending tokens (tokens, which are already preprocessed), then
0715     // return the next one from there
0716     if (!pending.empty()) {
0717         on_exit::pop_front<definition_container_type> pop_front_token(pending);
0718 
0719         return act_token = pending.front();
0720     }
0721 
0722     //  analyze the next element of the given sequence, if it is an
0723     //  T_IDENTIFIER token, try to replace this as a macro etc.
0724     using namespace boost::wave;
0725 
0726     if (first != last) {
0727         token_id id = token_id(*first);
0728 
0729         // ignore placeholder tokens
0730         if (T_PLACEHOLDER == id) {
0731             token_type placeholder = *first;
0732 
0733             ++first;
0734             if (first == last)
0735                 return act_token = placeholder;
0736             id = token_id(*first);
0737         }
0738 
0739         if (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType) ||
0740             IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
0741             IS_CATEGORY(id, BoolLiteralTokenType))
0742         {
0743         // try to replace this identifier as a macro
0744             if (expand_operator_defined && (*first).get_value() == "defined") {
0745             // resolve operator defined()
0746                 return resolve_defined(first, last, pending);
0747             }
0748 #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0
0749             else if (boost::wave::need_has_include(ctx.get_language()) &&
0750                      expand_operator_has_include &&
0751                      (*first).get_value() == "__has_include") {
0752                 // resolve operator __has_include()
0753                 return resolve_has_include(first, last, pending);
0754             }
0755 #endif
0756             else if (boost::wave::need_variadics(ctx.get_language()) &&
0757                 (*first).get_value() == "_Pragma")
0758             {
0759                 // in C99 mode only: resolve the operator _Pragma
0760                 token_type curr_token = *first;
0761 
0762                 if (!resolve_operator_pragma(first, last, pending, seen_newline) ||
0763                     pending.size() > 0)
0764                 {
0765                     // unknown to us pragma or supplied replacement, return the
0766                     // next token
0767                     on_exit::pop_front<definition_container_type> pop_token(pending);
0768 
0769                     return act_token = pending.front();
0770                 }
0771 
0772                 // the operator _Pragma() was eaten completely, continue
0773                 return act_token = token_type(T_PLACEHOLDER, "_",
0774                     curr_token.get_position());
0775             }
0776 
0777             token_type name_token(*first);
0778             typename defined_macros_type::iterator it;
0779 
0780             if (is_defined(name_token.get_value(), it)) {
0781                 // the current token contains an identifier, which is currently
0782                 // defined as a macro
0783                 if (expand_macro(pending, name_token, it, first, last,
0784                                  seen_newline, expand_operator_defined,
0785                                  expand_operator_has_include,
0786                                  expanding_pos))
0787                 {
0788                     // the tokens returned by expand_macro should be rescanned
0789                     // beginning at the last token of the returned replacement list
0790                     if (first != last) {
0791                         // splice the last token back into the input queue
0792                         typename ContainerT::reverse_iterator rit = pending.rbegin();
0793 
0794                         first.get_unput_queue().splice(
0795                             first.get_unput_queue().begin(), pending,
0796                             (++rit).base(), pending.end());
0797                     }
0798 
0799                     // fall through ...
0800                 }
0801                 else if (!pending.empty()) {
0802                     // return the first token from the pending queue
0803                     on_exit::pop_front<definition_container_type> pop_queue(pending);
0804 
0805                     return act_token = pending.front();
0806                 }
0807                 else {
0808                     // macro expansion reached the eoi
0809                     return act_token = token_type();
0810                 }
0811 
0812                 // return the next preprocessed token
0813                 if (!expanding_pos)
0814                     expanding_pos = name_token.get_expand_position();
0815 
0816                 typename ContextT::token_type const & result =
0817                     expand_tokensequence_worker(
0818                         pending, first, last,
0819                         seen_newline, expand_operator_defined,
0820                         expand_operator_has_include,
0821                         expanding_pos);
0822 
0823                 return result;
0824             }
0825             else {
0826                 act_token = name_token;
0827                 ++first;
0828                 return act_token;
0829             }
0830         }
0831         else if (expand_operator_defined && IS_CATEGORY(*first, BoolLiteralTokenType)) {
0832             // expanding a constant expression inside #if/#elif, special handling
0833             // of 'true' and 'false'
0834 
0835             // all remaining identifiers and keywords, except for true and false,
0836             // are replaced with the pp-number 0 (C++ standard 16.1.4, [cpp.cond])
0837             return act_token = token_type(T_INTLIT, T_TRUE != id ? "0" : "1",
0838                 (*first++).get_position());
0839         }
0840         else {
0841             act_token = *first;
0842             ++first;
0843             return act_token;
0844         }
0845     }
0846     return act_token = token_type();     // eoi
0847 }
0848 
0849 ///////////////////////////////////////////////////////////////////////////////
0850 //
0851 //  collect_arguments(): collect the actual arguments of a macro invocation
0852 //
0853 //      return the number of successfully detected non-empty arguments
0854 //
0855 ///////////////////////////////////////////////////////////////////////////////
0856 template <typename ContextT>
0857 template <typename IteratorT, typename ContainerT, typename SizeT>
0858 inline typename std::vector<ContainerT>::size_type
0859 macromap<ContextT>::collect_arguments (token_type const curr_token,
0860     std::vector<ContainerT> &arguments, IteratorT &next, IteratorT &endparen,
0861     IteratorT const &end, SizeT const &parameter_count, bool& seen_newline)
0862 {
0863     using namespace boost::wave;
0864 
0865     arguments.push_back(ContainerT());
0866 
0867     // collect the actual arguments
0868     typename std::vector<ContainerT>::size_type count_arguments = 0;
0869     int nested_parenthesis_level = 1;
0870     ContainerT* argument = &arguments[0];
0871     bool was_whitespace = false;
0872     token_type startof_argument_list = *next;
0873 
0874     while (++next != end && nested_parenthesis_level) {
0875         token_id id = token_id(*next);
0876 
0877         if (0 == parameter_count &&
0878             !IS_CATEGORY((*next), WhiteSpaceTokenType) && id != T_NEWLINE &&
0879             id != T_RIGHTPAREN && id != T_LEFTPAREN)
0880         {
0881         // there shouldn't be any arguments
0882             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
0883                 too_many_macroarguments, curr_token.get_value().c_str(),
0884                 main_pos);
0885             return 0;
0886         }
0887 
0888         switch (id) {
0889         case T_LEFTPAREN:
0890             ++nested_parenthesis_level;
0891             argument->push_back(*next);
0892             was_whitespace = false;
0893             break;
0894 
0895         case T_RIGHTPAREN:
0896             {
0897                 if (--nested_parenthesis_level >= 1)
0898                     argument->push_back(*next);
0899                 else {
0900                 // found closing parenthesis
0901 //                    trim_sequence(argument);
0902                     endparen = next;
0903                     if (parameter_count > 0) {
0904                         if (argument->empty() ||
0905                             impl::is_whitespace_only(*argument))
0906                         {
0907 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
0908                             if (boost::wave::need_variadics(ctx.get_language())) {
0909                             // store a placemarker as the argument
0910                                 argument->push_back(token_type(T_PLACEMARKER, "\xA7",
0911                                     (*next).get_position()));
0912                                 ++count_arguments;
0913                             }
0914 #endif
0915                         }
0916                         else {
0917                             ++count_arguments;
0918                         }
0919                     }
0920                 }
0921                 was_whitespace = false;
0922             }
0923             break;
0924 
0925         case T_COMMA:
0926             if (1 == nested_parenthesis_level) {
0927                 // next parameter
0928 //                trim_sequence(argument);
0929                 if (argument->empty() ||
0930                     impl::is_whitespace_only(*argument))
0931                 {
0932 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
0933                     if (boost::wave::need_variadics(ctx.get_language())) {
0934                         // store a placemarker as the argument
0935                         argument->push_back(token_type(T_PLACEMARKER, "\xA7",
0936                             (*next).get_position()));
0937                         ++count_arguments;
0938                     }
0939 #endif
0940                 }
0941                 else {
0942                     ++count_arguments;
0943                 }
0944                 arguments.push_back(ContainerT()); // add new arg
0945                 argument = &arguments[arguments.size()-1];
0946             }
0947             else {
0948                 // surrounded by parenthesises, so store to current argument
0949                 argument->push_back(*next);
0950             }
0951             was_whitespace = false;
0952             break;
0953 
0954         case T_NEWLINE:
0955             seen_newline = true;
0956             /* fall through */
0957         case T_SPACE:
0958         case T_SPACE2:
0959         case T_CCOMMENT:
0960             if (!was_whitespace)
0961                 argument->push_back(token_type(T_SPACE, " ", (*next).get_position()));
0962             was_whitespace = true;
0963             break;      // skip whitespace
0964 
0965         case T_PLACEHOLDER:
0966             break;      // ignore placeholder
0967 
0968         default:
0969             argument->push_back(*next);
0970             was_whitespace = false;
0971             break;
0972         }
0973     }
0974 
0975     if (nested_parenthesis_level >= 1) {
0976         // missing ')': improperly terminated macro invocation
0977         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
0978             improperly_terminated_macro, "missing ')'", main_pos);
0979         return 0;
0980     }
0981 
0982     // if no argument was expected and we didn't find any, than remove the empty
0983     // element
0984     if (0 == parameter_count && 0 == count_arguments) {
0985         BOOST_ASSERT(1 == arguments.size());
0986         arguments.clear();
0987     }
0988     return count_arguments;
0989 }
0990 
0991 ///////////////////////////////////////////////////////////////////////////////
0992 //
0993 //  expand_whole_tokensequence
0994 //
0995 //      fully expands a given token sequence
0996 //
0997 ///////////////////////////////////////////////////////////////////////////////
0998 template <typename ContextT>
0999 template <typename IteratorT, typename ContainerT>
1000 inline void
1001 macromap<ContextT>::expand_whole_tokensequence(ContainerT &expanded,
1002                                                IteratorT &first, IteratorT const &last,
1003                                                bool expand_operator_defined,
1004                                                bool expand_operator_has_include)
1005 {
1006     typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT>
1007         gen_type;
1008     typedef typename gen_type::return_type iterator_type;
1009 
1010     ContainerT empty;
1011     iterator_type first_it = gen_type::generate(empty, first);
1012     iterator_type last_it = gen_type::generate(last);
1013 
1014     on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
1015     ContainerT pending_queue;
1016     bool seen_newline;
1017 
1018     while (!pending_queue.empty() || first_it != last_it) {
1019         expanded.push_back(
1020             expand_tokensequence_worker(
1021                 pending_queue, first_it,
1022                 last_it, seen_newline, expand_operator_defined,
1023                 expand_operator_has_include,
1024                 boost::none)
1025         );
1026     }
1027 
1028     // should have returned all expanded tokens
1029     BOOST_ASSERT(pending_queue.empty()/* && unput_queue.empty()*/);
1030 }
1031 
1032 ///////////////////////////////////////////////////////////////////////////////
1033 //
1034 //  expand_argument
1035 //
1036 //      fully expands the given argument of a macro call
1037 //
1038 ///////////////////////////////////////////////////////////////////////////////
1039 template <typename ContextT>
1040 template <typename ContainerT>
1041 inline void
1042 macromap<ContextT>::expand_argument (
1043     typename std::vector<ContainerT>::size_type arg,
1044     std::vector<ContainerT> &arguments, std::vector<ContainerT> &expanded_args,
1045     bool expand_operator_defined, bool expand_operator_has_include,
1046     std::vector<bool> &has_expanded_args)
1047 {
1048     if (!has_expanded_args[arg]) {
1049         // expand the argument only once
1050         typedef typename std::vector<ContainerT>::value_type::iterator
1051             argument_iterator_type;
1052 
1053         argument_iterator_type begin_it = arguments[arg].begin();
1054         argument_iterator_type end_it = arguments[arg].end();
1055 
1056         expand_whole_tokensequence(
1057             expanded_args[arg], begin_it, end_it,
1058             expand_operator_defined, expand_operator_has_include);
1059         impl::remove_placeholders(expanded_args[arg]);
1060         has_expanded_args[arg] = true;
1061     }
1062 }
1063 
1064 ///////////////////////////////////////////////////////////////////////////////
1065 //
1066 //  expand_replacement_list
1067 //
1068 //      fully expands the replacement list of a given macro with the
1069 //      actual arguments/expanded arguments
1070 //      handles the '#' [cpp.stringize] and the '##' [cpp.concat] operator
1071 //
1072 ///////////////////////////////////////////////////////////////////////////////
1073 template <typename ContextT>
1074 template <typename ContainerT>
1075 inline void
1076 macromap<ContextT>::expand_replacement_list(
1077     typename macro_definition_type::const_definition_iterator_t cit,
1078     typename macro_definition_type::const_definition_iterator_t cend,
1079     std::vector<ContainerT> &arguments, bool expand_operator_defined,
1080     bool expand_operator_has_include,
1081     ContainerT &expanded)
1082 {
1083     using namespace boost::wave;
1084     typedef typename macro_definition_type::const_definition_iterator_t
1085         macro_definition_iter_t;
1086 
1087     std::vector<ContainerT> expanded_args(arguments.size());
1088     std::vector<bool> has_expanded_args(arguments.size());
1089     bool seen_concat = false;
1090     bool adjacent_concat = false;
1091     bool adjacent_stringize = false;
1092 
1093     for (;cit != cend; ++cit)
1094     {
1095         bool use_replaced_arg = true;
1096         token_id base_id = BASE_TOKEN(token_id(*cit));
1097 
1098         if (T_POUND_POUND == base_id) {
1099             // concatenation operator
1100             adjacent_concat = true;
1101             seen_concat = true;
1102         }
1103         else if (T_POUND == base_id) {
1104             // stringize operator
1105             adjacent_stringize = true;
1106         }
1107         else {
1108             if (adjacent_stringize || adjacent_concat ||
1109                 T_POUND_POUND == impl::next_token<macro_definition_iter_t>
1110                     ::peek(cit, cend))
1111             {
1112                 use_replaced_arg = false;
1113             }
1114             if (adjacent_concat)    // spaces after '##' ?
1115                 adjacent_concat = IS_CATEGORY(*cit, WhiteSpaceTokenType);
1116         }
1117 
1118         if (IS_CATEGORY((*cit), ParameterTokenType)) {
1119             // copy argument 'i' instead of the parameter token i
1120             typename ContainerT::size_type i;
1121 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1122             bool is_ellipsis = false;
1123 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1124             bool is_va_opt = false;
1125 #endif
1126 
1127             if (IS_EXTCATEGORY((*cit), ExtParameterTokenType)) {
1128                 BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
1129                 i = token_id(*cit) - T_EXTPARAMETERBASE;
1130                 is_ellipsis = true;
1131             }
1132             else
1133 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1134 
1135             if (IS_EXTCATEGORY((*cit), OptParameterTokenType)) {
1136                 BOOST_ASSERT(boost::wave::need_va_opt(ctx.get_language()));
1137                 i = token_id(*cit) - T_OPTPARAMETERBASE;
1138                 is_va_opt = true;
1139             }
1140             else
1141 #endif
1142 #endif
1143             {
1144                 i = token_id(*cit) - T_PARAMETERBASE;
1145             }
1146 
1147             BOOST_ASSERT(i <= arguments.size());
1148             if (use_replaced_arg) {
1149 
1150 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1151                 if (is_ellipsis) {
1152                     position_type const& pos = (*cit).get_position();
1153 
1154                     BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
1155 
1156                     // ensure all variadic arguments to be expanded
1157                     for (typename vector<ContainerT>::size_type arg = i;
1158                          arg < expanded_args.size(); ++arg)
1159                     {
1160                         expand_argument(
1161                             arg, arguments, expanded_args,
1162                             expand_operator_defined, expand_operator_has_include,
1163                             has_expanded_args);
1164                     }
1165                     impl::replace_ellipsis(expanded_args, i, expanded, pos);
1166                 }
1167                 else
1168 
1169 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1170                 if (is_va_opt) {
1171                     position_type const &pos = (*cit).get_position();
1172 
1173                     BOOST_ASSERT(boost::wave::need_va_opt(ctx.get_language()));
1174 
1175                     // ensure all variadic arguments to be expanded
1176                     for (typename vector<ContainerT>::size_type arg = i;
1177                          arg < expanded_args.size(); ++arg)
1178                     {
1179                         expand_argument(
1180                             arg, arguments, expanded_args,
1181                             expand_operator_defined, expand_operator_has_include,
1182                             has_expanded_args);
1183                     }
1184 
1185                     // locate the end of the __VA_OPT__ call
1186                     typename macro_definition_type::const_definition_iterator_t cstart = cit;
1187                     if (!impl::find_va_opt_args(cit, cend)) {
1188                         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1189                             improperly_terminated_macro, "missing '(' or ')' in __VA_OPT__",
1190                             pos);
1191                     }
1192                     // cstart still points to __VA_OPT__; cit now points to the last rparen
1193 
1194                     // locate the __VA_OPT__ arguments
1195                     typename macro_definition_type::const_definition_iterator_t arg_start = cstart;
1196                     ++arg_start;  // skip __VA_OPT__
1197                     ++arg_start;  // skip lparen
1198 
1199                     // create a synthetic macro definition for use with hooks
1200                     token_type macroname(T_IDENTIFIER, "__VA_OPT__", position_type("<built-in>"));
1201                     parameter_container_type macroparameters;
1202                     macroparameters.push_back(token_type(T_ELLIPSIS, "...", position_type("<built-in>")));
1203                     definition_container_type macrodefinition;
1204 
1205                     bool suppress_expand = false;
1206                     // __VA_OPT__ treats its arguments as an undifferentiated stream of tokens
1207                     // for our purposes we can consider it as a single argument
1208                     typename std::vector<ContainerT> va_opt_args(1, ContainerT(arg_start, cit));
1209                     suppress_expand = ctx.get_hooks().expanding_function_like_macro(
1210                         ctx.derived(),
1211                         macroname, macroparameters, macrodefinition,
1212                         *cstart, va_opt_args,
1213                         cstart, cit);
1214 
1215                     if (suppress_expand) {
1216                         // leave the whole expression in place
1217                         std::copy(cstart, cit, std::back_inserter(expanded));
1218                         expanded.push_back(*cit);  // include the rparen
1219                     } else {
1220                         ContainerT va_expanded;
1221                         if ((i == arguments.size()) ||                 // no variadic argument
1222                             impl::is_whitespace_only(arguments[i])) {  // no visible tokens
1223                             // no args; insert placemarker
1224                             va_expanded.push_back(
1225                                 typename ContainerT::value_type(T_PLACEMARKER, "\xA7", pos));
1226                         } else if (!impl::is_blank_only(arguments[i])) {
1227                             // [cstart, cit) is now the args to va_opt
1228                             // recursively process them
1229                             expand_replacement_list(arg_start, cit, arguments,
1230                                                     expand_operator_defined,
1231                                                     expand_operator_has_include,
1232                                                     va_expanded);
1233                         }
1234                         // run final hooks
1235                         ctx.get_hooks().expanded_macro(ctx.derived(), va_expanded);
1236 
1237                         // updated overall expansion with va_opt results
1238                         expanded.splice(expanded.end(), va_expanded);
1239                     }
1240                     // continue from rparen
1241                 }
1242                 else
1243 
1244 #endif
1245 #endif
1246                 {
1247                     BOOST_ASSERT(i < arguments.size());
1248                     // ensure argument i to be expanded
1249                     expand_argument(
1250                         i, arguments, expanded_args,
1251                         expand_operator_defined, expand_operator_has_include,
1252                         has_expanded_args);
1253 
1254                     // replace argument
1255                     BOOST_ASSERT(i < expanded_args.size());
1256                     ContainerT const& arg = expanded_args[i];
1257 
1258                     std::copy(arg.begin(), arg.end(),
1259                         std::inserter(expanded, expanded.end()));
1260                 }
1261             }
1262             else if (adjacent_stringize &&
1263                     !IS_CATEGORY(*cit, WhiteSpaceTokenType))
1264             {
1265                 // stringize the current argument
1266                 BOOST_ASSERT(!arguments[i].empty());
1267 
1268                 // safe a copy of the first tokens position (not a reference!)
1269                 position_type pos((*arguments[i].begin()).get_position());
1270 
1271 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1272                 if (is_ellipsis && boost::wave::need_variadics(ctx.get_language())) {
1273                     impl::trim_sequence_left(arguments[i]);
1274                     impl::trim_sequence_right(arguments.back());
1275                     expanded.push_back(token_type(T_STRINGLIT,
1276                         impl::as_stringlit(arguments, i, pos), pos));
1277                 }
1278                 else
1279 #endif
1280                 {
1281                     impl::trim_sequence(arguments[i]);
1282                     expanded.push_back(token_type(T_STRINGLIT,
1283                         impl::as_stringlit(arguments[i], pos), pos));
1284                 }
1285                 adjacent_stringize = false;
1286             }
1287             else {
1288                 // simply copy the original argument (adjacent '##' or '#')
1289 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1290                 if (is_ellipsis) {
1291                     position_type const& pos = (*cit).get_position();
1292 #if BOOST_WAVE_SUPPORT_CPP2A != 0
1293                     if (i < arguments.size())
1294 #endif
1295                     {
1296 
1297                         impl::trim_sequence_left(arguments[i]);
1298                         impl::trim_sequence_right(arguments.back());
1299                         BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
1300                         impl::replace_ellipsis(arguments, i, expanded, pos);
1301                     }
1302 #if BOOST_WAVE_SUPPORT_CPP2A != 0
1303                     else if (boost::wave::need_cpp2a(ctx.get_language())) {
1304                         BOOST_ASSERT(i == arguments.size());
1305                         // no argument supplied; insert placemarker
1306                         expanded.push_back(
1307                             typename ContainerT::value_type(T_PLACEMARKER, "\xA7", pos));
1308                     }
1309 #endif
1310                 }
1311                 else
1312 #endif
1313                 {
1314                     ContainerT& arg = arguments[i];
1315 
1316                     impl::trim_sequence(arg);
1317                     std::copy(arg.begin(), arg.end(),
1318                         std::inserter(expanded, expanded.end()));
1319                 }
1320             }
1321         }
1322         else if (!adjacent_stringize || T_POUND != base_id) {
1323             // insert the actual replacement token (if it is not the '#' operator)
1324             expanded.push_back(*cit);
1325         }
1326     }
1327 
1328     if (adjacent_stringize) {
1329         // error, '#' should not be the last token
1330         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_operator,
1331             "stringize ('#')", main_pos);
1332         return;
1333     }
1334 
1335     // handle the cpp.concat operator
1336     if (seen_concat)
1337         concat_tokensequence(expanded);
1338 }
1339 
1340 ///////////////////////////////////////////////////////////////////////////////
1341 //
1342 //  rescan_replacement_list
1343 //
1344 //    As the name implies, this function is used to rescan the replacement list
1345 //    after the first macro substitution phase.
1346 //
1347 ///////////////////////////////////////////////////////////////////////////////
1348 template <typename ContextT>
1349 template <typename IteratorT, typename ContainerT>
1350 inline void
1351 macromap<ContextT>::rescan_replacement_list(token_type const &curr_token,
1352     macro_definition_type &macro_def, ContainerT &replacement_list,
1353     ContainerT &expanded,
1354     bool expand_operator_defined,
1355     bool expand_operator_has_include,
1356     IteratorT &nfirst, IteratorT const &nlast)
1357 {
1358     if (!replacement_list.empty()) {
1359 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1360         // remove the placemarkers
1361         if (boost::wave::need_variadics(ctx.get_language())) {
1362             typename ContainerT::iterator end = replacement_list.end();
1363             typename ContainerT::iterator it = replacement_list.begin();
1364 
1365             while (it != end) {
1366                 using namespace boost::wave;
1367                 if (T_PLACEMARKER == token_id(*it)) {
1368                     typename ContainerT::iterator placemarker = it;
1369 
1370                     ++it;
1371                     replacement_list.erase(placemarker);
1372                 }
1373                 else {
1374                     ++it;
1375                 }
1376             }
1377         }
1378 #endif
1379 
1380         // rescan the replacement list, during this rescan the current macro under
1381         // expansion isn't available as an expandable macro
1382         on_exit::reset<bool> on_exit(macro_def.is_available_for_replacement, false);
1383         typename ContainerT::iterator begin_it = replacement_list.begin();
1384         typename ContainerT::iterator end_it = replacement_list.end();
1385 
1386         expand_whole_tokensequence(
1387             expanded, begin_it, end_it,
1388             expand_operator_defined, expand_operator_has_include);
1389 
1390         // trim replacement list, leave placeholder tokens untouched
1391         impl::trim_replacement_list(expanded);
1392     }
1393 
1394     if (expanded.empty()) {
1395         // the resulting replacement list should contain at least a placeholder
1396         // token
1397         expanded.push_back(token_type(T_PLACEHOLDER, "_", curr_token.get_position()));
1398     }
1399 }
1400 
1401 ///////////////////////////////////////////////////////////////////////////////
1402 //
1403 //  expand_macro(): expands a defined macro
1404 //
1405 //      This functions tries to expand the macro, to which points the 'first'
1406 //      iterator. The functions eats up more tokens, if the macro to expand is
1407 //      a function-like macro.
1408 //
1409 ///////////////////////////////////////////////////////////////////////////////
1410 template <typename ContextT>
1411 template <typename IteratorT, typename ContainerT>
1412 inline bool
1413 macromap<ContextT>::expand_macro(ContainerT &expanded,
1414     token_type const &curr_token, typename defined_macros_type::iterator it,
1415     IteratorT &first, IteratorT const &last,
1416     bool& seen_newline, bool expand_operator_defined,
1417     bool expand_operator_has_include,
1418     boost::optional<position_type> expanding_pos,
1419     defined_macros_type *scope, ContainerT *queue_symbol)
1420 {
1421     using namespace boost::wave;
1422 
1423     if (0 == scope) scope = current_macros;
1424 
1425     BOOST_ASSERT(T_IDENTIFIER == token_id(curr_token) ||
1426         IS_CATEGORY(token_id(curr_token), KeywordTokenType) ||
1427         IS_EXTCATEGORY(token_id(curr_token), OperatorTokenType|AltExtTokenType) ||
1428         IS_CATEGORY(token_id(curr_token), BoolLiteralTokenType));
1429 
1430     if (it == scope->end()) {
1431         ++first;    // advance
1432 
1433         // try to expand a predefined macro (__FILE__, __LINE__ or __INCLUDE_LEVEL__)
1434         if (expand_predefined_macro(curr_token, expanded))
1435             return false;
1436 
1437         // not defined as a macro
1438         if (0 != queue_symbol) {
1439             expanded.splice(expanded.end(), *queue_symbol);
1440         }
1441         else {
1442             expanded.push_back(curr_token);
1443         }
1444         return false;
1445     }
1446 
1447     // ensure the parameters to be replaced with special parameter tokens
1448     macro_definition_type& macro_def = *(*it).second.get();
1449 
1450     macro_def.replace_parameters(ctx);
1451 
1452     // test if this macro is currently available for replacement
1453     if (!macro_def.is_available_for_replacement) {
1454         // this macro is marked as non-replaceable
1455         // copy the macro name itself
1456         if (0 != queue_symbol) {
1457             queue_symbol->push_back(token_type(T_NONREPLACABLE_IDENTIFIER,
1458                 curr_token.get_value(), curr_token.get_position()));
1459             expanded.splice(expanded.end(), *queue_symbol);
1460         }
1461         else {
1462             expanded.push_back(token_type(T_NONREPLACABLE_IDENTIFIER,
1463                 curr_token.get_value(), curr_token.get_position()));
1464         }
1465         ++first;
1466         return false;
1467     }
1468 
1469     // try to replace the current identifier as a function-like macro
1470     ContainerT replacement_list;
1471 
1472     if (T_LEFTPAREN == impl::next_token<IteratorT>::peek(first, last)) {
1473         // called as a function-like macro
1474         impl::skip_to_token(ctx, first, last, T_LEFTPAREN, seen_newline);
1475 
1476         IteratorT seqstart = first;
1477         IteratorT seqend = first;
1478 
1479         if (macro_def.is_functionlike) {
1480             // defined as a function-like macro
1481 
1482             // collect the arguments
1483             std::vector<ContainerT> arguments;
1484             typename std::vector<ContainerT>::size_type count_args =
1485                 collect_arguments(curr_token, arguments, first, seqend, last,
1486                     macro_def.macroparameters.size(), seen_newline);
1487 
1488             std::size_t parm_count_required = macro_def.macroparameters.size();
1489 #if BOOST_WAVE_SUPPORT_CPP2A
1490             if (boost::wave::need_cpp2a(ctx.get_language())) {
1491                 // Starting with C++20, variable arguments may be left out
1492                 // entirely, so reduce the mandatory argument count by one
1493                 // if the last parameter is ellipsis:
1494                 if ((parm_count_required > 0) &&
1495                     (T_ELLIPSIS == token_id(macro_def.macroparameters.back()))) {
1496                     --parm_count_required;
1497                 }
1498             }
1499 #endif
1500 
1501             // verify the parameter count
1502             if (count_args < parm_count_required ||
1503                 arguments.size() < parm_count_required)
1504             {
1505                 if (count_args != arguments.size()) {
1506                     // must been at least one empty argument in C++ mode
1507                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1508                         empty_macroarguments, curr_token.get_value().c_str(),
1509                         main_pos);
1510                 }
1511                 else {
1512                     // too few macro arguments
1513                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1514                         too_few_macroarguments, curr_token.get_value().c_str(),
1515                         main_pos);
1516                 }
1517                 return false;
1518             }
1519 
1520             if (count_args > macro_def.macroparameters.size() ||
1521                 arguments.size() > macro_def.macroparameters.size())
1522             {
1523 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1524                 if (!macro_def.has_ellipsis)
1525 #endif
1526                 {
1527                     // too many macro arguments
1528                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1529                         too_many_macroarguments,
1530                         curr_token.get_value().c_str(), main_pos);
1531                     return false;
1532                 }
1533             }
1534 
1535             // inject tracing support
1536             if (ctx.get_hooks().expanding_function_like_macro(ctx.derived(),
1537                     macro_def.macroname, macro_def.macroparameters,
1538                     macro_def.macrodefinition, curr_token, arguments,
1539                     seqstart, seqend))
1540             {
1541 //                 // do not expand this macro, just copy the whole sequence
1542 //                 expanded.push_back(curr_token);
1543 //                 std::copy(seqstart, first,
1544 //                     std::inserter(expanded, expanded.end()));
1545                 // do not expand macro, just copy macro name and parenthesis
1546                 expanded.push_back(curr_token);
1547                 expanded.push_back(*seqstart);
1548                 first = ++seqstart;
1549                 return false;           // no further preprocessing required
1550             }
1551 
1552             // expand the replacement list of this macro
1553             expand_replacement_list(macro_def.macrodefinition.begin(),
1554                 macro_def.macrodefinition.end(),
1555                 arguments, expand_operator_defined,
1556                 expand_operator_has_include,
1557                 replacement_list);
1558 
1559             if (!expanding_pos)
1560                 expanding_pos = curr_token.get_expand_position();
1561             set_expand_positions(replacement_list, *expanding_pos);
1562         }
1563         else {
1564             // defined as an object-like macro
1565             if (ctx.get_hooks().expanding_object_like_macro(ctx.derived(),
1566                   macro_def.macroname, macro_def.macrodefinition, curr_token))
1567             {
1568                 // do not expand this macro, just copy the whole sequence
1569                 expanded.push_back(curr_token);
1570                 return false;           // no further preprocessing required
1571             }
1572 
1573             bool found = false;
1574             impl::find_concat_operator concat_tag(found);
1575 
1576             std::remove_copy_if(macro_def.macrodefinition.begin(),
1577                 macro_def.macrodefinition.end(),
1578                 std::inserter(replacement_list, replacement_list.end()),
1579                 concat_tag);
1580 
1581             // handle concatenation operators
1582             if (found && !concat_tokensequence(replacement_list))
1583                 return false;
1584         }
1585     }
1586     else {
1587         // called as an object like macro
1588         if ((*it).second->is_functionlike) {
1589             // defined as a function-like macro
1590             if (0 != queue_symbol) {
1591                 queue_symbol->push_back(curr_token);
1592                 expanded.splice(expanded.end(), *queue_symbol);
1593             }
1594             else {
1595                 expanded.push_back(curr_token);
1596             }
1597             ++first;                // skip macro name
1598             return false;           // no further preprocessing required
1599         }
1600         else {
1601             // defined as an object-like macro (expand it)
1602             if (ctx.get_hooks().expanding_object_like_macro(ctx.derived(),
1603                   macro_def.macroname, macro_def.macrodefinition, curr_token))
1604             {
1605                 // do not expand this macro, just copy the whole sequence
1606                 expanded.push_back(curr_token);
1607                 ++first;                // skip macro name
1608                 return false;           // no further preprocessing required
1609             }
1610 
1611             bool found = false;
1612             impl::find_concat_operator concat_tag(found);
1613 
1614             std::remove_copy_if(macro_def.macrodefinition.begin(),
1615                 macro_def.macrodefinition.end(),
1616                 std::inserter(replacement_list, replacement_list.end()),
1617                 concat_tag);
1618 
1619             // handle concatenation operators
1620             if (found && !concat_tokensequence(replacement_list))
1621                 return false;
1622 
1623             ++first;                // skip macro name
1624         }
1625     }
1626 
1627     // rescan the replacement list
1628     ContainerT expanded_list;
1629 
1630     ctx.get_hooks().expanded_macro(ctx.derived(), replacement_list);
1631 
1632     rescan_replacement_list(
1633         curr_token, macro_def, replacement_list,
1634         expanded_list, expand_operator_defined,
1635         expand_operator_has_include, first, last);
1636 
1637     ctx.get_hooks().rescanned_macro(ctx.derived(), expanded_list);
1638 
1639     if (!expanding_pos)
1640         // set the expanding position for rescan
1641         expanding_pos = curr_token.get_expand_position();
1642 
1643     // record the location where all the tokens were expanded from
1644     set_expand_positions(expanded_list, *expanding_pos);
1645 
1646     expanded.splice(expanded.end(), expanded_list);
1647     return true;        // rescan is required
1648 }
1649 
1650 ///////////////////////////////////////////////////////////////////////////////
1651 //
1652 //  If the token under inspection points to a certain predefined macro it will
1653 //  be expanded, otherwise false is returned.
1654 //  (only __FILE__, __LINE__ and __INCLUDE_LEVEL__ macros are expanded here)
1655 //
1656 ///////////////////////////////////////////////////////////////////////////////
1657 template <typename ContextT>
1658 template <typename ContainerT>
1659 inline bool
1660 macromap<ContextT>::expand_predefined_macro(token_type const &curr_token,
1661     ContainerT &expanded)
1662 {
1663     using namespace boost::wave;
1664 
1665     string_type const& value = curr_token.get_value();
1666 
1667     if ((value != "__LINE__") && (value != "__FILE__") && (value != "__INCLUDE_LEVEL__"))
1668         return false;
1669 
1670     // construct a fake token for the macro's definition point
1671     token_type deftoken(T_IDENTIFIER, value, position_type("<built-in>"));
1672 
1673     if (ctx.get_hooks().expanding_object_like_macro(ctx.derived(),
1674             deftoken, ContainerT(), curr_token))
1675     {
1676         // do not expand this macro, just copy the whole sequence
1677         expanded.push_back(curr_token);
1678         return false;           // no further preprocessing required
1679     }
1680 
1681     token_type replacement;
1682 
1683     if (value == "__LINE__") {
1684         // expand the __LINE__ macro
1685         std::string buffer = lexical_cast<std::string>(curr_token.get_expand_position().get_line());
1686 
1687         replacement = token_type(T_INTLIT, buffer.c_str(), curr_token.get_position());
1688     }
1689     else if (value == "__FILE__") {
1690         // expand the __FILE__ macro
1691         namespace fs = boost::filesystem;
1692 
1693         std::string file("\"");
1694         fs::path filename(
1695             wave::util::create_path(curr_token.get_expand_position().get_file().c_str()));
1696 
1697         using boost::wave::util::impl::escape_lit;
1698         file += escape_lit(wave::util::native_file_string(filename)) + "\"";
1699         replacement = token_type(T_STRINGLIT, file.c_str(),
1700             curr_token.get_position());
1701     }
1702     else if (value == "__INCLUDE_LEVEL__") {
1703         // expand the __INCLUDE_LEVEL__ macro
1704         std::string buffer = std::to_string(ctx.get_iteration_depth());
1705         replacement = token_type(T_INTLIT, buffer.c_str(), curr_token.get_position());
1706     }
1707 
1708     // post-expansion hooks
1709     ContainerT replacement_list;
1710     replacement_list.push_back(replacement);
1711 
1712     ctx.get_hooks().expanded_macro(ctx.derived(), replacement_list);
1713 
1714     expanded.push_back(replacement);
1715 
1716     ctx.get_hooks().rescanned_macro(ctx.derived(), expanded);
1717 
1718     return true;
1719 
1720 }
1721 
1722 ///////////////////////////////////////////////////////////////////////////////
1723 //
1724 //  resolve_defined(): resolve the operator defined() and replace it with the
1725 //                     correct T_INTLIT token
1726 //
1727 ///////////////////////////////////////////////////////////////////////////////
1728 template <typename ContextT>
1729 template <typename IteratorT, typename ContainerT>
1730 inline typename ContextT::token_type const &
1731 macromap<ContextT>::resolve_defined(IteratorT &first,
1732     IteratorT const &last, ContainerT &pending)
1733 {
1734     using namespace boost::wave;
1735     using namespace boost::wave::grammars;
1736 
1737 ContainerT result;
1738 IteratorT start = first;
1739 boost::spirit::classic::parse_info<IteratorT> hit =
1740     defined_grammar_gen<typename ContextT::lexer_type>::
1741         parse_operator_defined(start, last, result);
1742 
1743     if (!hit.hit) {
1744         string_type msg ("defined(): ");
1745         msg = msg + util::impl::as_string<string_type>(first, last);
1746         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_expression,
1747             msg.c_str(), main_pos);
1748 
1749         // insert a dummy token
1750         pending.push_back(token_type(T_INTLIT, "0", main_pos));
1751     }
1752     else {
1753         impl::assign_iterator<IteratorT>::do_(first, hit.stop);
1754 
1755         // insert a token, which reflects the outcome
1756         pending.push_back(token_type(T_INTLIT,
1757             is_defined(result.begin(), result.end()) ? "1" : "0",
1758             main_pos));
1759     }
1760 
1761     on_exit::pop_front<definition_container_type> pop_front_token(pending);
1762 
1763     return act_token = pending.front();
1764 }
1765 
1766 #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0
1767 ///////////////////////////////////////////////////////////////////////////////
1768 //
1769 //  resolve_has_include(): resolve the operator __has_include() and replace
1770 //                      it with the correct T_INTLIT token
1771 //
1772 ///////////////////////////////////////////////////////////////////////////////
1773 template <typename ContextT>
1774 template <typename IteratorT, typename ContainerT>
1775 inline typename ContextT::token_type const &
1776 macromap<ContextT>::resolve_has_include(IteratorT &first,
1777     IteratorT const &last, ContainerT &pending)
1778 {
1779     using namespace boost::wave;
1780     using namespace boost::wave::grammars;
1781 
1782     ContainerT result;
1783     bool is_quoted_filename;
1784     bool is_system;
1785     IteratorT start = first;
1786 
1787     boost::spirit::classic::parse_info<IteratorT> hit =
1788         has_include_grammar_gen<typename ContextT::lexer_type>::
1789         parse_operator_has_include(start, last, result, is_quoted_filename, is_system);
1790 
1791     if (!hit.hit) {
1792         string_type msg ("__has_include(): ");
1793         msg = msg + util::impl::as_string<string_type>(first, last);
1794         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_expression,
1795             msg.c_str(), main_pos);
1796 
1797         // insert a dummy token
1798         pending.push_back(token_type(T_INTLIT, "0", main_pos));
1799     }
1800     else {
1801         impl::assign_iterator<IteratorT>::do_(first, hit.stop);
1802 
1803         // insert a token, which reflects the outcome
1804         pending.push_back(
1805             token_type(T_INTLIT,
1806                        has_include(result.begin(), result.end(),
1807                                    is_quoted_filename, is_system) ? "1" : "0",
1808                        main_pos));
1809     }
1810 
1811     on_exit::pop_front<definition_container_type> pop_front_token(pending);
1812 
1813     return act_token = pending.front();
1814 }
1815 #endif
1816 
1817 ///////////////////////////////////////////////////////////////////////////////
1818 //
1819 //  resolve_operator_pragma(): resolve the operator _Pragma() and dispatch to
1820 //                             the associated action
1821 //
1822 //      This function returns true, if the pragma was correctly interpreted.
1823 //      The iterator 'first' is positioned behind the closing ')'.
1824 //      This function returns false, if the _Pragma was not known, the
1825 //      preprocessed token sequence is pushed back to the 'pending' sequence.
1826 //
1827 ///////////////////////////////////////////////////////////////////////////////
1828 template <typename ContextT>
1829 template <typename IteratorT, typename ContainerT>
1830 inline bool
1831 macromap<ContextT>::resolve_operator_pragma(IteratorT &first,
1832     IteratorT const &last, ContainerT &pending, bool& seen_newline)
1833 {
1834     // isolate the parameter of the operator _Pragma
1835     token_type pragma_token = *first;
1836 
1837     if (!impl::skip_to_token(ctx, first, last, T_LEFTPAREN, seen_newline)) {
1838         // illformed operator _Pragma
1839         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_expression,
1840             "operator _Pragma()", pragma_token.get_position());
1841         return false;
1842     }
1843 
1844     std::vector<ContainerT> arguments;
1845     IteratorT endparen = first;
1846     typename std::vector<ContainerT>::size_type count_args =
1847         collect_arguments (pragma_token, arguments, first, endparen, last, 1,
1848             seen_newline);
1849 
1850     // verify the parameter count
1851     if (pragma_token.get_position().get_file().empty())
1852         pragma_token.set_position(act_token.get_position());
1853 
1854     if (count_args < 1 || arguments.size() < 1) {
1855         // too few macro arguments
1856         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, too_few_macroarguments,
1857             pragma_token.get_value().c_str(), pragma_token.get_position());
1858         return false;
1859     }
1860     if (count_args > 1 || arguments.size() > 1) {
1861         // too many macro arguments
1862         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, too_many_macroarguments,
1863             pragma_token.get_value().c_str(), pragma_token.get_position());
1864         return false;
1865     }
1866 
1867     // preprocess the pragma token body
1868     typedef typename std::vector<ContainerT>::value_type::iterator
1869         argument_iterator_type;
1870 
1871     ContainerT expanded;
1872     argument_iterator_type begin_it = arguments[0].begin();
1873     argument_iterator_type end_it = arguments[0].end();
1874     expand_whole_tokensequence(expanded, begin_it, end_it, false, false);
1875 
1876     // un-escape the parameter of the operator _Pragma
1877     typedef typename token_type::string_type string_type;
1878 
1879     string_type pragma_cmd;
1880     typename ContainerT::const_iterator end_exp = expanded.end();
1881     for (typename ContainerT::const_iterator it_exp = expanded.begin();
1882          it_exp != end_exp; ++it_exp)
1883     {
1884         if (T_EOF == token_id(*it_exp))
1885             break;
1886         if (IS_CATEGORY(*it_exp, WhiteSpaceTokenType))
1887             continue;
1888 
1889         if (T_STRINGLIT != token_id(*it_exp)) {
1890             // ill formed operator _Pragma
1891             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1892                 ill_formed_pragma_option, "_Pragma",
1893                 pragma_token.get_position());
1894             return false;
1895         }
1896         if (pragma_cmd.size() > 0) {
1897             // there should be exactly one string literal (string literals are to
1898             // be concatenated at translation phase 6, but _Pragma operators are
1899             // to be executed at translation phase 4)
1900             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1901                 ill_formed_pragma_option, "_Pragma",
1902                 pragma_token.get_position());
1903             return false;
1904         }
1905 
1906         // remove the '\"' and concat all given string literal-values
1907         string_type token_str = (*it_exp).get_value();
1908         pragma_cmd += token_str.substr(1, token_str.size() - 2);
1909     }
1910     string_type pragma_cmd_unesc = impl::unescape_lit(pragma_cmd);
1911 
1912     // tokenize the pragma body
1913     typedef typename ContextT::lexer_type lexer_type;
1914 
1915     ContainerT pragma;
1916     std::string pragma_cmd_str(pragma_cmd_unesc.c_str());
1917     lexer_type it = lexer_type(pragma_cmd_str.begin(), pragma_cmd_str.end(),
1918         pragma_token.get_position(), ctx.get_language());
1919     lexer_type end = lexer_type();
1920     for (/**/; it != end; ++it)
1921         pragma.push_back(*it);
1922 
1923     // analyze the preprocessed token sequence and eventually dispatch to the
1924     // associated action
1925     if (interpret_pragma(ctx, pragma_token, pragma.begin(), pragma.end(),
1926         pending))
1927     {
1928         return true;    // successfully recognized a wave specific pragma
1929     }
1930 
1931     // unknown pragma token sequence, push it back and return to the caller
1932     pending.push_front(token_type(T_SPACE, " ", pragma_token.get_position()));
1933     pending.push_front(token_type(T_RIGHTPAREN, ")", pragma_token.get_position()));
1934     pending.push_front(token_type(T_STRINGLIT, string_type("\"") + pragma_cmd + "\"",
1935         pragma_token.get_position()));
1936     pending.push_front(token_type(T_LEFTPAREN, "(", pragma_token.get_position()));
1937     pending.push_front(pragma_token);
1938     return false;
1939 }
1940 
1941 ///////////////////////////////////////////////////////////////////////////////
1942 //
1943 //  Test, whether the result of a concat operator is well formed or not.
1944 //
1945 //  This is done by re-scanning (re-tokenizing) the resulting token sequence,
1946 //  which should give back exactly one token.
1947 //
1948 ///////////////////////////////////////////////////////////////////////////////
1949 template <typename ContextT>
1950 template <typename ContainerT>
1951 inline bool
1952 macromap<ContextT>::is_valid_concat(string_type new_value,
1953     position_type const &pos, ContainerT &rescanned)
1954 {
1955     // re-tokenize the newly generated string
1956     typedef typename ContextT::lexer_type lexer_type;
1957 
1958     std::string value_to_test(new_value.c_str());
1959 
1960     boost::wave::language_support lang =
1961         boost::wave::enable_prefer_pp_numbers(ctx.get_language());
1962     lang = boost::wave::enable_single_line(lang);
1963 
1964     lexer_type it = lexer_type(value_to_test.begin(), value_to_test.end(), pos,
1965         lang);
1966     lexer_type end = lexer_type();
1967     for (/**/; it != end && T_EOF != token_id(*it); ++it)
1968     {
1969         // as of Wave V2.0.7 pasting of tokens is valid only if the resulting
1970         // tokens are pp_tokens (as mandated by C++11)
1971         if (!is_pp_token(*it))
1972             return false;
1973         rescanned.push_back(*it);
1974     }
1975 
1976 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1977     if (boost::wave::need_variadics(ctx.get_language()))
1978         return true;       // in variadics mode token pasting is well defined
1979 #endif
1980 
1981     // test if the newly generated token sequence contains more than 1 token
1982     return 1 == rescanned.size();
1983 }
1984 
1985 ///////////////////////////////////////////////////////////////////////////////
1986 //
1987 //  Bulk update expand positions
1988 //
1989 ///////////////////////////////////////////////////////////////////////////////
1990 // batch update tokens with a single expand position
1991 template <typename ContextT>
1992 template <typename ContainerT>
1993 void macromap<ContextT>::set_expand_positions(ContainerT &tokens, position_type pos)
1994 {
1995     typename ContainerT::iterator ex_end = tokens.end();
1996     for (typename ContainerT::iterator it = tokens.begin();
1997          it != ex_end; ++it) {
1998         // expand positions are only used for __LINE__, __FILE__, and macro names
1999         if (token_id(*it) == T_IDENTIFIER)
2000             it->set_expand_position(pos);
2001     }
2002 }
2003 
2004 ///////////////////////////////////////////////////////////////////////////////
2005 //
2006 //  Handle all occurrences of the concatenation operator '##' inside the given
2007 //  token sequence.
2008 //
2009 ///////////////////////////////////////////////////////////////////////////////
2010 template <typename Context>
2011 inline void report_invalid_concatenation(Context& ctx,
2012     typename Context::token_type const& prev,
2013     typename Context::token_type const& next,
2014     typename Context::position_type const& main_pos)
2015 {
2016     typename Context::string_type error_string("\"");
2017 
2018     error_string += prev.get_value();
2019     error_string += "\" and \"";
2020     error_string += next.get_value();
2021     error_string += "\"";
2022     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_concat,
2023         error_string.c_str(), main_pos);
2024 }
2025 
2026 template <typename ContextT>
2027 template <typename ContainerT>
2028 inline bool
2029 macromap<ContextT>::concat_tokensequence(ContainerT &expanded)
2030 {
2031     using namespace boost::wave;
2032     typedef typename ContainerT::iterator iterator_type;
2033 
2034     iterator_type end = expanded.end();
2035     iterator_type prev = end;
2036     for (iterator_type it = expanded.begin(); it != end; /**/)
2037     {
2038         if (T_POUND_POUND == BASE_TOKEN(token_id(*it))) {
2039             iterator_type next = it;
2040 
2041             ++next;
2042             if (prev == end || next == end) {
2043                 // error, '##' should be in between two tokens
2044                 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2045                     ill_formed_operator, "concat ('##')", main_pos);
2046                 return false;
2047             }
2048 
2049             // replace prev##next with the concatenated value, skip whitespace
2050             // before and after the '##' operator
2051             while (IS_CATEGORY(*next, WhiteSpaceTokenType)) {
2052                 ++next;
2053                 if (next == end) {
2054                     // error, '##' should be in between two tokens
2055                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2056                         ill_formed_operator, "concat ('##')", main_pos);
2057                     return false;
2058                 }
2059             }
2060 
2061 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
2062             if (boost::wave::need_variadics(ctx.get_language())) {
2063                 if (T_PLACEMARKER == token_id(*next)) {
2064                     // remove the '##' and the next tokens from the sequence
2065                     iterator_type first_to_delete = prev;
2066 
2067                     expanded.erase(++first_to_delete, ++next);
2068                     it = next;
2069                     continue;
2070                 }
2071                 else if (T_PLACEMARKER == token_id(*prev)) {
2072                     // remove the '##' and the next tokens from the sequence
2073                     iterator_type first_to_delete = prev;
2074 
2075                     *prev = *next;
2076                     expanded.erase(++first_to_delete, ++next);
2077                     it = next;
2078                     continue;
2079                 }
2080             }
2081 #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
2082 
2083             // test if the concat operator has to concatenate two unrelated
2084             // tokens i.e. the result yields more then one token
2085             string_type concat_result;
2086             ContainerT rescanned;
2087 
2088             concat_result = ((*prev).get_value() + (*next).get_value());
2089 
2090             // analyze the validity of the concatenation result
2091             if (!is_valid_concat(concat_result, (*prev).get_position(),
2092                     rescanned) &&
2093                 !IS_CATEGORY(*prev, WhiteSpaceTokenType) &&
2094                 !IS_CATEGORY(*next, WhiteSpaceTokenType))
2095             {
2096                 report_invalid_concatenation(ctx, *prev, *next, main_pos);
2097                 return false;
2098             }
2099 
2100 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
2101             if (boost::wave::need_variadics(ctx.get_language())) {
2102                 // remove the prev, '##' and the next tokens from the sequence
2103                 expanded.erase(prev, ++next); // remove not needed tokens
2104 
2105                 // some stl implementations clear() the container if we erased all
2106                 // the elements, which orphans all iterators. we re-initialize these
2107                 // here
2108                 if (expanded.empty())
2109                     end = next = expanded.end();
2110 
2111                 // replace the old token (pointed to by *prev) with the re-tokenized
2112                 // sequence
2113                 expanded.splice(next, rescanned);
2114 
2115                 // the last token of the inserted sequence is the new previous
2116                 prev = next;
2117                 if (next != expanded.end())
2118                     --prev;
2119             }
2120             else
2121 #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
2122             {
2123                 // we leave the token_id unchanged, but unmark the token as
2124                 // disabled, if appropriate
2125                 (*prev).set_value(concat_result);
2126                 if (T_NONREPLACABLE_IDENTIFIER == token_id(*prev))
2127                     (*prev).set_token_id(T_IDENTIFIER);
2128 
2129                 // remove the '##' and the next tokens from the sequence
2130                 iterator_type first_to_delete = prev;
2131 
2132                 expanded.erase(++first_to_delete, ++next);
2133             }
2134             it = next;
2135             continue;
2136         }
2137 
2138         // save last non-whitespace token position
2139         if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
2140             prev = it;
2141 
2142         ++it;           // next token, please
2143     }
2144     return true;
2145 }
2146 
2147 ///////////////////////////////////////////////////////////////////////////////
2148 //
2149 //  predefine_macro(): predefine a single macro
2150 //
2151 ///////////////////////////////////////////////////////////////////////////////
2152 template <typename ContextT>
2153 inline void
2154 macromap<ContextT>::predefine_macro(defined_macros_type *scope,
2155     string_type const &name, token_type const &t)
2156 {
2157 definition_container_type macrodefinition;
2158 std::vector<token_type> param;
2159 
2160     macrodefinition.push_back(t);
2161     add_macro(token_type(T_IDENTIFIER, name, t.get_position()),
2162         false, param, macrodefinition, true, scope);
2163 }
2164 
2165 ///////////////////////////////////////////////////////////////////////////////
2166 //
2167 //  init_predefined_macros(): init the predefined macros
2168 //
2169 ///////////////////////////////////////////////////////////////////////////////
2170 template <typename ContextT>
2171 inline void
2172 macromap<ContextT>::init_predefined_macros(char const *fname,
2173     defined_macros_type *scope, bool at_global_scope)
2174 {
2175     // if no scope is given, use the current one
2176     defined_macros_type* current_scope = scope ? scope : current_macros;
2177 
2178     // first, add the static macros
2179     position_type pos("<built-in>");
2180 
2181 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
2182     if (boost::wave::need_c99(ctx.get_language())) {
2183         // define C99 specifics
2184         for (int i = 0; 0 != predef.static_data_c99(i).name; ++i) {
2185             predefined_macros::static_macros const& m = predef.static_data_c99(i);
2186             predefine_macro(current_scope, m.name,
2187                 token_type(m.token_id, m.value, pos));
2188         }
2189     }
2190     else
2191 #endif
2192     {
2193 #if BOOST_WAVE_SUPPORT_CPP0X != 0
2194         if (boost::wave::need_cpp0x(ctx.get_language())) {
2195             // define C++11 specifics
2196             for (int i = 0; 0 != predef.static_data_cpp0x(i).name; ++i) {
2197                 predefined_macros::static_macros const& m = predef.static_data_cpp0x(i);
2198                 predefine_macro(current_scope, m.name,
2199                     token_type(m.token_id, m.value, pos));
2200             }
2201         }
2202         else
2203 #endif
2204 #if BOOST_WAVE_SUPPORT_CPP2A != 0
2205             if (boost::wave::need_cpp2a(ctx.get_language())) {
2206             // define C++20 specifics
2207             for (int i = 0; 0 != predef.static_data_cpp2a(i).name; ++i) {
2208                 predefined_macros::static_macros const& m = predef.static_data_cpp2a(i);
2209                 predefine_macro(current_scope, m.name,
2210                     token_type(m.token_id, m.value, pos));
2211             }
2212         }
2213         else
2214 #endif
2215         {
2216             // define C++ specifics
2217             for (int i = 0; 0 != predef.static_data_cpp(i).name; ++i) {
2218                 predefined_macros::static_macros const& m = predef.static_data_cpp(i);
2219                 predefine_macro(current_scope, m.name,
2220                     token_type(m.token_id, m.value, pos));
2221             }
2222 
2223 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
2224             // define __WAVE_HAS_VARIADICS__, if appropriate
2225             if (boost::wave::need_variadics(ctx.get_language())) {
2226                 predefine_macro(current_scope, "__WAVE_HAS_VARIADICS__",
2227                     token_type(T_INTLIT, "1", pos));
2228             }
2229 #endif
2230         }
2231     }
2232 
2233     // predefine the __BASE_FILE__ macro which contains the main file name
2234     namespace fs = boost::filesystem;
2235     if (string_type(fname) != "<Unknown>") {
2236         fs::path filename(create_path(fname));
2237 
2238         using boost::wave::util::impl::escape_lit;
2239         predefine_macro(current_scope, "__BASE_FILE__",
2240             token_type(T_STRINGLIT, string_type("\"") +
2241                 escape_lit(native_file_string(filename)).c_str() + "\"", pos));
2242         base_name = fname;
2243     }
2244     else if (!base_name.empty()) {
2245         fs::path filename(create_path(base_name.c_str()));
2246 
2247         using boost::wave::util::impl::escape_lit;
2248         predefine_macro(current_scope, "__BASE_FILE__",
2249             token_type(T_STRINGLIT, string_type("\"") +
2250                 escape_lit(native_file_string(filename)).c_str() + "\"", pos));
2251     }
2252 
2253     // now add the dynamic macros
2254     for (int j = 0; 0 != predef.dynamic_data(j).name; ++j) {
2255         predefined_macros::dynamic_macros const& m = predef.dynamic_data(j);
2256         predefine_macro(current_scope, m.name,
2257             token_type(m.token_id, (predef.* m.generator)(), pos));
2258     }
2259 }
2260 
2261 ///////////////////////////////////////////////////////////////////////////////
2262 //
2263 //  reset_macromap(): initialize the internal macro symbol namespace
2264 //
2265 ///////////////////////////////////////////////////////////////////////////////
2266 template <typename ContextT>
2267 inline void
2268 macromap<ContextT>::reset_macromap()
2269 {
2270     current_macros->clear();
2271     predef.reset();
2272     act_token = token_type();
2273 }
2274 
2275 ///////////////////////////////////////////////////////////////////////////////
2276 }}}   // namespace boost::wave::util
2277 
2278 #if BOOST_WAVE_SERIALIZATION != 0
2279 namespace boost { namespace serialization {
2280 
2281 template<typename ContextT>
2282 struct version<boost::wave::util::macromap<ContextT> >
2283 {
2284     typedef boost::wave::util::macromap<ContextT> target_type;
2285     typedef mpl::int_<target_type::version> type;
2286     typedef mpl::integral_c_tag tag;
2287     BOOST_STATIC_CONSTANT(unsigned int, value = version::type::value);
2288 };
2289 
2290 }}    // namespace boost::serialization
2291 #endif
2292 
2293 // the suffix header occurs after all of the code
2294 #ifdef BOOST_HAS_ABI_HEADERS
2295 #include BOOST_ABI_SUFFIX
2296 #endif
2297 
2298 #endif // !defined(BOOST_CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED)