LCOV - code coverage report
Current view: top level - usr/include/boost/wave/util - cpp_macromap.hpp (source / functions) Hit Total Coverage
Test: ROSE Lines: 0 547 0.0 %
Date: 2022-12-08 13:48:47 Functions: 0 31 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*=============================================================================
       2             :     Boost.Wave: A Standard compliant C++ preprocessor library
       3             : 
       4             :     Macro expansion engine
       5             : 
       6             :     http://www.boost.org/
       7             : 
       8             :     Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
       9             :     Software License, Version 1.0. (See accompanying file
      10             :     LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      11             : =============================================================================*/
      12             : 
      13             : #if !defined(CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED)
      14             : #define CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED
      15             : 
      16             : #include <cstdlib>
      17             : #include <cstdio>
      18             : #include <ctime>
      19             : 
      20             : #include <list>
      21             : #include <map>
      22             : #include <set>
      23             : #include <vector>
      24             : #include <iterator>
      25             : #include <algorithm>
      26             : 
      27             : #include <boost/assert.hpp>
      28             : #include <boost/wave/wave_config.hpp>
      29             : #if BOOST_WAVE_SERIALIZATION != 0
      30             : #include <boost/serialization/serialization.hpp>
      31             : #include <boost/serialization/shared_ptr.hpp>
      32             : #endif
      33             : 
      34             : #include <boost/filesystem/path.hpp>
      35             : #include <boost/lexical_cast.hpp>
      36             : 
      37             : #include <boost/wave/util/time_conversion_helper.hpp>
      38             : #include <boost/wave/util/unput_queue_iterator.hpp>
      39             : #include <boost/wave/util/macro_helpers.hpp>
      40             : #include <boost/wave/util/macro_definition.hpp>
      41             : #include <boost/wave/util/symbol_table.hpp>
      42             : #include <boost/wave/util/cpp_macromap_utils.hpp>
      43             : #include <boost/wave/util/cpp_macromap_predef.hpp>
      44             : #include <boost/wave/util/filesystem_compatibility.hpp>
      45             : #include <boost/wave/grammars/cpp_defined_grammar_gen.hpp>
      46             : 
      47             : #include <boost/wave/wave_version.hpp>
      48             : #include <boost/wave/cpp_exceptions.hpp>
      49             : #include <boost/wave/language_support.hpp>
      50             : 
      51             : // this must occur after all of the includes and before any code appears
      52             : #ifdef BOOST_HAS_ABI_HEADERS
      53             : #include BOOST_ABI_PREFIX
      54             : #endif
      55             : 
      56             : ///////////////////////////////////////////////////////////////////////////////
      57             : namespace boost { namespace wave { namespace util {
      58             : 
      59             : ///////////////////////////////////////////////////////////////////////////////
      60             : //
      61             : //  macromap
      62             : //
      63             : //      This class holds all currently defined macros and on demand expands
      64             : //      those macro definitions
      65             : //
      66             : ///////////////////////////////////////////////////////////////////////////////
      67             : template <typename ContextT>
      68             : class macromap {
      69             : 
      70             :     typedef macromap<ContextT>                      self_type;
      71             :     typedef typename ContextT::token_type           token_type;
      72             :     typedef typename token_type::string_type        string_type;
      73             :     typedef typename token_type::position_type      position_type;
      74             : 
      75             :     typedef typename ContextT::token_sequence_type  definition_container_type;
      76             :     typedef std::vector<token_type>                 parameter_container_type;
      77             : 
      78             :     typedef macro_definition<token_type, definition_container_type>
      79             :         macro_definition_type;
      80             :     typedef symbol_table<string_type, macro_definition_type>
      81             :         defined_macros_type;
      82             :     typedef typename defined_macros_type::value_type::second_type
      83             :         macro_ref_type;
      84             : 
      85             : public:
      86           0 :     macromap(ContextT &ctx_)
      87           0 :     :   current_macros(0), defined_macros(new defined_macros_type(1)),
      88           0 :         main_pos("", 0), ctx(ctx_), macro_uid(1)
      89             :     {
      90           0 :         current_macros = defined_macros.get();
      91           0 :     }
      92           0 :     ~macromap() {}
      93             : 
      94             : //  Add a new macro to the given macro scope
      95             :     bool add_macro(token_type const &name, bool has_parameters,
      96             :         parameter_container_type &parameters,
      97             :         definition_container_type &definition, bool is_predefined = false,
      98             :         defined_macros_type *scope = 0);
      99             : 
     100             : //  Tests, whether the given macro name is defined in the given macro scope
     101             :     bool is_defined(string_type const &name,
     102             :         typename defined_macros_type::iterator &it,
     103             :         defined_macros_type *scope = 0) const;
     104             : 
     105             : // expects a token sequence as its parameters
     106             :     template <typename IteratorT>
     107             :     bool is_defined(IteratorT const &begin, IteratorT const &end) const;
     108             : 
     109             : // expects an arbitrary string as its parameter
     110             :     bool is_defined(string_type const &str) const;
     111             : 
     112             : //  Get the macro definition for the given macro scope
     113             :     bool get_macro(string_type const &name, bool &has_parameters,
     114             :         bool &is_predefined, position_type &pos,
     115             :         parameter_container_type &parameters,
     116             :         definition_container_type &definition,
     117             :         defined_macros_type *scope = 0) const;
     118             : 
     119             : //  Remove a macro name from the given macro scope
     120             :     bool remove_macro(string_type const &name, position_type const& pos,
     121             :         bool even_predefined = false);
     122             : 
     123             :     template <typename IteratorT, typename ContainerT>
     124             :     token_type const &expand_tokensequence(IteratorT &first,
     125             :         IteratorT const &last, ContainerT &pending, ContainerT &expanded,
     126             :         bool& seen_newline, bool expand_operator_defined);
     127             : 
     128             : //  Expand all macros inside the given token sequence
     129             :     template <typename IteratorT, typename ContainerT>
     130             :     void expand_whole_tokensequence(ContainerT &expanded,
     131             :         IteratorT &first, IteratorT const &last,
     132             :         bool expand_operator_defined);
     133             : 
     134             : //  Init the predefined macros (add them to the given scope)
     135             :     void init_predefined_macros(char const *fname = "<Unknown>",
     136             :         defined_macros_type *scope = 0, bool at_global_scope = true);
     137             :     void predefine_macro(defined_macros_type *scope, string_type const &name,
     138             :         token_type const &t);
     139             : 
     140             : //  Init the internal macro symbol namespace
     141             :     void reset_macromap();
     142             : 
     143           0 :     position_type &get_main_pos() { return main_pos; }
     144             :     position_type const& get_main_pos() const { return main_pos; }
     145             : 
     146             : //  interface for macro name introspection
     147             :     typedef typename defined_macros_type::name_iterator name_iterator;
     148             :     typedef typename defined_macros_type::const_name_iterator const_name_iterator;
     149             : 
     150             :     name_iterator begin()
     151             :         { return defined_macros_type::make_iterator(current_macros->begin()); }
     152             :     name_iterator end()
     153             :         { return defined_macros_type::make_iterator(current_macros->end()); }
     154             :     const_name_iterator begin() const
     155             :         { return defined_macros_type::make_iterator(current_macros->begin()); }
     156             :     const_name_iterator end() const
     157             :         { return defined_macros_type::make_iterator(current_macros->end()); }
     158             : 
     159             : protected:
     160             : //  Helper functions for expanding all macros in token sequences
     161             :     template <typename IteratorT, typename ContainerT>
     162             :     token_type const &expand_tokensequence_worker(ContainerT &pending,
     163             :         unput_queue_iterator<IteratorT, token_type, ContainerT> &first,
     164             :         unput_queue_iterator<IteratorT, token_type, ContainerT> const &last,
     165             :         bool& seen_newline, bool expand_operator_defined);
     166             : 
     167             : //  Collect all arguments supplied to a macro invocation
     168             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
     169             :     template <typename IteratorT, typename ContainerT, typename SizeT>
     170             :     typename std::vector<ContainerT>::size_type collect_arguments (
     171             :         token_type const curr_token, std::vector<ContainerT> &arguments,
     172             :         IteratorT &next, IteratorT const &end, SizeT const &parameter_count,
     173             :         bool& seen_newline);
     174             : #else
     175             :     template <typename IteratorT, typename ContainerT, typename SizeT>
     176             :     typename std::vector<ContainerT>::size_type collect_arguments (
     177             :         token_type const curr_token, std::vector<ContainerT> &arguments,
     178             :         IteratorT &next, IteratorT &endparen, IteratorT const &end,
     179             :         SizeT const &parameter_count, bool& seen_newline);
     180             : #endif
     181             : 
     182             : //  Expand a single macro name
     183             :     template <typename IteratorT, typename ContainerT>
     184             :     bool expand_macro(ContainerT &pending, token_type const &name,
     185             :         typename defined_macros_type::iterator it,
     186             :         IteratorT &first, IteratorT const &last,
     187             :         bool& seen_newline, bool expand_operator_defined,
     188             :         defined_macros_type *scope = 0, ContainerT *queue_symbol = 0);
     189             : 
     190             : //  Expand a predefined macro (__LINE__, __FILE__ and __INCLUDE_LEVEL__)
     191             :     template <typename ContainerT>
     192             :     bool expand_predefined_macro(token_type const &curr_token,
     193             :         ContainerT &expanded);
     194             : 
     195             : //  Expand a single macro argument
     196             :     template <typename ContainerT>
     197             :     void expand_argument (typename std::vector<ContainerT>::size_type arg,
     198             :         std::vector<ContainerT> &arguments,
     199             :         std::vector<ContainerT> &expanded_args, bool expand_operator_defined,
     200             :         std::vector<bool> &has_expanded_args);
     201             : 
     202             : //  Expand the replacement list (replaces parameters with arguments)
     203             :     template <typename ContainerT>
     204             :     void expand_replacement_list(
     205             :         macro_definition_type const &macrodefinition,
     206             :         std::vector<ContainerT> &arguments,
     207             :         bool expand_operator_defined, ContainerT &expanded);
     208             : 
     209             : //  Rescans the replacement list for macro expansion
     210             :     template <typename IteratorT, typename ContainerT>
     211             :     void rescan_replacement_list(token_type const &curr_token,
     212             :         macro_definition_type &macrodef, ContainerT &replacement_list,
     213             :         ContainerT &expanded, bool expand_operator_defined,
     214             :         IteratorT &nfirst, IteratorT const &nlast);
     215             : 
     216             : //  Resolves the operator defined() and replces the token with "0" or "1"
     217             :     template <typename IteratorT, typename ContainerT>
     218             :     token_type const &resolve_defined(IteratorT &first, IteratorT const &last,
     219             :         ContainerT &expanded);
     220             : 
     221             : //  Resolve operator _Pragma or the #pragma directive
     222             :     template <typename IteratorT, typename ContainerT>
     223             :     bool resolve_operator_pragma(IteratorT &first,
     224             :         IteratorT const &last, ContainerT &expanded, bool& seen_newline);
     225             : 
     226             : //  Handle the concatenation operator '##'
     227             :     template <typename ContainerT>
     228             :     bool concat_tokensequence(ContainerT &expanded);
     229             : 
     230             :     template <typename ContainerT>
     231             :     bool is_valid_concat(string_type new_value,
     232             :         position_type const &pos, ContainerT &rescanned);
     233             : 
     234             : #if BOOST_WAVE_SERIALIZATION != 0
     235             : public:
     236             :     BOOST_STATIC_CONSTANT(unsigned int, version = 0x10);
     237             :     BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f);
     238             : 
     239             : private:
     240             :     friend class boost::serialization::access;
     241             :     template<typename Archive>
     242             :     void save(Archive &ar, const unsigned int version) const
     243             :     {
     244             :         using namespace boost::serialization;
     245             :         ar & make_nvp("defined_macros", defined_macros);
     246             :     }
     247             :     template<typename Archive>
     248             :     void load(Archive &ar, const unsigned int loaded_version)
     249             :     {
     250             :         using namespace boost::serialization;
     251             :         if (version != (loaded_version & ~version_mask)) {
     252             :             BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
     253             :                 "cpp_context state version", get_main_pos());
     254             :         }
     255             :         ar & make_nvp("defined_macros", defined_macros);
     256             :         current_macros = defined_macros.get();
     257             :     }
     258             :     BOOST_SERIALIZATION_SPLIT_MEMBER()
     259             : #endif
     260             : 
     261             : private:
     262             :     defined_macros_type *current_macros;                   // current symbol table
     263             :     boost::shared_ptr<defined_macros_type> defined_macros; // global symbol table
     264             : 
     265             :     token_type act_token;       // current token
     266             :     position_type main_pos;     // last token position in the pp_iterator
     267             :     string_type base_name;      // the name to be expanded by __BASE_FILE__
     268             :     ContextT &ctx;              // context object associated with the macromap
     269             :     long macro_uid;
     270             :     predefined_macros predef;   // predefined macro support
     271             : };
     272             : ///////////////////////////////////////////////////////////////////////////////
     273             : 
     274             : ///////////////////////////////////////////////////////////////////////////////
     275             : //
     276             : //  add_macro(): adds a new macro to the macromap
     277             : //
     278             : ///////////////////////////////////////////////////////////////////////////////
     279             : template <typename ContextT>
     280             : inline bool
     281           0 : macromap<ContextT>::add_macro(token_type const &name, bool has_parameters,
     282             :     parameter_container_type &parameters, definition_container_type &definition,
     283             :     bool is_predefined, defined_macros_type *scope)
     284             : {
     285           0 :     if (!is_predefined && impl::is_special_macroname (name.get_value())) {
     286             :     // exclude special macro names
     287           0 :         BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
     288             :             illegal_redefinition, name.get_value().c_str(), main_pos,
     289             :             name.get_value().c_str());
     290             :         return false;
     291             :     }
     292           0 :     if (boost::wave::need_variadics(ctx.get_language()) &&
     293           0 :         "__VA_ARGS__" == name.get_value())
     294             :     {
     295             :     // can't use __VA_ARGS__ as a macro name
     296           0 :         BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
     297             :             bad_define_statement_va_args, name.get_value().c_str(), main_pos,
     298             :             name.get_value().c_str());
     299             :         return false;
     300             :     }
     301           0 :     if (AltExtTokenType == (token_id(name) & ExtTokenOnlyMask)) {
     302             :     // exclude special operator names
     303           0 :         BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
     304             :             illegal_operator_redefinition, name.get_value().c_str(), main_pos,
     305             :             name.get_value().c_str());
     306             :         return false;
     307             :     }
     308             : 
     309             : // try to define the new macro
     310           0 : defined_macros_type *current_scope = scope ? scope : current_macros;
     311           0 : typename defined_macros_type::iterator it = current_scope->find(name.get_value());
     312             : 
     313           0 :     if (it != current_scope->end()) {
     314             :     // redefinition, should not be different
     315           0 :         macro_definition_type* macrodef = (*it).second.get();
     316           0 :         if (macrodef->is_functionlike != has_parameters ||
     317           0 :             !impl::parameters_equal(macrodef->macroparameters, parameters) ||
     318           0 :             !impl::definition_equals(macrodef->macrodefinition, definition))
     319             :         {
     320           0 :             BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
     321             :                 macro_redefinition, name.get_value().c_str(), main_pos,
     322             :                 name.get_value().c_str());
     323             :         }
     324             :         return false;
     325             :     }
     326             : 
     327             : // test the validity of the parameter names
     328           0 :     if (has_parameters) {
     329           0 :         std::set<typename token_type::string_type> names;
     330             : 
     331             :         typedef typename parameter_container_type::iterator
     332             :             parameter_iterator_type;
     333             :         typedef typename std::set<typename token_type::string_type>::iterator
     334             :             name_iterator_type;
     335             : 
     336           0 :         parameter_iterator_type end = parameters.end();
     337           0 :         for (parameter_iterator_type itp = parameters.begin(); itp != end; ++itp)
     338             :         {
     339           0 :         name_iterator_type pit = names.find((*itp).get_value());
     340             : 
     341           0 :             if (pit != names.end()) {
     342             :             // duplicate parameter name
     343           0 :                 BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
     344             :                     duplicate_parameter_name, (*pit).c_str(), main_pos,
     345             :                     name.get_value().c_str());
     346             :                 return false;
     347             :             }
     348           0 :             names.insert((*itp).get_value());
     349             :         }
     350             :     }
     351             : 
     352             : // insert a new macro node
     353           0 :     std::pair<typename defined_macros_type::iterator, bool> p =
     354             :         current_scope->insert(
     355           0 :             typename defined_macros_type::value_type(
     356             :                 name.get_value(),
     357           0 :                 macro_ref_type(new macro_definition_type(name,
     358           0 :                     has_parameters, is_predefined, ++macro_uid)
     359             :                 )
     360             :             )
     361             :         );
     362             : 
     363           0 :     if (!p.second) {
     364           0 :         BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
     365             :             macro_insertion_error, name.get_value().c_str(), main_pos,
     366             :             name.get_value().c_str());
     367             :         return false;
     368             :     }
     369             : 
     370             : // add the parameters and the definition
     371           0 :     std::swap((*p.first).second->macroparameters, parameters);
     372           0 :     std::swap((*p.first).second->macrodefinition, definition);
     373             : 
     374             : // call the context supplied preprocessing hook
     375             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
     376             :     ctx.get_hooks().defined_macro(name, has_parameters,
     377             :         (*p.first).second->macroparameters,
     378             :         (*p.first).second->macrodefinition, is_predefined);
     379             : #else
     380           0 :     ctx.get_hooks().defined_macro(ctx.derived(), name, has_parameters,
     381           0 :         (*p.first).second->macroparameters,
     382           0 :         (*p.first).second->macrodefinition, is_predefined);
     383             : #endif
     384             :     return true;
     385             : }
     386             : 
     387             : ///////////////////////////////////////////////////////////////////////////////
     388             : //
     389             : //  is_defined(): returns, whether a given macro is already defined
     390             : //
     391             : ///////////////////////////////////////////////////////////////////////////////
     392             : template <typename ContextT>
     393             : inline bool
     394           0 : macromap<ContextT>::is_defined(typename token_type::string_type const &name,
     395             :     typename defined_macros_type::iterator &it,
     396             :     defined_macros_type *scope) const
     397             : {
     398           0 :     if (0 == scope) scope = current_macros;
     399             : 
     400           0 :     if ((it = scope->find(name)) != scope->end())
     401             :         return true;        // found in symbol table
     402             : 
     403             : // quick pre-check
     404           0 :     if (name.size() < 8 || '_' != name[0] || '_' != name[1])
     405             :         return false;       // quick check failed
     406             : 
     407           0 :     return name == "__LINE__" || name == "__FILE__" ||
     408           0 :         name == "__INCLUDE_LEVEL__";
     409             : }
     410             : 
     411             : template <typename ContextT>
     412             : template <typename IteratorT>
     413             : inline bool
     414           0 : macromap<ContextT>::is_defined(IteratorT const &begin,
     415             :     IteratorT const &end) const
     416             : {
     417             : // in normal mode the name under inspection should consist of an identifier
     418             : // only
     419           0 : token_id id = token_id(*begin);
     420             : 
     421           0 :     if (T_IDENTIFIER != id &&
     422           0 :         !IS_CATEGORY(id, KeywordTokenType) &&
     423           0 :         !IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) &&
     424             :         !IS_CATEGORY(id, BoolLiteralTokenType))
     425             :     {
     426           0 :         std::string msg(impl::get_full_name(begin, end));
     427           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_macroname,
     428             :             msg.c_str(), main_pos);
     429           0 :         return false;
     430             :     }
     431             : 
     432           0 : IteratorT it = begin;
     433           0 : string_type name ((*it).get_value());
     434           0 : typename defined_macros_type::iterator cit;
     435             : 
     436           0 :     if (++it != end) {
     437             :     // there should be only one token as the inspected name
     438           0 :         std::string msg(impl::get_full_name(begin, end));
     439           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_macroname,
     440             :             msg.c_str(), main_pos);
     441           0 :         return false;
     442             :     }
     443           0 :     return is_defined(name, cit, 0);
     444             : }
     445             : 
     446             : ///////////////////////////////////////////////////////////////////////////////
     447             : //  same as above, only takes an arbitrary string type as its parameter
     448             : template <typename ContextT>
     449             : inline bool
     450           0 : macromap<ContextT>::is_defined(string_type const &str) const
     451             : {
     452           0 :     typename defined_macros_type::iterator cit;
     453           0 :     return is_defined(str, cit, 0);
     454             : }
     455             : 
     456             : ///////////////////////////////////////////////////////////////////////////////
     457             : //
     458             : //  Get the macro definition for the given macro scope
     459             : //
     460             : ///////////////////////////////////////////////////////////////////////////////
     461             : template <typename ContextT>
     462             : inline bool
     463             : macromap<ContextT>::get_macro(string_type const &name, bool &has_parameters,
     464             :     bool &is_predefined, position_type &pos,
     465             :     parameter_container_type &parameters,
     466             :     definition_container_type &definition,
     467             :     defined_macros_type *scope) const
     468             : {
     469             :     typename defined_macros_type::iterator it;
     470             :     if (!is_defined(name, it, scope))
     471             :         return false;
     472             : 
     473             : macro_definition_type &macro_def = *(*it).second.get();
     474             : 
     475             :     has_parameters = macro_def.is_functionlike;
     476             :     is_predefined = macro_def.is_predefined;
     477             :     pos = macro_def.macroname.get_position();
     478             :     parameters = macro_def.macroparameters;
     479             :     definition = macro_def.macrodefinition;
     480             :     return true;
     481             : }
     482             : 
     483             : ///////////////////////////////////////////////////////////////////////////////
     484             : //
     485             : //  remove_macro(): remove a macro from the macromap
     486             : //
     487             : ///////////////////////////////////////////////////////////////////////////////
     488             : template <typename ContextT>
     489             : inline bool
     490           0 : macromap<ContextT>::remove_macro(string_type const &name,
     491             :     position_type const& pos, bool even_predefined)
     492             : {
     493           0 :     typename defined_macros_type::iterator it = current_macros->find(name);
     494             : 
     495           0 :     if (it != current_macros->end()) {
     496           0 :         if ((*it).second->is_predefined) {
     497           0 :             if (!even_predefined || impl::is_special_macroname(name)) {
     498           0 :                 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
     499             :                     bad_undefine_statement, name.c_str(), main_pos);
     500           0 :                 return false;
     501             :             }
     502             :         }
     503           0 :         current_macros->erase(it);
     504             : 
     505             :     // call the context supplied preprocessing hook function
     506           0 :     token_type tok(T_IDENTIFIER, name, pos);
     507             : 
     508             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
     509             :         ctx.get_hooks().undefined_macro(tok);
     510             : #else
     511           0 :         ctx.get_hooks().undefined_macro(ctx.derived(), tok);
     512             : #endif
     513             :         return true;
     514             :     }
     515           0 :     else if (impl::is_special_macroname(name)) {
     516           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_undefine_statement,
     517             :             name.c_str(), pos);
     518             :     }
     519             :     return false;       // macro was not defined
     520             : }
     521             : 
     522             : ///////////////////////////////////////////////////////////////////////////////
     523             : //
     524             : //  expand_tokensequence
     525             : //
     526             : //      This function is a helper function which wraps the given iterator
     527             : //      range into corresponding unput_iterator's and calls the main workhorse
     528             : //      of the macro expansion engine (the function expand_tokensequence_worker)
     529             : //
     530             : //      This is the top level macro expansion function called from the
     531             : //      preprocessing iterator component only.
     532             : //
     533             : ///////////////////////////////////////////////////////////////////////////////
     534             : template <typename ContextT>
     535             : template <typename IteratorT, typename ContainerT>
     536             : inline typename ContextT::token_type const &
     537           0 : macromap<ContextT>::expand_tokensequence(IteratorT &first,
     538             :     IteratorT const &last, ContainerT &pending, ContainerT &expanded,
     539             :     bool& seen_newline, bool expand_operator_defined)
     540             : {
     541             :     typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT>
     542             :         gen_type;
     543             :     typedef typename gen_type::return_type iterator_type;
     544             : 
     545           0 :     iterator_type first_it = gen_type::generate(expanded, first);
     546           0 :     iterator_type last_it = gen_type::generate(last);
     547             : 
     548           0 : on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
     549             : 
     550             :     return expand_tokensequence_worker(pending, first_it, last_it,
     551           0 :         seen_newline, expand_operator_defined);
     552             : }
     553             : 
     554             : ///////////////////////////////////////////////////////////////////////////////
     555             : //
     556             : //  expand_tokensequence_worker
     557             : //
     558             : //      This function is the main workhorse of the macro expansion engine. It
     559             : //      expands as much tokens as needed to identify the next preprocessed
     560             : //      token to return to the caller.
     561             : //      It returns the next preprocessed token.
     562             : //
     563             : //      The iterator 'first' is adjusted accordingly.
     564             : //
     565             : ///////////////////////////////////////////////////////////////////////////////
     566             : template <typename ContextT>
     567             : template <typename IteratorT, typename ContainerT>
     568             : inline typename ContextT::token_type const &
     569           0 : macromap<ContextT>::expand_tokensequence_worker(
     570             :     ContainerT &pending,
     571             :     unput_queue_iterator<IteratorT, token_type, ContainerT> &first,
     572             :     unput_queue_iterator<IteratorT, token_type, ContainerT> const &last,
     573             :     bool& seen_newline, bool expand_operator_defined)
     574             : {
     575             : // if there exist pending tokens (tokens, which are already preprocessed), then
     576             : // return the next one from there
     577           0 :     if (!pending.empty()) {
     578           0 :     on_exit::pop_front<definition_container_type> pop_front_token(pending);
     579             : 
     580           0 :         return act_token = pending.front();
     581             :     }
     582             : 
     583             : //  analyze the next element of the given sequence, if it is an
     584             : //  T_IDENTIFIER token, try to replace this as a macro etc.
     585             :     using namespace boost::wave;
     586             : 
     587           0 :     if (first != last) {
     588           0 :     token_id id = token_id(*first);
     589             : 
     590             :     // ignore placeholder tokens
     591           0 :         if (T_PLACEHOLDER == id) {
     592           0 :         token_type placeholder = *first;
     593             : 
     594           0 :             ++first;
     595           0 :             if (first == last)
     596           0 :                 return act_token = placeholder;
     597           0 :             id = token_id(*first);
     598             :         }
     599             : 
     600           0 :         if (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType) ||
     601           0 :             IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
     602             :             IS_CATEGORY(id, BoolLiteralTokenType))
     603             :         {
     604             :         // try to replace this identifier as a macro
     605           0 :             if (expand_operator_defined && (*first).get_value() == "defined") {
     606             :             // resolve operator defined()
     607           0 :                 return resolve_defined(first, last, pending);
     608             :             }
     609           0 :             else if (boost::wave::need_variadics(ctx.get_language()) &&
     610           0 :                 (*first).get_value() == "_Pragma")
     611             :             {
     612             :             // in C99 mode only: resolve the operator _Pragma
     613           0 :             token_type curr_token = *first;
     614             : 
     615           0 :                 if (!resolve_operator_pragma(first, last, pending, seen_newline) ||
     616           0 :                     pending.size() > 0)
     617             :                 {
     618             :                 // unknown to us pragma or supplied replacement, return the
     619             :                 // next token
     620           0 :                 on_exit::pop_front<definition_container_type> pop_token(pending);
     621             : 
     622           0 :                     return act_token = pending.front();
     623             :                 }
     624             : 
     625             :             // the operator _Pragma() was eaten completely, continue
     626           0 :                 return act_token = token_type(T_PLACEHOLDER, "_",
     627             :                     curr_token.get_position());
     628             :             }
     629             : 
     630           0 :         token_type name_token (*first);
     631           0 :         typename defined_macros_type::iterator it;
     632             : 
     633           0 :             if (is_defined(name_token.get_value(), it)) {
     634             :             // the current token contains an identifier, which is currently
     635             :             // defined as a macro
     636           0 :                 if (expand_macro(pending, name_token, it, first, last,
     637             :                       seen_newline, expand_operator_defined))
     638             :                 {
     639             :                 // the tokens returned by expand_macro should be rescanned
     640             :                 // beginning at the last token of the returned replacement list
     641           0 :                     if (first != last) {
     642             :                     // splice the last token back into the input queue
     643           0 :                     typename ContainerT::reverse_iterator rit = pending.rbegin();
     644             : 
     645           0 :                         first.get_unput_queue().splice(
     646           0 :                             first.get_unput_queue().begin(), pending,
     647           0 :                             (++rit).base(), pending.end());
     648             :                     }
     649             : 
     650             :                 // fall through ...
     651             :                 }
     652           0 :                 else if (!pending.empty()) {
     653             :                 // return the first token from the pending queue
     654           0 :                 on_exit::pop_front<definition_container_type> pop_queue (pending);
     655             : 
     656           0 :                     return act_token = pending.front();
     657             :                 }
     658             :                 else {
     659             :                 // macro expansion reached the eoi
     660           0 :                     return act_token = token_type();
     661             :                 }
     662             : 
     663             :             // return the next preprocessed token
     664             :                 return expand_tokensequence_worker(pending, first, last,
     665           0 :                     seen_newline, expand_operator_defined);
     666             :             }
     667             : //            else if (expand_operator_defined) {
     668             : //            // in preprocessing conditionals undefined identifiers and keywords
     669             : //            // are to be replaced with '0' (see. C++ standard 16.1.4, [cpp.cond])
     670             : //                return act_token =
     671             : //                    token_type(T_INTLIT, "0", (*first++).get_position());
     672             : //            }
     673             :             else {
     674           0 :                 act_token = name_token;
     675           0 :                 ++first;
     676           0 :                 return act_token;
     677             :             }
     678             :         }
     679           0 :         else if (expand_operator_defined && IS_CATEGORY(*first, BoolLiteralTokenType)) {
     680             :         // expanding a constant expression inside #if/#elif, special handling
     681             :         // of 'true' and 'false'
     682             : 
     683             :         // all remaining identifiers and keywords, except for true and false,
     684             :         // are replaced with the pp-number 0 (C++ standard 16.1.4, [cpp.cond])
     685           0 :             return act_token = token_type(T_INTLIT, T_TRUE != id ? "0" : "1",
     686           0 :                 (*first++).get_position());
     687             :         }
     688             :         else {
     689           0 :             act_token = *first;
     690           0 :             ++first;
     691           0 :             return act_token;
     692             :         }
     693             :     }
     694           0 :     return act_token = token_type();     // eoi
     695             : }
     696             : 
     697             : ///////////////////////////////////////////////////////////////////////////////
     698             : //
     699             : //  collect_arguments(): collect the actual arguments of a macro invocation
     700             : //
     701             : //      return the number of successfully detected non-empty arguments
     702             : //
     703             : ///////////////////////////////////////////////////////////////////////////////
     704             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
     705             : template <typename ContextT>
     706             : template <typename IteratorT, typename ContainerT, typename SizeT>
     707             : inline typename std::vector<ContainerT>::size_type
     708             : macromap<ContextT>::collect_arguments (token_type const curr_token,
     709             :     std::vector<ContainerT> &arguments, IteratorT &next,
     710             :     IteratorT const &end, SizeT const &parameter_count, bool& seen_newline)
     711             : #else
     712             : template <typename ContextT>
     713             : template <typename IteratorT, typename ContainerT, typename SizeT>
     714             : inline typename std::vector<ContainerT>::size_type
     715           0 : macromap<ContextT>::collect_arguments (token_type const curr_token,
     716             :     std::vector<ContainerT> &arguments, IteratorT &next, IteratorT &endparen,
     717             :     IteratorT const &end, SizeT const &parameter_count, bool& seen_newline)
     718             : #endif
     719             : {
     720             :     using namespace boost::wave;
     721             : 
     722           0 :     arguments.push_back(ContainerT());
     723             : 
     724             : // collect the actual arguments
     725           0 : typename std::vector<ContainerT>::size_type count_arguments = 0;
     726           0 : int nested_parenthesis_level = 1;
     727           0 : ContainerT *argument = &arguments[0];
     728           0 : bool was_whitespace = false;
     729           0 : token_type startof_argument_list = *next;
     730             : 
     731           0 :     while (++next != end && nested_parenthesis_level) {
     732           0 :     token_id id = token_id(*next);
     733             : 
     734           0 :         if (0 == parameter_count &&
     735           0 :             !IS_CATEGORY((*next), WhiteSpaceTokenType) && id != T_NEWLINE &&
     736           0 :             id != T_RIGHTPAREN && id != T_LEFTPAREN)
     737             :         {
     738             :         // there shouldn't be any arguments
     739           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
     740             :                 too_many_macroarguments, curr_token.get_value().c_str(),
     741             :                 main_pos);
     742             :             return 0;
     743             :         }
     744             : 
     745           0 :         switch (id) {
     746           0 :         case T_LEFTPAREN:
     747           0 :             ++nested_parenthesis_level;
     748           0 :             argument->push_back(*next);
     749             :             was_whitespace = false;
     750             :             break;
     751             : 
     752           0 :         case T_RIGHTPAREN:
     753             :             {
     754           0 :                 if (--nested_parenthesis_level >= 1)
     755           0 :                     argument->push_back(*next);
     756             :                 else {
     757             :                 // found closing parenthesis
     758             : //                    trim_sequence(argument);
     759             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
     760           0 :                     endparen = next;
     761             : #endif
     762           0 :                     if (parameter_count > 0) {
     763           0 :                         if (argument->empty() ||
     764           0 :                             impl::is_whitespace_only(*argument))
     765             :                         {
     766             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
     767           0 :                             if (boost::wave::need_variadics(ctx.get_language())) {
     768             :                             // store a placemarker as the argument
     769           0 :                                 argument->push_back(token_type(T_PLACEMARKER, "\xA7",
     770           0 :                                     (*next).get_position()));
     771           0 :                                 ++count_arguments;
     772             :                             }
     773             : #endif
     774             :                         }
     775             :                         else {
     776           0 :                             ++count_arguments;
     777             :                         }
     778             :                     }
     779             :                 }
     780             :                 was_whitespace = false;
     781             :             }
     782             :             break;
     783             : 
     784           0 :         case T_COMMA:
     785           0 :             if (1 == nested_parenthesis_level) {
     786             :             // next parameter
     787             : //                trim_sequence(argument);
     788           0 :                 if (argument->empty() ||
     789           0 :                     impl::is_whitespace_only(*argument))
     790             :                 {
     791             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
     792           0 :                     if (boost::wave::need_variadics(ctx.get_language())) {
     793             :                     // store a placemarker as the argument
     794           0 :                         argument->push_back(token_type(T_PLACEMARKER, "\xA7",
     795           0 :                             (*next).get_position()));
     796           0 :                         ++count_arguments;
     797             :                     }
     798             : #endif
     799             :                 }
     800             :                 else {
     801           0 :                     ++count_arguments;
     802             :                 }
     803           0 :                 arguments.push_back(ContainerT()); // add new arg
     804           0 :                 argument = &arguments[arguments.size()-1];
     805             :             }
     806             :             else {
     807             :             // surrounded by parenthesises, so store to current argument
     808           0 :                 argument->push_back(*next);
     809             :             }
     810             :             was_whitespace = false;
     811             :             break;
     812             : 
     813           0 :         case T_NEWLINE:
     814           0 :             seen_newline = true;
     815             :             /* fall through */
     816           0 :         case T_SPACE:
     817             :         case T_SPACE2:
     818             :         case T_CCOMMENT:
     819           0 :             if (!was_whitespace)
     820           0 :                 argument->push_back(token_type(T_SPACE, " ", (*next).get_position()));
     821           0 :             was_whitespace = true;
     822             :             break;      // skip whitespace
     823             : 
     824             :         case T_PLACEHOLDER:
     825             :             break;      // ignore placeholder
     826             : 
     827           0 :         default:
     828           0 :             argument->push_back(*next);
     829             :             was_whitespace = false;
     830             :             break;
     831             :         }
     832             :     }
     833             : 
     834           0 :     if (nested_parenthesis_level >= 1) {
     835             :     // missing ')': improperly terminated macro invocation
     836           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
     837             :             improperly_terminated_macro, "missing ')'", main_pos);
     838             :         return 0;
     839             :     }
     840             : 
     841             : // if no argument was expected and we didn't find any, than remove the empty
     842             : // element
     843           0 :     if (0 == parameter_count && 0 == count_arguments) {
     844           0 :         BOOST_ASSERT(1 == arguments.size());
     845           0 :         arguments.clear();
     846             :     }
     847             :     return count_arguments;
     848             : }
     849             : 
     850             : ///////////////////////////////////////////////////////////////////////////////
     851             : //
     852             : //  expand_whole_tokensequence
     853             : //
     854             : //      fully expands a given token sequence
     855             : //
     856             : ///////////////////////////////////////////////////////////////////////////////
     857             : template <typename ContextT>
     858             : template <typename IteratorT, typename ContainerT>
     859             : inline void
     860           0 : macromap<ContextT>::expand_whole_tokensequence(ContainerT &expanded,
     861             :     IteratorT &first, IteratorT const &last,
     862             :     bool expand_operator_defined)
     863             : {
     864             :     typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT>
     865             :         gen_type;
     866             :     typedef typename gen_type::return_type iterator_type;
     867             : 
     868           0 :     ContainerT empty;
     869           0 :     iterator_type first_it = gen_type::generate(empty, first);
     870           0 :     iterator_type last_it = gen_type::generate(last);
     871             : 
     872           0 :     on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
     873           0 :     ContainerT pending_queue;
     874             :     bool seen_newline;
     875             : 
     876           0 :     while (!pending_queue.empty() || first_it != last_it) {
     877           0 :         expanded.push_back(
     878             :             expand_tokensequence_worker(pending_queue, first_it,
     879             :                     last_it, seen_newline, expand_operator_defined)
     880             :         );
     881             :     }
     882             : 
     883             : // should have returned all expanded tokens
     884           0 :     BOOST_ASSERT(pending_queue.empty()/* && unput_queue.empty()*/);
     885           0 : }
     886             : 
     887             : ///////////////////////////////////////////////////////////////////////////////
     888             : //
     889             : //  expand_argument
     890             : //
     891             : //      fully expands the given argument of a macro call
     892             : //
     893             : ///////////////////////////////////////////////////////////////////////////////
     894             : template <typename ContextT>
     895             : template <typename ContainerT>
     896             : inline void
     897           0 : macromap<ContextT>::expand_argument (
     898             :     typename std::vector<ContainerT>::size_type arg,
     899             :     std::vector<ContainerT> &arguments, std::vector<ContainerT> &expanded_args,
     900             :     bool expand_operator_defined, std::vector<bool> &has_expanded_args)
     901             : {
     902           0 :     if (!has_expanded_args[arg]) {
     903             :     // expand the argument only once
     904             :         typedef typename std::vector<ContainerT>::value_type::iterator
     905             :             argument_iterator_type;
     906             : 
     907           0 :         argument_iterator_type begin_it = arguments[arg].begin();
     908           0 :         argument_iterator_type end_it = arguments[arg].end();
     909             : 
     910           0 :         expand_whole_tokensequence(expanded_args[arg], begin_it, end_it,
     911             :             expand_operator_defined);
     912           0 :         impl::remove_placeholders(expanded_args[arg]);
     913           0 :         has_expanded_args[arg] = true;
     914             :     }
     915           0 : }
     916             : 
     917             : ///////////////////////////////////////////////////////////////////////////////
     918             : //
     919             : //  expand_replacement_list
     920             : //
     921             : //      fully expands the replacement list of a given macro with the
     922             : //      actual arguments/expanded arguments
     923             : //      handles the '#' [cpp.stringize] and the '##' [cpp.concat] operator
     924             : //
     925             : ///////////////////////////////////////////////////////////////////////////////
     926             : template <typename ContextT>
     927             : template <typename ContainerT>
     928             : inline void
     929           0 : macromap<ContextT>::expand_replacement_list(
     930             :     macro_definition_type const &macrodef,
     931             :     std::vector<ContainerT> &arguments, bool expand_operator_defined,
     932             :     ContainerT &expanded)
     933             : {
     934             :     using namespace boost::wave;
     935             :     typedef typename macro_definition_type::const_definition_iterator_t
     936             :         macro_definition_iter_t;
     937             : 
     938           0 : std::vector<ContainerT> expanded_args(arguments.size());
     939           0 : std::vector<bool> has_expanded_args(arguments.size());
     940           0 : bool seen_concat = false;
     941           0 : bool adjacent_concat = false;
     942           0 : bool adjacent_stringize = false;
     943             : 
     944           0 :     macro_definition_iter_t cend = macrodef.macrodefinition.end();
     945           0 :     for (macro_definition_iter_t cit = macrodef.macrodefinition.begin();
     946           0 :         cit != cend; ++cit)
     947             :     {
     948           0 :     bool use_replaced_arg = true;
     949           0 :     token_id base_id = BASE_TOKEN(token_id(*cit));
     950             : 
     951           0 :         if (T_POUND_POUND == base_id) {
     952             :         // concatenation operator
     953             :             adjacent_concat = true;
     954             :             seen_concat = true;
     955             :         }
     956           0 :         else if (T_POUND == base_id) {
     957             :         // stringize operator
     958             :             adjacent_stringize = true;
     959             :         }
     960             :         else {
     961           0 :             if (adjacent_stringize || adjacent_concat ||
     962             :                 T_POUND_POUND == impl::next_token<macro_definition_iter_t>
     963           0 :                     ::peek(cit, cend))
     964             :             {
     965             :                 use_replaced_arg = false;
     966             :             }
     967           0 :             if (adjacent_concat)    // spaces after '##' ?
     968           0 :                 adjacent_concat = IS_CATEGORY(*cit, WhiteSpaceTokenType);
     969             :         }
     970             : 
     971           0 :         if (IS_CATEGORY((*cit), ParameterTokenType)) {
     972             :         // copy argument 'i' instead of the parameter token i
     973             :         typename ContainerT::size_type i;
     974             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
     975           0 :         bool is_ellipsis = false;
     976             : 
     977           0 :             if (IS_EXTCATEGORY((*cit), ExtParameterTokenType)) {
     978           0 :                 BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
     979           0 :                 i = token_id(*cit) - T_EXTPARAMETERBASE;
     980           0 :                 is_ellipsis = true;
     981             :             }
     982             :             else
     983             : #endif
     984             :             {
     985           0 :                 i = token_id(*cit) - T_PARAMETERBASE;
     986             :             }
     987             : 
     988           0 :             BOOST_ASSERT(i < arguments.size());
     989           0 :             if (use_replaced_arg) {
     990             : 
     991             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
     992           0 :                 if (is_ellipsis) {
     993           0 :                 position_type const &pos = (*cit).get_position();
     994             : 
     995           0 :                     BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
     996             : 
     997             :                 // ensure all variadic arguments to be expanded
     998           0 :                     for (typename vector<ContainerT>::size_type arg = i;
     999           0 :                          arg < expanded_args.size(); ++arg)
    1000             :                     {
    1001           0 :                         expand_argument(arg, arguments, expanded_args,
    1002             :                             expand_operator_defined, has_expanded_args);
    1003             :                     }
    1004           0 :                     impl::replace_ellipsis(expanded_args, i, expanded, pos);
    1005             :                 }
    1006             :                 else
    1007             : #endif
    1008             :                 {
    1009             :                 // ensure argument i to be expanded
    1010           0 :                     expand_argument(i, arguments, expanded_args,
    1011             :                         expand_operator_defined, has_expanded_args);
    1012             : 
    1013             :                 // replace argument
    1014           0 :                 ContainerT const &arg = expanded_args[i];
    1015             : 
    1016           0 :                     std::copy(arg.begin(), arg.end(),
    1017             :                         std::inserter(expanded, expanded.end()));
    1018             :                 }
    1019             :             }
    1020           0 :             else if (adjacent_stringize &&
    1021           0 :                     !IS_CATEGORY(*cit, WhiteSpaceTokenType))
    1022             :             {
    1023             :             // stringize the current argument
    1024           0 :                 BOOST_ASSERT(!arguments[i].empty());
    1025             : 
    1026             :             // safe a copy of the first tokens position (not a reference!)
    1027           0 :             position_type pos ((*arguments[i].begin()).get_position());
    1028             : 
    1029             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1030           0 :                 if (is_ellipsis && boost::wave::need_variadics(ctx.get_language())) {
    1031           0 :                     impl::trim_sequence_left(arguments[i]);
    1032           0 :                     impl::trim_sequence_right(arguments.back());
    1033           0 :                     expanded.push_back(token_type(T_STRINGLIT,
    1034             :                         impl::as_stringlit(arguments, i, pos), pos));
    1035             :                 }
    1036             :                 else
    1037             : #endif
    1038             :                 {
    1039           0 :                     impl::trim_sequence(arguments[i]);
    1040           0 :                     expanded.push_back(token_type(T_STRINGLIT,
    1041           0 :                         impl::as_stringlit(arguments[i], pos), pos));
    1042             :                 }
    1043           0 :                 adjacent_stringize = false;
    1044             :             }
    1045             :             else {
    1046             :             // simply copy the original argument (adjacent '##' or '#')
    1047             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1048           0 :                 if (is_ellipsis) {
    1049           0 :                 position_type const &pos = (*cit).get_position();
    1050             : 
    1051           0 :                     impl::trim_sequence_left(arguments[i]);
    1052           0 :                     impl::trim_sequence_right(arguments.back());
    1053           0 :                     BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
    1054           0 :                     impl::replace_ellipsis(arguments, i, expanded, pos);
    1055             :                 }
    1056             :                 else
    1057             : #endif
    1058             :                 {
    1059           0 :                 ContainerT &arg = arguments[i];
    1060             : 
    1061           0 :                     impl::trim_sequence(arg);
    1062           0 :                     std::copy(arg.begin(), arg.end(),
    1063             :                         std::inserter(expanded, expanded.end()));
    1064             :                 }
    1065             :             }
    1066             :         }
    1067           0 :         else if (!adjacent_stringize || T_POUND != base_id) {
    1068             :         // insert the actual replacement token (if it is not the '#' operator)
    1069           0 :             expanded.push_back(*cit);
    1070             :         }
    1071             :     }
    1072             : 
    1073           0 :     if (adjacent_stringize) {
    1074             :     // error, '#' should not be the last token
    1075           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_operator,
    1076             :             "stringize ('#')", main_pos);
    1077           0 :         return;
    1078             :     }
    1079             : 
    1080             : // handle the cpp.concat operator
    1081           0 :     if (seen_concat)
    1082           0 :         concat_tokensequence(expanded);
    1083             : }
    1084             : 
    1085             : ///////////////////////////////////////////////////////////////////////////////
    1086             : //
    1087             : //  rescan_replacement_list
    1088             : //
    1089             : //    As the name implies, this function is used to rescan the replacement list
    1090             : //    after the first macro substitution phase.
    1091             : //
    1092             : ///////////////////////////////////////////////////////////////////////////////
    1093             : template <typename ContextT>
    1094             : template <typename IteratorT, typename ContainerT>
    1095             : inline void
    1096           0 : macromap<ContextT>::rescan_replacement_list(token_type const &curr_token,
    1097             :     macro_definition_type &macro_def, ContainerT &replacement_list,
    1098             :     ContainerT &expanded, bool expand_operator_defined,
    1099             :     IteratorT &nfirst, IteratorT const &nlast)
    1100             : {
    1101           0 :     if (!replacement_list.empty()) {
    1102             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1103             :     // remove the placemarkers
    1104           0 :         if (boost::wave::need_variadics(ctx.get_language())) {
    1105           0 :         typename ContainerT::iterator end = replacement_list.end();
    1106             :         typename ContainerT::iterator it = replacement_list.begin();
    1107             : 
    1108           0 :             while (it != end) {
    1109             :                 using namespace boost::wave;
    1110           0 :                 if (T_PLACEMARKER == token_id(*it)) {
    1111           0 :                 typename ContainerT::iterator placemarker = it;
    1112             : 
    1113           0 :                     ++it;
    1114           0 :                     replacement_list.erase(placemarker);
    1115             :                 }
    1116             :                 else {
    1117           0 :                     ++it;
    1118             :                 }
    1119             :             }
    1120             :         }
    1121             : #endif
    1122             : 
    1123             :     // rescan the replacement list, during this rescan the current macro under
    1124             :     // expansion isn't available as an expandable macro
    1125           0 :     on_exit::reset<bool> on_exit(macro_def.is_available_for_replacement, false);
    1126           0 :     typename ContainerT::iterator begin_it = replacement_list.begin();
    1127           0 :     typename ContainerT::iterator end_it = replacement_list.end();
    1128             : 
    1129           0 :         expand_whole_tokensequence(expanded, begin_it, end_it,
    1130             :             expand_operator_defined);
    1131             : 
    1132             :     // trim replacement list, leave placeholder tokens untouched
    1133           0 :         impl::trim_replacement_list(expanded);
    1134             :     }
    1135             : 
    1136           0 :     if (expanded.empty()) {
    1137             :     // the resulting replacement list should contain at least a placeholder
    1138             :     // token
    1139           0 :         expanded.push_back(token_type(T_PLACEHOLDER, "_", curr_token.get_position()));
    1140             :     }
    1141           0 : }
    1142             : 
    1143             : ///////////////////////////////////////////////////////////////////////////////
    1144             : //
    1145             : //  expand_macro(): expands a defined macro
    1146             : //
    1147             : //      This functions tries to expand the macro, to which points the 'first'
    1148             : //      iterator. The functions eats up more tokens, if the macro to expand is
    1149             : //      a function-like macro.
    1150             : //
    1151             : ///////////////////////////////////////////////////////////////////////////////
    1152             : template <typename ContextT>
    1153             : template <typename IteratorT, typename ContainerT>
    1154             : inline bool
    1155           0 : macromap<ContextT>::expand_macro(ContainerT &expanded,
    1156             :     token_type const &curr_token, typename defined_macros_type::iterator it,
    1157             :     IteratorT &first, IteratorT const &last,
    1158             :     bool& seen_newline, bool expand_operator_defined,
    1159             :     defined_macros_type *scope, ContainerT *queue_symbol)
    1160             : {
    1161             :     using namespace boost::wave;
    1162             : 
    1163           0 :     if (0 == scope) scope = current_macros;
    1164             : 
    1165           0 :     BOOST_ASSERT(T_IDENTIFIER == token_id(curr_token) ||
    1166             :         IS_CATEGORY(token_id(curr_token), KeywordTokenType) ||
    1167             :         IS_EXTCATEGORY(token_id(curr_token), OperatorTokenType|AltExtTokenType) ||
    1168             :         IS_CATEGORY(token_id(curr_token), BoolLiteralTokenType));
    1169             : 
    1170           0 :     if (it == scope->end()) {
    1171           0 :         ++first;    // advance
    1172             : 
    1173             :     // try to expand a predefined macro (__FILE__, __LINE__ or __INCLUDE_LEVEL__)
    1174           0 :         if (expand_predefined_macro(curr_token, expanded))
    1175             :             return false;
    1176             : 
    1177             :     // not defined as a macro
    1178           0 :         if (0 != queue_symbol) {
    1179           0 :             expanded.splice(expanded.end(), *queue_symbol);
    1180             :         }
    1181             :         else {
    1182           0 :             expanded.push_back(curr_token);
    1183             :         }
    1184           0 :         return false;
    1185             :     }
    1186             : 
    1187             : // ensure the parameters to be replaced with special parameter tokens
    1188           0 : macro_definition_type &macro_def = *(*it).second.get();
    1189             : 
    1190           0 :     macro_def.replace_parameters();
    1191             : 
    1192             : // test if this macro is currently available for replacement
    1193           0 :     if (!macro_def.is_available_for_replacement) {
    1194             :     // this macro is marked as non-replaceable
    1195             :     // copy the macro name itself
    1196           0 :         if (0 != queue_symbol) {
    1197           0 :             queue_symbol->push_back(token_type(T_NONREPLACABLE_IDENTIFIER,
    1198             :                 curr_token.get_value(), curr_token.get_position()));
    1199           0 :             expanded.splice(expanded.end(), *queue_symbol);
    1200             :         }
    1201             :         else {
    1202           0 :             expanded.push_back(token_type(T_NONREPLACABLE_IDENTIFIER,
    1203             :                 curr_token.get_value(), curr_token.get_position()));
    1204             :         }
    1205           0 :         ++first;
    1206           0 :         return false;
    1207             :     }
    1208             : 
    1209             : // try to replace the current identifier as a function-like macro
    1210           0 : ContainerT replacement_list;
    1211             : 
    1212           0 :     if (T_LEFTPAREN == impl::next_token<IteratorT>::peek(first, last)) {
    1213             :     // called as a function-like macro
    1214           0 :         impl::skip_to_token(ctx, first, last, T_LEFTPAREN, seen_newline);
    1215             : 
    1216             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
    1217           0 :         IteratorT seqstart = first;
    1218           0 :         IteratorT seqend = first;
    1219             : #endif
    1220             : 
    1221           0 :         if (macro_def.is_functionlike) {
    1222             :         // defined as a function-like macro
    1223             : 
    1224             :         // collect the arguments
    1225           0 :         std::vector<ContainerT> arguments;
    1226             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    1227             :         typename std::vector<ContainerT>::size_type count_args =
    1228             :             collect_arguments (curr_token, arguments, first, last,
    1229             :                 macro_def.macroparameters.size(), seen_newline);
    1230             : #else
    1231           0 :         typename std::vector<ContainerT>::size_type count_args =
    1232             :             collect_arguments (curr_token, arguments, first, seqend, last,
    1233             :                 macro_def.macroparameters.size(), seen_newline);
    1234             : #endif
    1235             : 
    1236             :         // verify the parameter count
    1237           0 :             if (count_args < macro_def.macroparameters.size() ||
    1238           0 :                 arguments.size() < macro_def.macroparameters.size())
    1239             :             {
    1240           0 :                 if (count_args != arguments.size()) {
    1241             :                 // must been at least one empty argument in C++ mode
    1242           0 :                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1243             :                         empty_macroarguments, curr_token.get_value().c_str(),
    1244             :                         main_pos);
    1245             :                 }
    1246             :                 else {
    1247             :                 // too few macro arguments
    1248           0 :                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1249             :                         too_few_macroarguments, curr_token.get_value().c_str(),
    1250             :                         main_pos);
    1251             :                 }
    1252           0 :                 return false;
    1253             :             }
    1254             : 
    1255           0 :             if (count_args > macro_def.macroparameters.size() ||
    1256           0 :                 arguments.size() > macro_def.macroparameters.size())
    1257             :             {
    1258             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1259           0 :                 if (!macro_def.has_ellipsis)
    1260             : #endif
    1261             :                 {
    1262             :                 // too many macro arguments
    1263           0 :                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1264             :                         too_many_macroarguments,
    1265             :                         curr_token.get_value().c_str(), main_pos);
    1266             :                     return false;
    1267             :                 }
    1268             :             }
    1269             : 
    1270             :         // inject tracing support
    1271             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    1272             :             ctx.get_hooks().expanding_function_like_macro(
    1273             :                 macro_def.macroname, macro_def.macroparameters,
    1274             :                 macro_def.macrodefinition, curr_token, arguments);
    1275             : #else
    1276           0 :             if (ctx.get_hooks().expanding_function_like_macro(ctx.derived(),
    1277           0 :                     macro_def.macroname, macro_def.macroparameters,
    1278           0 :                     macro_def.macrodefinition, curr_token, arguments,
    1279             :                     seqstart, seqend))
    1280             :             {
    1281             : //                 // do not expand this macro, just copy the whole sequence
    1282             : //                 expanded.push_back(curr_token);
    1283             : //                 std::copy(seqstart, first,
    1284             : //                     std::inserter(expanded, expanded.end()));
    1285             :                 // do not expand macro, just copy macro name and parenthesis
    1286             :                 expanded.push_back(curr_token);
    1287             :                 expanded.push_back(*seqstart);
    1288             :                 first = ++seqstart;
    1289             :                 return false;           // no further preprocessing required
    1290             :             }
    1291             : #endif
    1292             : 
    1293             :         // expand the replacement list of this macro
    1294           0 :             expand_replacement_list(macro_def, arguments, expand_operator_defined,
    1295             :                 replacement_list);
    1296             :         }
    1297             :         else {
    1298             :         // defined as an object-like macro
    1299             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    1300             :             ctx.get_hooks().expanding_object_like_macro(
    1301             :                 macro_def.macroname, macro_def.macrodefinition, curr_token);
    1302             : #else
    1303           0 :             if (ctx.get_hooks().expanding_object_like_macro(ctx.derived(),
    1304           0 :                   macro_def.macroname, macro_def.macrodefinition, curr_token))
    1305             :             {
    1306             :                 // do not expand this macro, just copy the whole sequence
    1307             :                 expanded.push_back(curr_token);
    1308           0 :                 return false;           // no further preprocessing required
    1309             :             }
    1310             : #endif
    1311             : 
    1312           0 :         bool found = false;
    1313           0 :         impl::find_concat_operator concat_tag(found);
    1314             : 
    1315           0 :             std::remove_copy_if(macro_def.macrodefinition.begin(),
    1316             :                 macro_def.macrodefinition.end(),
    1317             :                 std::inserter(replacement_list, replacement_list.end()),
    1318             :                 concat_tag);
    1319             : 
    1320             :         // handle concatenation operators
    1321           0 :             if (found && !concat_tokensequence(replacement_list))
    1322             :                 return false;
    1323             :         }
    1324             :     }
    1325             :     else {
    1326             :     // called as an object like macro
    1327           0 :         if ((*it).second->is_functionlike) {
    1328             :         // defined as a function-like macro
    1329           0 :             if (0 != queue_symbol) {
    1330           0 :                 queue_symbol->push_back(curr_token);
    1331           0 :                 expanded.splice(expanded.end(), *queue_symbol);
    1332             :             }
    1333             :             else {
    1334           0 :                 expanded.push_back(curr_token);
    1335             :             }
    1336           0 :             ++first;                // skip macro name
    1337           0 :             return false;           // no further preprocessing required
    1338             :         }
    1339             :         else {
    1340             :         // defined as an object-like macro (expand it)
    1341             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    1342             :             ctx.get_hooks().expanding_object_like_macro(
    1343             :                 macro_def.macroname, macro_def.macrodefinition, curr_token);
    1344             : #else
    1345           0 :             if (ctx.get_hooks().expanding_object_like_macro(ctx.derived(),
    1346           0 :                   macro_def.macroname, macro_def.macrodefinition, curr_token))
    1347             :             {
    1348             :                 // do not expand this macro, just copy the whole sequence
    1349             :                 expanded.push_back(curr_token);
    1350             :                 ++first;                // skip macro name
    1351           0 :                 return false;           // no further preprocessing required
    1352             :             }
    1353             : #endif
    1354             : 
    1355           0 :         bool found = false;
    1356           0 :         impl::find_concat_operator concat_tag(found);
    1357             : 
    1358           0 :             std::remove_copy_if(macro_def.macrodefinition.begin(),
    1359             :                 macro_def.macrodefinition.end(),
    1360             :                 std::inserter(replacement_list, replacement_list.end()),
    1361             :                 concat_tag);
    1362             : 
    1363             :         // handle concatenation operators
    1364           0 :             if (found && !concat_tokensequence(replacement_list))
    1365             :                 return false;
    1366             : 
    1367           0 :             ++first;                // skip macro name
    1368             :         }
    1369             :     }
    1370             : 
    1371             : // rescan the replacement list
    1372           0 : ContainerT expanded_list;
    1373             : 
    1374             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    1375             :     ctx.get_hooks().expanded_macro(replacement_list);
    1376             : #else
    1377           0 :     ctx.get_hooks().expanded_macro(ctx.derived(), replacement_list);
    1378             : #endif
    1379             : 
    1380           0 :     rescan_replacement_list(curr_token, macro_def, replacement_list,
    1381             :         expanded_list, expand_operator_defined, first, last);
    1382             : 
    1383             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    1384             :     ctx.get_hooks().rescanned_macro(expanded_list);
    1385             : #else
    1386           0 :     ctx.get_hooks().rescanned_macro(ctx.derived(), expanded_list);
    1387             : #endif
    1388           0 :     expanded.splice(expanded.end(), expanded_list);
    1389           0 :     return true;        // rescan is required
    1390             : }
    1391             : 
    1392             : ///////////////////////////////////////////////////////////////////////////////
    1393             : //
    1394             : //  If the token under inspection points to a certain predefined macro it will
    1395             : //  be expanded, otherwise false is returned.
    1396             : //  (only __FILE__, __LINE__ and __INCLUDE_LEVEL__ macros are expanded here)
    1397             : //
    1398             : ///////////////////////////////////////////////////////////////////////////////
    1399             : template <typename ContextT>
    1400             : template <typename ContainerT>
    1401             : inline bool
    1402           0 : macromap<ContextT>::expand_predefined_macro(token_type const &curr_token,
    1403             :     ContainerT &expanded)
    1404             : {
    1405             :     using namespace boost::wave;
    1406             : 
    1407           0 : string_type const &value = curr_token.get_value();
    1408             : 
    1409           0 :     if (value.size() < 8 || '_' != value[0] || '_' != value[1])
    1410             :         return false;       // quick check failed
    1411             : 
    1412           0 :     if (value == "__LINE__") {
    1413             :     // expand the __LINE__ macro
    1414           0 :         std::string buffer = lexical_cast<std::string>(main_pos.get_line());
    1415             : 
    1416           0 :         expanded.push_back(token_type(T_INTLIT, buffer.c_str(), curr_token.get_position()));
    1417           0 :         return true;
    1418             :     }
    1419           0 :     else if (value == "__FILE__") {
    1420             :     // expand the __FILE__ macro
    1421             :         namespace fs = boost::filesystem;
    1422             : 
    1423           0 :     std::string file("\"");
    1424           0 :     fs::path filename(wave::util::create_path(main_pos.get_file().c_str()));
    1425             : 
    1426             :         using boost::wave::util::impl::escape_lit;
    1427           0 :         file += escape_lit(wave::util::native_file_string(filename)) + "\"";
    1428           0 :         expanded.push_back(token_type(T_STRINGLIT, file.c_str(),
    1429             :             curr_token.get_position()));
    1430           0 :         return true;
    1431             :     }
    1432           0 :     else if (value == "__INCLUDE_LEVEL__") {
    1433             :     // expand the __INCLUDE_LEVEL__ macro
    1434             :     char buffer[22];    // 21 bytes holds all NUL-terminated unsigned 64-bit numbers
    1435             : 
    1436             :         using namespace std;    // for some systems sprintf is in namespace std
    1437           0 :         sprintf(buffer, "%d", (int)ctx.get_iteration_depth());
    1438           0 :         expanded.push_back(token_type(T_INTLIT, buffer, curr_token.get_position()));
    1439             :         return true;
    1440             :     }
    1441             :     return false;   // no predefined token
    1442             : }
    1443             : 
    1444             : ///////////////////////////////////////////////////////////////////////////////
    1445             : //
    1446             : //  resolve_defined(): resolve the operator defined() and replace it with the
    1447             : //                     correct T_INTLIT token
    1448             : //
    1449             : ///////////////////////////////////////////////////////////////////////////////
    1450             : template <typename ContextT>
    1451             : template <typename IteratorT, typename ContainerT>
    1452             : inline typename ContextT::token_type const &
    1453           0 : macromap<ContextT>::resolve_defined(IteratorT &first,
    1454             :     IteratorT const &last, ContainerT &pending)
    1455             : {
    1456             :     using namespace boost::wave;
    1457             :     using namespace boost::wave::grammars;
    1458             : 
    1459           0 : ContainerT result;
    1460           0 : IteratorT start = first;
    1461           0 : boost::spirit::classic::parse_info<IteratorT> hit =
    1462             :     defined_grammar_gen<typename ContextT::lexer_type>::
    1463           0 :         parse_operator_defined(start, last, result);
    1464             : 
    1465           0 :     if (!hit.hit) {
    1466           0 :         string_type msg ("defined(): ");
    1467           0 :         msg = msg + util::impl::as_string<string_type>(first, last);
    1468           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_expression,
    1469             :             msg.c_str(), main_pos);
    1470             : 
    1471             :     // insert a dummy token
    1472           0 :         pending.push_back(token_type(T_INTLIT, "0", main_pos));
    1473             :     }
    1474             :     else {
    1475           0 :         impl::assign_iterator<IteratorT>::do_(first, hit.stop);
    1476             : 
    1477             :     // insert a token, which reflects the outcome
    1478           0 :         pending.push_back(token_type(T_INTLIT,
    1479           0 :             is_defined(result.begin(), result.end()) ? "1" : "0",
    1480           0 :             main_pos));
    1481             :     }
    1482             : 
    1483           0 : on_exit::pop_front<definition_container_type> pop_front_token(pending);
    1484             : 
    1485           0 :     return act_token = pending.front();
    1486             : }
    1487             : 
    1488             : ///////////////////////////////////////////////////////////////////////////////
    1489             : //
    1490             : //  resolve_operator_pragma(): resolve the operator _Pragma() and dispatch to
    1491             : //                             the associated action
    1492             : //
    1493             : //      This function returns true, if the pragma was correctly interpreted.
    1494             : //      The iterator 'first' is positioned behind the closing ')'.
    1495             : //      This function returns false, if the _Pragma was not known, the
    1496             : //      preprocessed token sequence is pushed back to the 'pending' sequence.
    1497             : //
    1498             : ///////////////////////////////////////////////////////////////////////////////
    1499             : template <typename ContextT>
    1500             : template <typename IteratorT, typename ContainerT>
    1501             : inline bool
    1502           0 : macromap<ContextT>::resolve_operator_pragma(IteratorT &first,
    1503             :     IteratorT const &last, ContainerT &pending, bool& seen_newline)
    1504             : {
    1505             : // isolate the parameter of the operator _Pragma
    1506           0 :     token_type pragma_token = *first;
    1507             : 
    1508           0 :     if (!impl::skip_to_token(ctx, first, last, T_LEFTPAREN, seen_newline)) {
    1509             :     // illformed operator _Pragma
    1510           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_expression,
    1511             :             "operator _Pragma()", pragma_token.get_position());
    1512             :         return false;
    1513             :     }
    1514             : 
    1515           0 :     std::vector<ContainerT> arguments;
    1516             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    1517             :     typename std::vector<ContainerT>::size_type count_args =
    1518             :         collect_arguments (pragma_token, arguments, first, last, 1, seen_newline);
    1519             : #else
    1520           0 :     IteratorT endparen = first;
    1521           0 :     typename std::vector<ContainerT>::size_type count_args =
    1522           0 :         collect_arguments (pragma_token, arguments, first, endparen, last, 1,
    1523             :             seen_newline);
    1524             : #endif
    1525             : 
    1526             : // verify the parameter count
    1527           0 :     if (pragma_token.get_position().get_file().empty())
    1528           0 :         pragma_token.set_position(act_token.get_position());
    1529             : 
    1530           0 :     if (count_args < 1 || arguments.size() < 1) {
    1531             :     // too few macro arguments
    1532           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, too_few_macroarguments,
    1533             :             pragma_token.get_value().c_str(), pragma_token.get_position());
    1534             :         return false;
    1535             :     }
    1536           0 :     if (count_args > 1 || arguments.size() > 1) {
    1537             :     // too many macro arguments
    1538           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, too_many_macroarguments,
    1539             :             pragma_token.get_value().c_str(), pragma_token.get_position());
    1540             :         return false;
    1541             :     }
    1542             : 
    1543             : // preprocess the pragma token body
    1544             :     typedef typename std::vector<ContainerT>::value_type::iterator
    1545             :         argument_iterator_type;
    1546             : 
    1547           0 :     ContainerT expanded;
    1548           0 :     argument_iterator_type begin_it = arguments[0].begin();
    1549           0 :     argument_iterator_type end_it = arguments[0].end();
    1550           0 :     expand_whole_tokensequence(expanded, begin_it, end_it, false);
    1551             : 
    1552             : // un-escape the parameter of the operator _Pragma
    1553             :     typedef typename token_type::string_type string_type;
    1554             : 
    1555           0 :     string_type pragma_cmd;
    1556           0 :     typename ContainerT::const_iterator end_exp = expanded.end();
    1557           0 :     for (typename ContainerT::const_iterator it_exp = expanded.begin();
    1558           0 :          it_exp != end_exp; ++it_exp)
    1559             :     {
    1560           0 :         if (T_EOF == token_id(*it_exp))
    1561             :             break;
    1562           0 :         if (IS_CATEGORY(*it_exp, WhiteSpaceTokenType))
    1563           0 :             continue;
    1564             : 
    1565           0 :         if (T_STRINGLIT != token_id(*it_exp)) {
    1566             :         // ill formed operator _Pragma
    1567           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1568             :                 ill_formed_pragma_option, "_Pragma",
    1569             :                 pragma_token.get_position());
    1570           0 :             return false;
    1571             :         }
    1572           0 :         if (pragma_cmd.size() > 0) {
    1573             :         // there should be exactly one string literal (string literals are to
    1574             :         // be concatenated at translation phase 6, but _Pragma operators are
    1575             :         // to be executed at translation phase 4)
    1576           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1577             :                 ill_formed_pragma_option, "_Pragma",
    1578             :                 pragma_token.get_position());
    1579             :             return false;
    1580             :         }
    1581             : 
    1582             :     // remove the '\"' and concat all given string literal-values
    1583           0 :         string_type token_str = (*it_exp).get_value();
    1584           0 :         pragma_cmd += token_str.substr(1, token_str.size() - 2);
    1585             :     }
    1586           0 :     string_type pragma_cmd_unesc = impl::unescape_lit(pragma_cmd);
    1587             : 
    1588             : // tokenize the pragma body
    1589             :     typedef typename ContextT::lexer_type lexer_type;
    1590             : 
    1591           0 :     ContainerT pragma;
    1592           0 :     std::string pragma_cmd_str(pragma_cmd_unesc.c_str());
    1593           0 :     lexer_type it = lexer_type(pragma_cmd_str.begin(), pragma_cmd_str.end(),
    1594           0 :         pragma_token.get_position(), ctx.get_language());
    1595           0 :     lexer_type end = lexer_type();
    1596           0 :     for (/**/; it != end; ++it)
    1597           0 :         pragma.push_back(*it);
    1598             : 
    1599             : // analyze the preprocessed token sequence and eventually dispatch to the
    1600             : // associated action
    1601           0 :     if (interpret_pragma(ctx, pragma_token, pragma.begin(), pragma.end(),
    1602             :         pending))
    1603             :     {
    1604             :         return true;    // successfully recognized a wave specific pragma
    1605             :     }
    1606             : 
    1607             : // unknown pragma token sequence, push it back and return to the caller
    1608           0 :     pending.push_front(token_type(T_SPACE, " ", pragma_token.get_position()));
    1609           0 :     pending.push_front(token_type(T_RIGHTPAREN, ")", pragma_token.get_position()));
    1610           0 :     pending.push_front(token_type(T_STRINGLIT, string_type("\"") + pragma_cmd + "\"",
    1611             :         pragma_token.get_position()));
    1612           0 :     pending.push_front(token_type(T_LEFTPAREN, "(", pragma_token.get_position()));
    1613           0 :     pending.push_front(pragma_token);
    1614             :     return false;
    1615             : }
    1616             : 
    1617             : ///////////////////////////////////////////////////////////////////////////////
    1618             : //
    1619             : //  Test, whether the result of a concat operator is well formed or not.
    1620             : //
    1621             : //  This is done by re-scanning (re-tokenizing) the resulting token sequence,
    1622             : //  which should give back exactly one token.
    1623             : //
    1624             : ///////////////////////////////////////////////////////////////////////////////
    1625             : template <typename ContextT>
    1626             : template <typename ContainerT>
    1627             : inline bool
    1628           0 : macromap<ContextT>::is_valid_concat(string_type new_value,
    1629             :     position_type const &pos, ContainerT &rescanned)
    1630             : {
    1631             : // re-tokenize the newly generated string
    1632             :     typedef typename ContextT::lexer_type lexer_type;
    1633             : 
    1634           0 :     std::string value_to_test(new_value.c_str());
    1635             : 
    1636             :     boost::wave::language_support lang =
    1637           0 :         boost::wave::enable_prefer_pp_numbers(ctx.get_language());
    1638           0 :     lang = boost::wave::enable_single_line(lang);
    1639             : 
    1640           0 :     lexer_type it = lexer_type(value_to_test.begin(), value_to_test.end(), pos,
    1641             :         lang);
    1642           0 :     lexer_type end = lexer_type();
    1643           0 :     for (/**/; it != end && T_EOF != token_id(*it); ++it)
    1644             :     {
    1645             :         // as of Wave V2.0.7 pasting of tokens is valid only if the resulting
    1646             :         // tokens are pp_tokens (as mandated by C++11)
    1647           0 :         if (!is_pp_token(*it))
    1648             :             return false;
    1649           0 :         rescanned.push_back(*it);
    1650             :     }
    1651             : 
    1652             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1653           0 :     if (boost::wave::need_variadics(ctx.get_language()))
    1654             :         return true;       // in variadics mode token pasting is well defined
    1655             : #endif
    1656             : 
    1657             : // test if the newly generated token sequence contains more than 1 token
    1658           0 :     return 1 == rescanned.size();
    1659             : }
    1660             : 
    1661             : ///////////////////////////////////////////////////////////////////////////////
    1662             : //
    1663             : //  Handle all occurrences of the concatenation operator '##' inside the given
    1664             : //  token sequence.
    1665             : //
    1666             : ///////////////////////////////////////////////////////////////////////////////
    1667             : template <typename Context>
    1668           0 : inline void report_invalid_concatenation(Context& ctx,
    1669             :     typename Context::token_type const& prev,
    1670             :     typename Context::token_type const& next,
    1671             :     typename Context::position_type const& main_pos)
    1672             : {
    1673           0 : typename Context::string_type error_string("\"");
    1674             : 
    1675           0 :     error_string += prev.get_value();
    1676           0 :     error_string += "\" and \"";
    1677           0 :     error_string += next.get_value();
    1678           0 :     error_string += "\"";
    1679           0 :     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_concat,
    1680             :         error_string.c_str(), main_pos);
    1681           0 : }
    1682             : 
    1683             : template <typename ContextT>
    1684             : template <typename ContainerT>
    1685             : inline bool
    1686           0 : macromap<ContextT>::concat_tokensequence(ContainerT &expanded)
    1687             : {
    1688             :     using namespace boost::wave;
    1689             :     typedef typename ContainerT::iterator iterator_type;
    1690             : 
    1691           0 :     iterator_type end = expanded.end();
    1692           0 :     iterator_type prev = end;
    1693           0 :     for (iterator_type it = expanded.begin(); it != end; /**/)
    1694             :     {
    1695           0 :         if (T_POUND_POUND == BASE_TOKEN(token_id(*it))) {
    1696           0 :         iterator_type next = it;
    1697             : 
    1698           0 :             ++next;
    1699           0 :             if (prev == end || next == end) {
    1700             :             // error, '##' should be in between two tokens
    1701           0 :                 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1702             :                     ill_formed_operator, "concat ('##')", main_pos);
    1703           0 :                 return false;
    1704             :             }
    1705             : 
    1706             :         // replace prev##next with the concatenated value, skip whitespace
    1707             :         // before and after the '##' operator
    1708           0 :             while (IS_CATEGORY(*next, WhiteSpaceTokenType)) {
    1709           0 :                 ++next;
    1710           0 :                 if (next == end) {
    1711             :                 // error, '##' should be in between two tokens
    1712           0 :                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1713             :                         ill_formed_operator, "concat ('##')", main_pos);
    1714             :                     return false;
    1715             :                 }
    1716             :             }
    1717             : 
    1718             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1719           0 :             if (boost::wave::need_variadics(ctx.get_language())) {
    1720           0 :                 if (T_PLACEMARKER == token_id(*next)) {
    1721             :                 // remove the '##' and the next tokens from the sequence
    1722           0 :                 iterator_type first_to_delete = prev;
    1723             : 
    1724           0 :                     expanded.erase(++first_to_delete, ++next);
    1725           0 :                     it = next;
    1726           0 :                     continue;
    1727             :                 }
    1728           0 :                 else if (T_PLACEMARKER == token_id(*prev)) {
    1729             :                 // remove the '##' and the next tokens from the sequence
    1730           0 :                 iterator_type first_to_delete = prev;
    1731             : 
    1732           0 :                     *prev = *next;
    1733           0 :                     expanded.erase(++first_to_delete, ++next);
    1734           0 :                     it = next;
    1735           0 :                     continue;
    1736             :                 }
    1737             :             }
    1738             : #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1739             : 
    1740             :         // test if the concat operator has to concatenate two unrelated
    1741             :         // tokens i.e. the result yields more then one token
    1742           0 :         string_type concat_result;
    1743           0 :         ContainerT rescanned;
    1744             : 
    1745           0 :             concat_result = ((*prev).get_value() + (*next).get_value());
    1746             : 
    1747             :         // analyze the validity of the concatenation result
    1748           0 :             if (!is_valid_concat(concat_result, (*prev).get_position(),
    1749           0 :                     rescanned) &&
    1750           0 :                 !IS_CATEGORY(*prev, WhiteSpaceTokenType) &&
    1751           0 :                 !IS_CATEGORY(*next, WhiteSpaceTokenType))
    1752             :             {
    1753           0 :                 report_invalid_concatenation(ctx, *prev, *next, main_pos);
    1754           0 :                 return false;
    1755             :             }
    1756             : 
    1757             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1758           0 :             if (boost::wave::need_variadics(ctx.get_language())) {
    1759             :             // remove the prev, '##' and the next tokens from the sequence
    1760           0 :                 expanded.erase(prev, ++next);       // remove not needed tokens
    1761             : 
    1762             :             // some stl implementations clear() the container if we erased all
    1763             :             // the elements, which orphans all iterators. we re-initialize these
    1764             :             // here
    1765           0 :                 if (expanded.empty())
    1766           0 :                     end = next = expanded.end();
    1767             : 
    1768             :             // replace the old token (pointed to by *prev) with the re-tokenized
    1769             :             // sequence
    1770           0 :                 expanded.splice(next, rescanned);
    1771             : 
    1772             :             // the last token of the inserted sequence is the new previous
    1773           0 :                 prev = next;
    1774           0 :                 if (next != expanded.end())
    1775           0 :                     --prev;
    1776             :             }
    1777             :             else
    1778             : #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1779             :             {
    1780             :             // we leave the token_id unchanged, but unmark the token as
    1781             :             // disabled, if appropriate
    1782           0 :                 (*prev).set_value(concat_result);
    1783           0 :                 if (T_NONREPLACABLE_IDENTIFIER == token_id(*prev))
    1784           0 :                     (*prev).set_token_id(T_IDENTIFIER);
    1785             : 
    1786             :             // remove the '##' and the next tokens from the sequence
    1787           0 :             iterator_type first_to_delete = prev;
    1788             : 
    1789           0 :                 expanded.erase(++first_to_delete, ++next);
    1790             :             }
    1791           0 :             it = next;
    1792           0 :             continue;
    1793             :         }
    1794             : 
    1795             :     // save last non-whitespace token position
    1796           0 :         if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
    1797           0 :             prev = it;
    1798             : 
    1799           0 :         ++it;           // next token, please
    1800             :     }
    1801             :     return true;
    1802             : }
    1803             : 
    1804             : ///////////////////////////////////////////////////////////////////////////////
    1805             : //
    1806             : //  predefine_macro(): predefine a single macro
    1807             : //
    1808             : ///////////////////////////////////////////////////////////////////////////////
    1809             : template <typename ContextT>
    1810             : inline void
    1811           0 : macromap<ContextT>::predefine_macro(defined_macros_type *scope,
    1812             :     string_type const &name, token_type const &t)
    1813             : {
    1814           0 : definition_container_type macrodefinition;
    1815           0 : std::vector<token_type> param;
    1816             : 
    1817           0 :     macrodefinition.push_back(t);
    1818           0 :     add_macro(token_type(T_IDENTIFIER, name, t.get_position()),
    1819             :         false, param, macrodefinition, true, scope);
    1820           0 : }
    1821             : 
    1822             : ///////////////////////////////////////////////////////////////////////////////
    1823             : //
    1824             : //  init_predefined_macros(): init the predefined macros
    1825             : //
    1826             : ///////////////////////////////////////////////////////////////////////////////
    1827             : template <typename ContextT>
    1828             : inline void
    1829           0 : macromap<ContextT>::init_predefined_macros(char const *fname,
    1830             :     defined_macros_type *scope, bool at_global_scope)
    1831             : {
    1832             : // if no scope is given, use the current one
    1833           0 : defined_macros_type *current_scope = scope ? scope : current_macros;
    1834             : 
    1835             : // first, add the static macros
    1836           0 : position_type pos("<built-in>");
    1837             : 
    1838             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1839           0 :     if (boost::wave::need_c99(ctx.get_language())) {
    1840             :     // define C99 specifics
    1841           0 :         for (int i = 0; 0 != predef.static_data_c99(i).name; ++i) {
    1842           0 :             predefined_macros::static_macros const& m = predef.static_data_c99(i);
    1843           0 :             predefine_macro(current_scope, m.name,
    1844           0 :                 token_type(m.token_id, m.value, pos));
    1845             :         }
    1846             :     }
    1847             :     else
    1848             : #endif
    1849             :     {
    1850             : #if BOOST_WAVE_SUPPORT_CPP0X != 0
    1851           0 :         if (boost::wave::need_cpp0x(ctx.get_language())) {
    1852             :         // define C++11 specifics
    1853           0 :             for (int i = 0; 0 != predef.static_data_cpp0x(i).name; ++i) {
    1854           0 :                 predefined_macros::static_macros const& m = predef.static_data_cpp0x(i);
    1855           0 :                 predefine_macro(current_scope, m.name,
    1856           0 :                     token_type(m.token_id, m.value, pos));
    1857             :             }
    1858             :         }
    1859             :         else
    1860             : #endif
    1861             :         {
    1862             :         // define C++ specifics
    1863           0 :             for (int i = 0; 0 != predef.static_data_cpp(i).name; ++i) {
    1864           0 :                 predefined_macros::static_macros const& m = predef.static_data_cpp(i);
    1865           0 :                 predefine_macro(current_scope, m.name,
    1866           0 :                     token_type(m.token_id, m.value, pos));
    1867             :             }
    1868             : 
    1869             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1870             :         // define __WAVE_HAS_VARIADICS__, if appropriate
    1871           0 :             if (boost::wave::need_variadics(ctx.get_language())) {
    1872           0 :                 predefine_macro(current_scope, "__WAVE_HAS_VARIADICS__",
    1873             :                     token_type(T_INTLIT, "1", pos));
    1874             :             }
    1875             : #endif
    1876             :         }
    1877             :     }
    1878             : 
    1879             : // predefine the __BASE_FILE__ macro which contains the main file name
    1880             :     namespace fs = boost::filesystem;
    1881           0 :     if (string_type(fname) != "<Unknown>") {
    1882           0 :     fs::path filename(create_path(fname));
    1883             : 
    1884             :         using boost::wave::util::impl::escape_lit;
    1885           0 :         predefine_macro(current_scope, "__BASE_FILE__",
    1886             :             token_type(T_STRINGLIT, string_type("\"") +
    1887             :                 escape_lit(native_file_string(filename)).c_str() + "\"", pos));
    1888           0 :         base_name = fname;
    1889             :     }
    1890           0 :     else if (!base_name.empty()) {
    1891           0 :     fs::path filename(create_path(base_name.c_str()));
    1892             : 
    1893             :         using boost::wave::util::impl::escape_lit;
    1894           0 :         predefine_macro(current_scope, "__BASE_FILE__",
    1895             :             token_type(T_STRINGLIT, string_type("\"") +
    1896             :                 escape_lit(native_file_string(filename)).c_str() + "\"", pos));
    1897             :     }
    1898             : 
    1899             : // now add the dynamic macros
    1900           0 :     for (int j = 0; 0 != predef.dynamic_data(j).name; ++j) {
    1901           0 :         predefined_macros::dynamic_macros const& m = predef.dynamic_data(j);
    1902           0 :         predefine_macro(current_scope, m.name,
    1903           0 :             token_type(m.token_id, (predef.* m.generator)(), pos));
    1904             :     }
    1905           0 : }
    1906             : 
    1907             : ///////////////////////////////////////////////////////////////////////////////
    1908             : //
    1909             : //  reset_macromap(): initialize the internal macro symbol namespace
    1910             : //
    1911             : ///////////////////////////////////////////////////////////////////////////////
    1912             : template <typename ContextT>
    1913             : inline void
    1914           0 : macromap<ContextT>::reset_macromap()
    1915             : {
    1916           0 :     current_macros->clear();
    1917           0 :     predef.reset();
    1918           0 :     act_token = token_type();
    1919           0 : }
    1920             : 
    1921             : ///////////////////////////////////////////////////////////////////////////////
    1922             : }}}   // namespace boost::wave::util
    1923             : 
    1924             : #if BOOST_WAVE_SERIALIZATION != 0
    1925             : namespace boost { namespace serialization {
    1926             : 
    1927             : template<typename ContextT>
    1928             : struct version<boost::wave::util::macromap<ContextT> >
    1929             : {
    1930             :     typedef boost::wave::util::macromap<ContextT> target_type;
    1931             :     typedef mpl::int_<target_type::version> type;
    1932             :     typedef mpl::integral_c_tag tag;
    1933             :     BOOST_STATIC_CONSTANT(unsigned int, value = version::type::value);
    1934             : };
    1935             : 
    1936             : }}    // namespace boost::serialization
    1937             : #endif
    1938             : 
    1939             : // the suffix header occurs after all of the code
    1940             : #ifdef BOOST_HAS_ABI_HEADERS
    1941             : #include BOOST_ABI_SUFFIX
    1942             : #endif
    1943             : 
    1944             : #endif // !defined(CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED)

Generated by: LCOV version 1.14