diff DEPENDENCIES/generic/include/boost/wave/util/cpp_macromap.hpp @ 16:2665513ce2d3

Add boost headers
author Chris Cannam
date Tue, 05 Aug 2014 11:11:38 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DEPENDENCIES/generic/include/boost/wave/util/cpp_macromap.hpp	Tue Aug 05 11:11:38 2014 +0100
@@ -0,0 +1,1946 @@
+/*=============================================================================
+    Boost.Wave: A Standard compliant C++ preprocessor library
+
+    Macro expansion engine
+
+    http://www.boost.org/
+
+    Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
+    Software License, Version 1.0. (See accompanying file
+    LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+
+#if !defined(CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED)
+#define CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED
+
+#include <cstdlib>
+#include <cstdio>
+#include <ctime>
+
+#include <list>
+#include <map>
+#include <set>
+#include <vector>
+#include <iterator>
+#include <algorithm>
+
+#include <boost/assert.hpp>
+#include <boost/wave/wave_config.hpp>
+#if BOOST_WAVE_SERIALIZATION != 0
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#endif
+
+#include <boost/filesystem/path.hpp>
+
+#include <boost/wave/util/time_conversion_helper.hpp>
+#include <boost/wave/util/unput_queue_iterator.hpp>
+#include <boost/wave/util/macro_helpers.hpp>
+#include <boost/wave/util/macro_definition.hpp>
+#include <boost/wave/util/symbol_table.hpp>
+#include <boost/wave/util/cpp_macromap_utils.hpp>
+#include <boost/wave/util/cpp_macromap_predef.hpp>
+#include <boost/wave/util/filesystem_compatibility.hpp>
+#include <boost/wave/grammars/cpp_defined_grammar_gen.hpp>
+
+#include <boost/wave/wave_version.hpp>
+#include <boost/wave/cpp_exceptions.hpp>
+#include <boost/wave/language_support.hpp>
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost { namespace wave { namespace util {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  macromap
+//
+//      This class holds all currently defined macros and on demand expands
+//      those macro definitions
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+class macromap {
+
+    typedef macromap<ContextT>                      self_type;
+    typedef typename ContextT::token_type           token_type;
+    typedef typename token_type::string_type        string_type;
+    typedef typename token_type::position_type      position_type;
+
+    typedef typename ContextT::token_sequence_type  definition_container_type;
+    typedef std::vector<token_type>                 parameter_container_type;
+
+    typedef macro_definition<token_type, definition_container_type>
+        macro_definition_type;
+    typedef symbol_table<string_type, macro_definition_type>
+        defined_macros_type;
+    typedef typename defined_macros_type::value_type::second_type
+        macro_ref_type;
+
+public:
+    macromap(ContextT &ctx_)
+    :   current_macros(0), defined_macros(new defined_macros_type(1)),
+        main_pos("", 0), ctx(ctx_), macro_uid(1)
+    {
+        current_macros = defined_macros.get();
+    }
+    ~macromap() {}
+
+//  Add a new macro to the given macro scope
+    bool add_macro(token_type const &name, bool has_parameters,
+        parameter_container_type &parameters,
+        definition_container_type &definition, bool is_predefined = false,
+        defined_macros_type *scope = 0);
+
+//  Tests, whether the given macro name is defined in the given macro scope
+    bool is_defined(string_type const &name,
+        typename defined_macros_type::iterator &it,
+        defined_macros_type *scope = 0) const;
+
+// expects a token sequence as its parameters
+    template <typename IteratorT>
+    bool is_defined(IteratorT const &begin, IteratorT const &end) const;
+
+// expects an arbitrary string as its parameter
+    bool is_defined(string_type const &str) const;
+
+//  Get the macro definition for the given macro scope
+    bool get_macro(string_type const &name, bool &has_parameters,
+        bool &is_predefined, position_type &pos,
+        parameter_container_type &parameters,
+        definition_container_type &definition,
+        defined_macros_type *scope = 0) const;
+
+//  Remove a macro name from the given macro scope
+    bool remove_macro(string_type const &name, position_type const& pos,
+        bool even_predefined = false);
+
+    template <typename IteratorT, typename ContainerT>
+    token_type const &expand_tokensequence(IteratorT &first,
+        IteratorT const &last, ContainerT &pending, ContainerT &expanded,
+        bool& seen_newline, bool expand_operator_defined);
+
+//  Expand all macros inside the given token sequence
+    template <typename IteratorT, typename ContainerT>
+    void expand_whole_tokensequence(ContainerT &expanded,
+        IteratorT &first, IteratorT const &last,
+        bool expand_operator_defined);
+
+//  Init the predefined macros (add them to the given scope)
+    void init_predefined_macros(char const *fname = "<Unknown>",
+        defined_macros_type *scope = 0, bool at_global_scope = true);
+    void predefine_macro(defined_macros_type *scope, string_type const &name,
+        token_type const &t);
+
+//  Init the internal macro symbol namespace
+    void reset_macromap();
+
+    position_type &get_main_pos() { return main_pos; }
+    position_type const& get_main_pos() const { return main_pos; }
+
+//  interface for macro name introspection
+    typedef typename defined_macros_type::name_iterator name_iterator;
+    typedef typename defined_macros_type::const_name_iterator const_name_iterator;
+
+    name_iterator begin()
+        { return defined_macros_type::make_iterator(current_macros->begin()); }
+    name_iterator end()
+        { return defined_macros_type::make_iterator(current_macros->end()); }
+    const_name_iterator begin() const
+        { return defined_macros_type::make_iterator(current_macros->begin()); }
+    const_name_iterator end() const
+        { return defined_macros_type::make_iterator(current_macros->end()); }
+
+protected:
+//  Helper functions for expanding all macros in token sequences
+    template <typename IteratorT, typename ContainerT>
+    token_type const &expand_tokensequence_worker(ContainerT &pending,
+        unput_queue_iterator<IteratorT, token_type, ContainerT> &first,
+        unput_queue_iterator<IteratorT, token_type, ContainerT> const &last,
+        bool& seen_newline, bool expand_operator_defined);
+
+//  Collect all arguments supplied to a macro invocation
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+    template <typename IteratorT, typename ContainerT, typename SizeT>
+    typename std::vector<ContainerT>::size_type collect_arguments (
+        token_type const curr_token, std::vector<ContainerT> &arguments,
+        IteratorT &next, IteratorT const &end, SizeT const &parameter_count,
+        bool& seen_newline);
+#else
+    template <typename IteratorT, typename ContainerT, typename SizeT>
+    typename std::vector<ContainerT>::size_type collect_arguments (
+        token_type const curr_token, std::vector<ContainerT> &arguments,
+        IteratorT &next, IteratorT &endparen, IteratorT const &end,
+        SizeT const &parameter_count, bool& seen_newline);
+#endif
+
+//  Expand a single macro name
+    template <typename IteratorT, typename ContainerT>
+    bool expand_macro(ContainerT &pending, token_type const &name,
+        typename defined_macros_type::iterator it,
+        IteratorT &first, IteratorT const &last,
+        bool& seen_newline, bool expand_operator_defined,
+        defined_macros_type *scope = 0, ContainerT *queue_symbol = 0);
+
+//  Expand a predefined macro (__LINE__, __FILE__ and __INCLUDE_LEVEL__)
+    template <typename ContainerT>
+    bool expand_predefined_macro(token_type const &curr_token,
+        ContainerT &expanded);
+
+//  Expand a single macro argument
+    template <typename ContainerT>
+    void expand_argument (typename std::vector<ContainerT>::size_type arg,
+        std::vector<ContainerT> &arguments,
+        std::vector<ContainerT> &expanded_args, bool expand_operator_defined,
+        std::vector<bool> &has_expanded_args);
+
+//  Expand the replacement list (replaces parameters with arguments)
+    template <typename ContainerT>
+    void expand_replacement_list(
+        macro_definition_type const &macrodefinition,
+        std::vector<ContainerT> &arguments,
+        bool expand_operator_defined, ContainerT &expanded);
+
+//  Rescans the replacement list for macro expansion
+    template <typename IteratorT, typename ContainerT>
+    void rescan_replacement_list(token_type const &curr_token,
+        macro_definition_type &macrodef, ContainerT &replacement_list,
+        ContainerT &expanded, bool expand_operator_defined,
+        IteratorT &nfirst, IteratorT const &nlast);
+
+//  Resolves the operator defined() and replces the token with "0" or "1"
+    template <typename IteratorT, typename ContainerT>
+    token_type const &resolve_defined(IteratorT &first, IteratorT const &last,
+        ContainerT &expanded);
+
+//  Resolve operator _Pragma or the #pragma directive
+    template <typename IteratorT, typename ContainerT>
+    bool resolve_operator_pragma(IteratorT &first,
+        IteratorT const &last, ContainerT &expanded, bool& seen_newline);
+
+//  Handle the concatenation operator '##'
+    template <typename ContainerT>
+    bool concat_tokensequence(ContainerT &expanded);
+
+    template <typename ContainerT>
+    bool is_valid_concat(string_type new_value,
+        position_type const &pos, ContainerT &rescanned);
+
+#if BOOST_WAVE_SERIALIZATION != 0
+public:
+    BOOST_STATIC_CONSTANT(unsigned int, version = 0x10);
+    BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f);
+
+private:
+    friend class boost::serialization::access;
+    template<typename Archive>
+    void save(Archive &ar, const unsigned int version) const
+    {
+        using namespace boost::serialization;
+        ar & make_nvp("defined_macros", defined_macros);
+    }
+    template<typename Archive>
+    void load(Archive &ar, const unsigned int loaded_version)
+    {
+        using namespace boost::serialization;
+        if (version != (loaded_version & ~version_mask)) {
+            BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
+                "cpp_context state version", get_main_pos());
+        }
+        ar & make_nvp("defined_macros", defined_macros);
+        current_macros = defined_macros.get();
+    }
+    BOOST_SERIALIZATION_SPLIT_MEMBER()
+#endif
+
+private:
+    defined_macros_type *current_macros;                   // current symbol table
+    boost::shared_ptr<defined_macros_type> defined_macros; // global symbol table
+
+    token_type act_token;       // current token
+    position_type main_pos;     // last token position in the pp_iterator
+    string_type base_name;      // the name to be expanded by __BASE_FILE__
+    ContextT &ctx;              // context object associated with the macromap
+    long macro_uid;
+    predefined_macros predef;   // predefined macro support
+};
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  add_macro(): adds a new macro to the macromap
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline bool
+macromap<ContextT>::add_macro(token_type const &name, bool has_parameters,
+    parameter_container_type &parameters, definition_container_type &definition,
+    bool is_predefined, defined_macros_type *scope)
+{
+    if (!is_predefined && impl::is_special_macroname (name.get_value())) {
+    // exclude special macro names
+        BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
+            illegal_redefinition, name.get_value().c_str(), main_pos,
+            name.get_value().c_str());
+        return false;
+    }
+    if (boost::wave::need_variadics(ctx.get_language()) &&
+        "__VA_ARGS__" == name.get_value())
+    {
+    // can't use __VA_ARGS__ as a macro name
+        BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
+            bad_define_statement_va_args, name.get_value().c_str(), main_pos,
+            name.get_value().c_str());
+        return false;
+    }
+    if (AltExtTokenType == (token_id(name) & ExtTokenOnlyMask)) {
+    // exclude special operator names
+        BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
+            illegal_operator_redefinition, name.get_value().c_str(), main_pos,
+            name.get_value().c_str());
+        return false;
+    }
+
+// try to define the new macro
+defined_macros_type *current_scope = scope ? scope : current_macros;
+typename defined_macros_type::iterator it = current_scope->find(name.get_value());
+
+    if (it != current_scope->end()) {
+    // redefinition, should not be different
+        macro_definition_type* macrodef = (*it).second.get();
+        if (macrodef->is_functionlike != has_parameters ||
+            !impl::parameters_equal(macrodef->macroparameters, parameters) ||
+            !impl::definition_equals(macrodef->macrodefinition, definition))
+        {
+            BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
+                macro_redefinition, name.get_value().c_str(), main_pos,
+                name.get_value().c_str());
+        }
+        return false;
+    }
+
+// test the validity of the parameter names
+    if (has_parameters) {
+        std::set<typename token_type::string_type> names;
+
+        typedef typename parameter_container_type::iterator
+            parameter_iterator_type;
+        typedef typename std::set<typename token_type::string_type>::iterator
+            name_iterator_type;
+
+        parameter_iterator_type end = parameters.end();
+        for (parameter_iterator_type itp = parameters.begin(); itp != end; ++itp)
+        {
+        name_iterator_type pit = names.find((*itp).get_value());
+
+            if (pit != names.end()) {
+            // duplicate parameter name
+                BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
+                    duplicate_parameter_name, (*pit).c_str(), main_pos,
+                    name.get_value().c_str());
+                return false;
+            }
+            names.insert((*itp).get_value());
+        }
+    }
+
+// insert a new macro node
+    std::pair<typename defined_macros_type::iterator, bool> p =
+        current_scope->insert(
+            typename defined_macros_type::value_type(
+                name.get_value(),
+                macro_ref_type(new macro_definition_type(name,
+                    has_parameters, is_predefined, ++macro_uid)
+                )
+            )
+        );
+
+    if (!p.second) {
+        BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
+            macro_insertion_error, name.get_value().c_str(), main_pos,
+            name.get_value().c_str());
+        return false;
+    }
+
+// add the parameters and the definition
+    std::swap((*p.first).second->macroparameters, parameters);
+    std::swap((*p.first).second->macrodefinition, definition);
+
+// call the context supplied preprocessing hook
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+    ctx.get_hooks().defined_macro(name, has_parameters,
+        (*p.first).second->macroparameters,
+        (*p.first).second->macrodefinition, is_predefined);
+#else
+    ctx.get_hooks().defined_macro(ctx.derived(), name, has_parameters,
+        (*p.first).second->macroparameters,
+        (*p.first).second->macrodefinition, is_predefined);
+#endif
+    return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  is_defined(): returns, whether a given macro is already defined
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline bool
+macromap<ContextT>::is_defined(typename token_type::string_type const &name,
+    typename defined_macros_type::iterator &it,
+    defined_macros_type *scope) const
+{
+    if (0 == scope) scope = current_macros;
+
+    if ((it = scope->find(name)) != scope->end())
+        return true;        // found in symbol table
+
+// quick pre-check
+    if (name.size() < 8 || '_' != name[0] || '_' != name[1])
+        return false;       // quick check failed
+
+    return name == "__LINE__" || name == "__FILE__" ||
+        name == "__INCLUDE_LEVEL__";
+}
+
+template <typename ContextT>
+template <typename IteratorT>
+inline bool
+macromap<ContextT>::is_defined(IteratorT const &begin,
+    IteratorT const &end) const
+{
+// in normal mode the name under inspection should consist of an identifier
+// only
+token_id id = token_id(*begin);
+
+    if (T_IDENTIFIER != id &&
+        !IS_CATEGORY(id, KeywordTokenType) &&
+        !IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) &&
+        !IS_CATEGORY(id, BoolLiteralTokenType))
+    {
+        std::string msg(impl::get_full_name(begin, end));
+        BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_macroname,
+            msg.c_str(), main_pos);
+        return false;
+    }
+
+IteratorT it = begin;
+string_type name ((*it).get_value());
+typename defined_macros_type::iterator cit;
+
+    if (++it != end) {
+    // there should be only one token as the inspected name
+        std::string msg(impl::get_full_name(begin, end));
+        BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_macroname,
+            msg.c_str(), main_pos);
+        return false;
+    }
+    return is_defined(name, cit, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//  same as above, only takes an arbitrary string type as its parameter
+template <typename ContextT>
+inline bool
+macromap<ContextT>::is_defined(string_type const &str) const
+{
+    typename defined_macros_type::iterator cit;
+    return is_defined(str, cit, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Get the macro definition for the given macro scope
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline bool
+macromap<ContextT>::get_macro(string_type const &name, bool &has_parameters,
+    bool &is_predefined, position_type &pos,
+    parameter_container_type &parameters,
+    definition_container_type &definition,
+    defined_macros_type *scope) const
+{
+    typename defined_macros_type::iterator it;
+    if (!is_defined(name, it, scope))
+        return false;
+
+macro_definition_type &macro_def = *(*it).second.get();
+
+    has_parameters = macro_def.is_functionlike;
+    is_predefined = macro_def.is_predefined;
+    pos = macro_def.macroname.get_position();
+    parameters = macro_def.macroparameters;
+    definition = macro_def.macrodefinition;
+    return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  remove_macro(): remove a macro from the macromap
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline bool
+macromap<ContextT>::remove_macro(string_type const &name,
+    position_type const& pos, bool even_predefined)
+{
+    typename defined_macros_type::iterator it = current_macros->find(name);
+
+    if (it != current_macros->end()) {
+        if ((*it).second->is_predefined) {
+            if (!even_predefined || impl::is_special_macroname(name)) {
+                BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+                    bad_undefine_statement, name.c_str(), main_pos);
+                return false;
+            }
+        }
+        current_macros->erase(it);
+
+    // call the context supplied preprocessing hook function
+    token_type tok(T_IDENTIFIER, name, pos);
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+        ctx.get_hooks().undefined_macro(tok);
+#else
+        ctx.get_hooks().undefined_macro(ctx.derived(), tok);
+#endif
+        return true;
+    }
+    else if (impl::is_special_macroname(name)) {
+        BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_undefine_statement,
+            name.c_str(), pos);
+    }
+    return false;       // macro was not defined
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  expand_tokensequence
+//
+//      This function is a helper function which wraps the given iterator
+//      range into corresponding unput_iterator's and calls the main workhorse
+//      of the macro expansion engine (the function expand_tokensequence_worker)
+//
+//      This is the top level macro expansion function called from the
+//      preprocessing iterator component only.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline typename ContextT::token_type const &
+macromap<ContextT>::expand_tokensequence(IteratorT &first,
+    IteratorT const &last, ContainerT &pending, ContainerT &expanded,
+    bool& seen_newline, bool expand_operator_defined)
+{
+    typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT>
+        gen_type;
+    typedef typename gen_type::return_type iterator_type;
+
+    iterator_type first_it = gen_type::generate(expanded, first);
+    iterator_type last_it = gen_type::generate(last);
+
+on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
+
+    return expand_tokensequence_worker(pending, first_it, last_it,
+        seen_newline, expand_operator_defined);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  expand_tokensequence_worker
+//
+//      This function is the main workhorse of the macro expansion engine. It
+//      expands as much tokens as needed to identify the next preprocessed
+//      token to return to the caller.
+//      It returns the next preprocessed token.
+//
+//      The iterator 'first' is adjusted accordingly.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline typename ContextT::token_type const &
+macromap<ContextT>::expand_tokensequence_worker(
+    ContainerT &pending,
+    unput_queue_iterator<IteratorT, token_type, ContainerT> &first,
+    unput_queue_iterator<IteratorT, token_type, ContainerT> const &last,
+    bool& seen_newline, bool expand_operator_defined)
+{
+// if there exist pending tokens (tokens, which are already preprocessed), then
+// return the next one from there
+    if (!pending.empty()) {
+    on_exit::pop_front<definition_container_type> pop_front_token(pending);
+
+        return act_token = pending.front();
+    }
+
+//  analyze the next element of the given sequence, if it is an
+//  T_IDENTIFIER token, try to replace this as a macro etc.
+    using namespace boost::wave;
+    typedef unput_queue_iterator<IteratorT, token_type, ContainerT> iterator_type;
+
+    if (first != last) {
+    token_id id = token_id(*first);
+
+    // ignore placeholder tokens
+        if (T_PLACEHOLDER == id) {
+        token_type placeholder = *first;
+
+            ++first;
+            if (first == last)
+                return act_token = placeholder;
+            id = token_id(*first);
+        }
+
+        if (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType) ||
+            IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
+            IS_CATEGORY(id, BoolLiteralTokenType))
+        {
+        // try to replace this identifier as a macro
+            if (expand_operator_defined && (*first).get_value() == "defined") {
+            // resolve operator defined()
+                return resolve_defined(first, last, pending);
+            }
+            else if (boost::wave::need_variadics(ctx.get_language()) &&
+                (*first).get_value() == "_Pragma")
+            {
+            // in C99 mode only: resolve the operator _Pragma
+            token_type curr_token = *first;
+
+                if (!resolve_operator_pragma(first, last, pending, seen_newline) ||
+                    pending.size() > 0)
+                {
+                // unknown to us pragma or supplied replacement, return the
+                // next token
+                on_exit::pop_front<definition_container_type> pop_token(pending);
+
+                    return act_token = pending.front();
+                }
+
+            // the operator _Pragma() was eaten completely, continue
+                return act_token = token_type(T_PLACEHOLDER, "_",
+                    curr_token.get_position());
+            }
+
+        token_type name_token (*first);
+        typename defined_macros_type::iterator it;
+
+            if (is_defined(name_token.get_value(), it)) {
+            // the current token contains an identifier, which is currently
+            // defined as a macro
+                if (expand_macro(pending, name_token, it, first, last,
+                      seen_newline, expand_operator_defined))
+                {
+                // the tokens returned by expand_macro should be rescanned
+                // beginning at the last token of the returned replacement list
+                    if (first != last) {
+                    // splice the last token back into the input queue
+                    typename ContainerT::reverse_iterator rit = pending.rbegin();
+
+                        first.get_unput_queue().splice(
+                            first.get_unput_queue().begin(), pending,
+                            (++rit).base(), pending.end());
+                    }
+
+                // fall through ...
+                }
+                else if (!pending.empty()) {
+                // return the first token from the pending queue
+                on_exit::pop_front<definition_container_type> pop_queue (pending);
+
+                    return act_token = pending.front();
+                }
+                else {
+                // macro expansion reached the eoi
+                    return act_token = token_type();
+                }
+
+            // return the next preprocessed token
+                return expand_tokensequence_worker(pending, first, last,
+                    seen_newline, expand_operator_defined);
+            }
+//            else if (expand_operator_defined) {
+//            // in preprocessing conditionals undefined identifiers and keywords
+//            // are to be replaced with '0' (see. C++ standard 16.1.4, [cpp.cond])
+//                return act_token =
+//                    token_type(T_INTLIT, "0", (*first++).get_position());
+//            }
+            else {
+                act_token = name_token;
+                ++first;
+                return act_token;
+            }
+        }
+        else if (expand_operator_defined && IS_CATEGORY(*first, BoolLiteralTokenType)) {
+        // expanding a constant expression inside #if/#elif, special handling
+        // of 'true' and 'false'
+
+        // all remaining identifiers and keywords, except for true and false,
+        // are replaced with the pp-number 0 (C++ standard 16.1.4, [cpp.cond])
+            return act_token = token_type(T_INTLIT, T_TRUE != id ? "0" : "1",
+                (*first++).get_position());
+        }
+        else {
+            act_token = *first;
+            ++first;
+            return act_token;
+        }
+    }
+    return act_token = token_type();     // eoi
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  collect_arguments(): collect the actual arguments of a macro invocation
+//
+//      return the number of successfully detected non-empty arguments
+//
+///////////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT, typename SizeT>
+inline typename std::vector<ContainerT>::size_type
+macromap<ContextT>::collect_arguments (token_type const curr_token,
+    std::vector<ContainerT> &arguments, IteratorT &next,
+    IteratorT const &end, SizeT const &parameter_count, bool& seen_newline)
+#else
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT, typename SizeT>
+inline typename std::vector<ContainerT>::size_type
+macromap<ContextT>::collect_arguments (token_type const curr_token,
+    std::vector<ContainerT> &arguments, IteratorT &next, IteratorT &endparen,
+    IteratorT const &end, SizeT const &parameter_count, bool& seen_newline)
+#endif
+{
+    using namespace boost::wave;
+
+    arguments.push_back(ContainerT());
+
+// collect the actual arguments
+typename std::vector<ContainerT>::size_type count_arguments = 0;
+int nested_parenthesis_level = 1;
+ContainerT *argument = &arguments[0];
+bool was_whitespace = false;
+token_type startof_argument_list = *next;
+
+    while (++next != end && nested_parenthesis_level) {
+    token_id id = token_id(*next);
+
+        if (0 == parameter_count &&
+            !IS_CATEGORY((*next), WhiteSpaceTokenType) && id != T_NEWLINE &&
+            id != T_RIGHTPAREN && id != T_LEFTPAREN)
+        {
+        // there shouldn't be any arguments
+            BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+                too_many_macroarguments, curr_token.get_value().c_str(),
+                main_pos);
+            return 0;
+        }
+
+        switch (static_cast<unsigned int>(id)) {
+        case T_LEFTPAREN:
+            ++nested_parenthesis_level;
+            argument->push_back(*next);
+            was_whitespace = false;
+            break;
+
+        case T_RIGHTPAREN:
+            {
+                if (--nested_parenthesis_level >= 1)
+                    argument->push_back(*next);
+                else {
+                // found closing parenthesis
+//                    trim_sequence(argument);
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
+                    endparen = next;
+#endif
+                    if (parameter_count > 0) {
+                        if (argument->empty() ||
+                            impl::is_whitespace_only(*argument))
+                        {
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+                            if (boost::wave::need_variadics(ctx.get_language())) {
+                            // store a placemarker as the argument
+                                argument->push_back(token_type(T_PLACEMARKER, "\xA7",
+                                    (*next).get_position()));
+                                ++count_arguments;
+                            }
+#endif
+                        }
+                        else {
+                            ++count_arguments;
+                        }
+                    }
+                }
+                was_whitespace = false;
+            }
+            break;
+
+        case T_COMMA:
+            if (1 == nested_parenthesis_level) {
+            // next parameter
+//                trim_sequence(argument);
+                if (argument->empty() ||
+                    impl::is_whitespace_only(*argument))
+                {
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+                    if (boost::wave::need_variadics(ctx.get_language())) {
+                    // store a placemarker as the argument
+                        argument->push_back(token_type(T_PLACEMARKER, "\xA7",
+                            (*next).get_position()));
+                        ++count_arguments;
+                    }
+#endif
+                }
+                else {
+                    ++count_arguments;
+                }
+                arguments.push_back(ContainerT()); // add new arg
+                argument = &arguments[arguments.size()-1];
+            }
+            else {
+            // surrounded by parenthesises, so store to current argument
+                argument->push_back(*next);
+            }
+            was_whitespace = false;
+            break;
+
+        case T_NEWLINE:
+            seen_newline = true;
+            /* fall through */
+        case T_SPACE:
+        case T_SPACE2:
+        case T_CCOMMENT:
+            if (!was_whitespace)
+                argument->push_back(token_type(T_SPACE, " ", (*next).get_position()));
+            was_whitespace = true;
+            break;      // skip whitespace
+
+        case T_PLACEHOLDER:
+            break;      // ignore placeholder
+
+        default:
+            argument->push_back(*next);
+            was_whitespace = false;
+            break;
+        }
+    }
+
+    if (nested_parenthesis_level >= 1) {
+    // missing ')': improperly terminated macro invocation
+        BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+            improperly_terminated_macro, "missing ')'", main_pos);
+        return 0;
+    }
+
+// if no argument was expected and we didn't find any, than remove the empty
+// element
+    if (0 == parameter_count && 0 == count_arguments) {
+        BOOST_ASSERT(1 == arguments.size());
+        arguments.clear();
+    }
+    return count_arguments;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  expand_whole_tokensequence
+//
+//      fully expands a given token sequence
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline void
+macromap<ContextT>::expand_whole_tokensequence(ContainerT &expanded,
+    IteratorT &first, IteratorT const &last,
+    bool expand_operator_defined)
+{
+    typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT>
+        gen_type;
+    typedef typename gen_type::return_type iterator_type;
+
+    ContainerT empty;
+    iterator_type first_it = gen_type::generate(empty, first);
+    iterator_type last_it = gen_type::generate(last);
+
+    on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
+    ContainerT pending_queue;
+    bool seen_newline;
+
+    while (!pending_queue.empty() || first_it != last_it) {
+        expanded.push_back(
+            expand_tokensequence_worker(pending_queue, first_it,
+                    last_it, seen_newline, expand_operator_defined)
+        );
+    }
+
+// should have returned all expanded tokens
+    BOOST_ASSERT(pending_queue.empty()/* && unput_queue.empty()*/);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  expand_argument
+//
+//      fully expands the given argument of a macro call
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename ContainerT>
+inline void
+macromap<ContextT>::expand_argument (
+    typename std::vector<ContainerT>::size_type arg,
+    std::vector<ContainerT> &arguments, std::vector<ContainerT> &expanded_args,
+    bool expand_operator_defined, std::vector<bool> &has_expanded_args)
+{
+    if (!has_expanded_args[arg]) {
+    // expand the argument only once
+        typedef typename std::vector<ContainerT>::value_type::iterator
+            argument_iterator_type;
+
+        argument_iterator_type begin_it = arguments[arg].begin();
+        argument_iterator_type end_it = arguments[arg].end();
+
+        expand_whole_tokensequence(expanded_args[arg], begin_it, end_it,
+            expand_operator_defined);
+        impl::remove_placeholders(expanded_args[arg]);
+        has_expanded_args[arg] = true;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  expand_replacement_list
+//
+//      fully expands the replacement list of a given macro with the
+//      actual arguments/expanded arguments
+//      handles the '#' [cpp.stringize] and the '##' [cpp.concat] operator
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename ContainerT>
+inline void
+macromap<ContextT>::expand_replacement_list(
+    macro_definition_type const &macrodef,
+    std::vector<ContainerT> &arguments, bool expand_operator_defined,
+    ContainerT &expanded)
+{
+    using namespace boost::wave;
+    typedef typename macro_definition_type::const_definition_iterator_t
+        macro_definition_iter_t;
+
+std::vector<ContainerT> expanded_args(arguments.size());
+std::vector<bool> has_expanded_args(arguments.size());
+bool seen_concat = false;
+bool adjacent_concat = false;
+bool adjacent_stringize = false;
+
+    macro_definition_iter_t cend = macrodef.macrodefinition.end();
+    for (macro_definition_iter_t cit = macrodef.macrodefinition.begin();
+        cit != cend; ++cit)
+    {
+    bool use_replaced_arg = true;
+    token_id base_id = BASE_TOKEN(token_id(*cit));
+
+        if (T_POUND_POUND == base_id) {
+        // concatenation operator
+            adjacent_concat = true;
+            seen_concat = true;
+        }
+        else if (T_POUND == base_id) {
+        // stringize operator
+            adjacent_stringize = true;
+        }
+        else {
+            if (adjacent_stringize || adjacent_concat ||
+                T_POUND_POUND == impl::next_token<macro_definition_iter_t>
+                    ::peek(cit, cend))
+            {
+                use_replaced_arg = false;
+            }
+            if (adjacent_concat)    // spaces after '##' ?
+                adjacent_concat = IS_CATEGORY(*cit, WhiteSpaceTokenType);
+        }
+
+        if (IS_CATEGORY((*cit), ParameterTokenType)) {
+        // copy argument 'i' instead of the parameter token i
+        typename ContainerT::size_type i;
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+        bool is_ellipsis = false;
+
+            if (IS_EXTCATEGORY((*cit), ExtParameterTokenType)) {
+                BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
+                i = token_id(*cit) - T_EXTPARAMETERBASE;
+                is_ellipsis = true;
+            }
+            else
+#endif
+            {
+                i = token_id(*cit) - T_PARAMETERBASE;
+            }
+
+            BOOST_ASSERT(i < arguments.size());
+            if (use_replaced_arg) {
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+                if (is_ellipsis) {
+                position_type const &pos = (*cit).get_position();
+
+                    BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
+
+                // ensure all variadic arguments to be expanded
+                    for (typename vector<ContainerT>::size_type arg = i;
+                         arg < expanded_args.size(); ++arg)
+                    {
+                        expand_argument(arg, arguments, expanded_args,
+                            expand_operator_defined, has_expanded_args);
+                    }
+                    impl::replace_ellipsis(expanded_args, i, expanded, pos);
+                }
+                else
+#endif
+                {
+                // ensure argument i to be expanded
+                    expand_argument(i, arguments, expanded_args,
+                        expand_operator_defined, has_expanded_args);
+
+                // replace argument
+                ContainerT const &arg = expanded_args[i];
+
+                    std::copy(arg.begin(), arg.end(),
+                        std::inserter(expanded, expanded.end()));
+                }
+            }
+            else if (adjacent_stringize &&
+                    !IS_CATEGORY(*cit, WhiteSpaceTokenType))
+            {
+            // stringize the current argument
+                BOOST_ASSERT(!arguments[i].empty());
+
+            // safe a copy of the first tokens position (not a reference!)
+            position_type pos ((*arguments[i].begin()).get_position());
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+                if (is_ellipsis && boost::wave::need_variadics(ctx.get_language())) {
+                    impl::trim_sequence_left(arguments[i]);
+                    impl::trim_sequence_right(arguments.back());
+                    expanded.push_back(token_type(T_STRINGLIT,
+                        impl::as_stringlit(arguments, i, pos), pos));
+                }
+                else
+#endif
+                {
+                    impl::trim_sequence(arguments[i]);
+                    expanded.push_back(token_type(T_STRINGLIT,
+                        impl::as_stringlit(arguments[i], pos), pos));
+                }
+                adjacent_stringize = false;
+            }
+            else {
+            // simply copy the original argument (adjacent '##' or '#')
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+                if (is_ellipsis) {
+                position_type const &pos = (*cit).get_position();
+
+                    impl::trim_sequence_left(arguments[i]);
+                    impl::trim_sequence_right(arguments.back());
+                    BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
+                    impl::replace_ellipsis(arguments, i, expanded, pos);
+                }
+                else
+#endif
+                {
+                ContainerT &arg = arguments[i];
+
+                    impl::trim_sequence(arg);
+                    std::copy(arg.begin(), arg.end(),
+                        std::inserter(expanded, expanded.end()));
+                }
+            }
+        }
+        else if (!adjacent_stringize || T_POUND != base_id) {
+        // insert the actual replacement token (if it is not the '#' operator)
+            expanded.push_back(*cit);
+        }
+    }
+
+    if (adjacent_stringize) {
+    // error, '#' should not be the last token
+        BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_operator,
+            "stringize ('#')", main_pos);
+        return;
+    }
+
+// handle the cpp.concat operator
+    if (seen_concat)
+        concat_tokensequence(expanded);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  rescan_replacement_list
+//
+//    As the name implies, this function is used to rescan the replacement list
+//    after the first macro substitution phase.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline void
+macromap<ContextT>::rescan_replacement_list(token_type const &curr_token,
+    macro_definition_type &macro_def, ContainerT &replacement_list,
+    ContainerT &expanded, bool expand_operator_defined,
+    IteratorT &nfirst, IteratorT const &nlast)
+{
+    if (!replacement_list.empty()) {
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+    // remove the placemarkers
+        if (boost::wave::need_variadics(ctx.get_language())) {
+        typename ContainerT::iterator end = replacement_list.end();
+        typename ContainerT::iterator it = replacement_list.begin();
+
+            while (it != end) {
+                using namespace boost::wave;
+                if (T_PLACEMARKER == token_id(*it)) {
+                typename ContainerT::iterator placemarker = it;
+
+                    ++it;
+                    replacement_list.erase(placemarker);
+                }
+                else {
+                    ++it;
+                }
+            }
+        }
+#endif
+
+    // rescan the replacement list, during this rescan the current macro under
+    // expansion isn't available as an expandable macro
+    on_exit::reset<bool> on_exit(macro_def.is_available_for_replacement, false);
+    typename ContainerT::iterator begin_it = replacement_list.begin();
+    typename ContainerT::iterator end_it = replacement_list.end();
+
+        expand_whole_tokensequence(expanded, begin_it, end_it,
+            expand_operator_defined);
+
+    // trim replacement list, leave placeholder tokens untouched
+        impl::trim_replacement_list(expanded);
+    }
+
+    if (expanded.empty()) {
+    // the resulting replacement list should contain at least a placeholder
+    // token
+        expanded.push_back(token_type(T_PLACEHOLDER, "_", curr_token.get_position()));
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  expand_macro(): expands a defined macro
+//
+//      This functions tries to expand the macro, to which points the 'first'
+//      iterator. The functions eats up more tokens, if the macro to expand is
+//      a function-like macro.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline bool
+macromap<ContextT>::expand_macro(ContainerT &expanded,
+    token_type const &curr_token, typename defined_macros_type::iterator it,
+    IteratorT &first, IteratorT const &last,
+    bool& seen_newline, bool expand_operator_defined,
+    defined_macros_type *scope, ContainerT *queue_symbol)
+{
+    using namespace boost::wave;
+
+    if (0 == scope) scope = current_macros;
+
+    BOOST_ASSERT(T_IDENTIFIER == token_id(curr_token) ||
+        IS_CATEGORY(token_id(curr_token), KeywordTokenType) ||
+        IS_EXTCATEGORY(token_id(curr_token), OperatorTokenType|AltExtTokenType) ||
+        IS_CATEGORY(token_id(curr_token), BoolLiteralTokenType));
+
+    if (it == scope->end()) {
+        ++first;    // advance
+
+    // try to expand a predefined macro (__FILE__, __LINE__ or __INCLUDE_LEVEL__)
+        if (expand_predefined_macro(curr_token, expanded))
+            return false;
+
+    // not defined as a macro
+        if (0 != queue_symbol) {
+            expanded.splice(expanded.end(), *queue_symbol);
+        }
+        else {
+            expanded.push_back(curr_token);
+        }
+        return false;
+    }
+
+// ensure the parameters to be replaced with special parameter tokens
+macro_definition_type &macro_def = *(*it).second.get();
+
+    macro_def.replace_parameters();
+
+// test if this macro is currently available for replacement
+    if (!macro_def.is_available_for_replacement) {
+    // this macro is marked as non-replaceable
+    // copy the macro name itself
+        if (0 != queue_symbol) {
+            queue_symbol->push_back(token_type(T_NONREPLACABLE_IDENTIFIER,
+                curr_token.get_value(), curr_token.get_position()));
+            expanded.splice(expanded.end(), *queue_symbol);
+        }
+        else {
+            expanded.push_back(token_type(T_NONREPLACABLE_IDENTIFIER,
+                curr_token.get_value(), curr_token.get_position()));
+        }
+        ++first;
+        return false;
+    }
+
+// try to replace the current identifier as a function-like macro
+ContainerT replacement_list;
+
+    if (T_LEFTPAREN == impl::next_token<IteratorT>::peek(first, last)) {
+    // called as a function-like macro
+        impl::skip_to_token(ctx, first, last, T_LEFTPAREN, seen_newline);
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
+        IteratorT seqstart = first;
+        IteratorT seqend = first;
+#endif
+
+        if (macro_def.is_functionlike) {
+        // defined as a function-like macro
+
+        // collect the arguments
+        std::vector<ContainerT> arguments;
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+        typename std::vector<ContainerT>::size_type count_args =
+            collect_arguments (curr_token, arguments, first, last,
+                macro_def.macroparameters.size(), seen_newline);
+#else
+        typename std::vector<ContainerT>::size_type count_args =
+            collect_arguments (curr_token, arguments, first, seqend, last,
+                macro_def.macroparameters.size(), seen_newline);
+#endif
+
+        // verify the parameter count
+            if (count_args < macro_def.macroparameters.size() ||
+                arguments.size() < macro_def.macroparameters.size())
+            {
+                if (count_args != arguments.size()) {
+                // must been at least one empty argument in C++ mode
+                    BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+                        empty_macroarguments, curr_token.get_value().c_str(),
+                        main_pos);
+                }
+                else {
+                // too few macro arguments
+                    BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+                        too_few_macroarguments, curr_token.get_value().c_str(),
+                        main_pos);
+                }
+                return false;
+            }
+
+            if (count_args > macro_def.macroparameters.size() ||
+                arguments.size() > macro_def.macroparameters.size())
+            {
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+                if (!macro_def.has_ellipsis)
+#endif
+                {
+                // too many macro arguments
+                    BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+                        too_many_macroarguments,
+                        curr_token.get_value().c_str(), main_pos);
+                    return false;
+                }
+            }
+
+        // inject tracing support
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+            ctx.get_hooks().expanding_function_like_macro(
+                macro_def.macroname, macro_def.macroparameters,
+                macro_def.macrodefinition, curr_token, arguments);
+#else
+            if (ctx.get_hooks().expanding_function_like_macro(ctx.derived(),
+                    macro_def.macroname, macro_def.macroparameters,
+                    macro_def.macrodefinition, curr_token, arguments,
+                    seqstart, seqend))
+            {
+//                 // do not expand this macro, just copy the whole sequence
+//                 expanded.push_back(curr_token);
+//                 std::copy(seqstart, first,
+//                     std::inserter(expanded, expanded.end()));
+                // do not expand macro, just copy macro name and parenthesis
+                expanded.push_back(curr_token);
+                expanded.push_back(*seqstart);
+                first = ++seqstart;
+                return false;           // no further preprocessing required
+            }
+#endif
+
+        // expand the replacement list of this macro
+            expand_replacement_list(macro_def, arguments, expand_operator_defined,
+                replacement_list);
+        }
+        else {
+        // defined as an object-like macro
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+            ctx.get_hooks().expanding_object_like_macro(
+                macro_def.macroname, macro_def.macrodefinition, curr_token);
+#else
+            if (ctx.get_hooks().expanding_object_like_macro(ctx.derived(),
+                  macro_def.macroname, macro_def.macrodefinition, curr_token))
+            {
+                // do not expand this macro, just copy the whole sequence
+                expanded.push_back(curr_token);
+                return false;           // no further preprocessing required
+            }
+#endif
+
+        bool found = false;
+        impl::find_concat_operator concat_tag(found);
+
+            std::remove_copy_if(macro_def.macrodefinition.begin(),
+                macro_def.macrodefinition.end(),
+                std::inserter(replacement_list, replacement_list.end()),
+                concat_tag);
+
+        // handle concatenation operators
+            if (found && !concat_tokensequence(replacement_list))
+                return false;
+        }
+    }
+    else {
+    // called as an object like macro
+        if ((*it).second->is_functionlike) {
+        // defined as a function-like macro
+            if (0 != queue_symbol) {
+                queue_symbol->push_back(curr_token);
+                expanded.splice(expanded.end(), *queue_symbol);
+            }
+            else {
+                expanded.push_back(curr_token);
+            }
+            ++first;                // skip macro name
+            return false;           // no further preprocessing required
+        }
+        else {
+        // defined as an object-like macro (expand it)
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+            ctx.get_hooks().expanding_object_like_macro(
+                macro_def.macroname, macro_def.macrodefinition, curr_token);
+#else
+            if (ctx.get_hooks().expanding_object_like_macro(ctx.derived(),
+                  macro_def.macroname, macro_def.macrodefinition, curr_token))
+            {
+                // do not expand this macro, just copy the whole sequence
+                expanded.push_back(curr_token);
+                ++first;                // skip macro name
+                return false;           // no further preprocessing required
+            }
+#endif
+
+        bool found = false;
+        impl::find_concat_operator concat_tag(found);
+
+            std::remove_copy_if(macro_def.macrodefinition.begin(),
+                macro_def.macrodefinition.end(),
+                std::inserter(replacement_list, replacement_list.end()),
+                concat_tag);
+
+        // handle concatenation operators
+            if (found && !concat_tokensequence(replacement_list))
+                return false;
+
+            ++first;                // skip macro name
+        }
+    }
+
+// rescan the replacement list
+ContainerT expanded_list;
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+    ctx.get_hooks().expanded_macro(replacement_list);
+#else
+    ctx.get_hooks().expanded_macro(ctx.derived(), replacement_list);
+#endif
+
+    rescan_replacement_list(curr_token, macro_def, replacement_list,
+        expanded_list, expand_operator_defined, first, last);
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+    ctx.get_hooks().rescanned_macro(expanded_list);
+#else
+    ctx.get_hooks().rescanned_macro(ctx.derived(), expanded_list);
+#endif
+    expanded.splice(expanded.end(), expanded_list);
+    return true;        // rescan is required
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  If the token under inspection points to a certain predefined macro it will
+//  be expanded, otherwise false is returned.
+//  (only __FILE__, __LINE__ and __INCLUDE_LEVEL__ macros are expanded here)
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename ContainerT>
+inline bool
+macromap<ContextT>::expand_predefined_macro(token_type const &curr_token,
+    ContainerT &expanded)
+{
+    using namespace boost::wave;
+
+string_type const &value = curr_token.get_value();
+
+    if (value.size() < 8 || '_' != value[0] || '_' != value[1])
+        return false;       // quick check failed
+
+    if (value == "__LINE__") {
+    // expand the __LINE__ macro
+    char buffer[22];    // 21 bytes holds all NUL-terminated unsigned 64-bit numbers
+
+        using namespace std;    // for some systems sprintf is in namespace std
+        sprintf(buffer, "%ld", main_pos.get_line());
+        expanded.push_back(token_type(T_INTLIT, buffer, curr_token.get_position()));
+        return true;
+    }
+    else if (value == "__FILE__") {
+    // expand the __FILE__ macro
+        namespace fs = boost::filesystem;
+
+    std::string file("\"");
+    fs::path filename(wave::util::create_path(main_pos.get_file().c_str()));
+
+        using boost::wave::util::impl::escape_lit;
+        file += escape_lit(wave::util::native_file_string(filename)) + "\"";
+        expanded.push_back(token_type(T_STRINGLIT, file.c_str(),
+            curr_token.get_position()));
+        return true;
+    }
+    else if (value == "__INCLUDE_LEVEL__") {
+    // expand the __INCLUDE_LEVEL__ macro
+    char buffer[22];    // 21 bytes holds all NUL-terminated unsigned 64-bit numbers
+
+        using namespace std;    // for some systems sprintf is in namespace std
+        sprintf(buffer, "%d", (int)ctx.get_iteration_depth());
+        expanded.push_back(token_type(T_INTLIT, buffer, curr_token.get_position()));
+        return true;
+    }
+    return false;   // no predefined token
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  resolve_defined(): resolve the operator defined() and replace it with the
+//                     correct T_INTLIT token
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline typename ContextT::token_type const &
+macromap<ContextT>::resolve_defined(IteratorT &first,
+    IteratorT const &last, ContainerT &pending)
+{
+    using namespace boost::wave;
+    using namespace boost::wave::grammars;
+
+ContainerT result;
+IteratorT start = first;
+boost::spirit::classic::parse_info<IteratorT> hit =
+    defined_grammar_gen<typename ContextT::lexer_type>::
+        parse_operator_defined(start, last, result);
+
+    if (!hit.hit) {
+        string_type msg ("defined(): ");
+        msg = msg + util::impl::as_string<string_type>(first, last);
+        BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_expression,
+            msg.c_str(), main_pos);
+
+    // insert a dummy token
+        pending.push_back(token_type(T_INTLIT, "0", main_pos));
+    }
+    else {
+        impl::assign_iterator<IteratorT>::do_(first, hit.stop);
+
+    // insert a token, which reflects the outcome
+        pending.push_back(token_type(T_INTLIT,
+            is_defined(result.begin(), result.end()) ? "1" : "0",
+            main_pos));
+    }
+
+on_exit::pop_front<definition_container_type> pop_front_token(pending);
+
+    return act_token = pending.front();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  resolve_operator_pragma(): resolve the operator _Pragma() and dispatch to
+//                             the associated action
+//
+//      This function returns true, if the pragma was correctly interpreted.
+//      The iterator 'first' is positioned behind the closing ')'.
+//      This function returns false, if the _Pragma was not known, the
+//      preprocessed token sequence is pushed back to the 'pending' sequence.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline bool
+macromap<ContextT>::resolve_operator_pragma(IteratorT &first,
+    IteratorT const &last, ContainerT &pending, bool& seen_newline)
+{
+// isolate the parameter of the operator _Pragma
+    token_type pragma_token = *first;
+
+    if (!impl::skip_to_token(ctx, first, last, T_LEFTPAREN, seen_newline)) {
+    // illformed operator _Pragma
+        BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_expression,
+            "operator _Pragma()", pragma_token.get_position());
+        return false;
+    }
+
+    std::vector<ContainerT> arguments;
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+    typename std::vector<ContainerT>::size_type count_args =
+        collect_arguments (pragma_token, arguments, first, last, 1, seen_newline);
+#else
+    IteratorT endparen = first;
+    typename std::vector<ContainerT>::size_type count_args =
+        collect_arguments (pragma_token, arguments, first, endparen, last, 1,
+            seen_newline);
+#endif
+
+// verify the parameter count
+    if (pragma_token.get_position().get_file().empty())
+        pragma_token.set_position(act_token.get_position());
+
+    if (count_args < 1 || arguments.size() < 1) {
+    // too few macro arguments
+        BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, too_few_macroarguments,
+            pragma_token.get_value().c_str(), pragma_token.get_position());
+        return false;
+    }
+    if (count_args > 1 || arguments.size() > 1) {
+    // too many macro arguments
+        BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, too_many_macroarguments,
+            pragma_token.get_value().c_str(), pragma_token.get_position());
+        return false;
+    }
+
+// preprocess the pragma token body
+    typedef typename std::vector<ContainerT>::value_type::iterator
+        argument_iterator_type;
+
+    ContainerT expanded;
+    argument_iterator_type begin_it = arguments[0].begin();
+    argument_iterator_type end_it = arguments[0].end();
+    expand_whole_tokensequence(expanded, begin_it, end_it, false);
+
+// un-escape the parameter of the operator _Pragma
+    typedef typename token_type::string_type string_type;
+
+    string_type pragma_cmd;
+    typename ContainerT::const_iterator end_exp = expanded.end();
+    for (typename ContainerT::const_iterator it_exp = expanded.begin();
+         it_exp != end_exp; ++it_exp)
+    {
+        if (T_EOF == token_id(*it_exp))
+            break;
+        if (IS_CATEGORY(*it_exp, WhiteSpaceTokenType))
+            continue;
+
+        if (T_STRINGLIT != token_id(*it_exp)) {
+        // ill formed operator _Pragma
+            BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+                ill_formed_pragma_option, "_Pragma",
+                pragma_token.get_position());
+            return false;
+        }
+        if (pragma_cmd.size() > 0) {
+        // there should be exactly one string literal (string literals are to
+        // be concatenated at translation phase 6, but _Pragma operators are
+        // to be executed at translation phase 4)
+            BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+                ill_formed_pragma_option, "_Pragma",
+                pragma_token.get_position());
+            return false;
+        }
+
+    // remove the '\"' and concat all given string literal-values
+        string_type token_str = (*it_exp).get_value();
+        pragma_cmd += token_str.substr(1, token_str.size() - 2);
+    }
+    string_type pragma_cmd_unesc = impl::unescape_lit(pragma_cmd);
+
+// tokenize the pragma body
+    typedef typename ContextT::lexer_type lexer_type;
+
+    ContainerT pragma;
+    std::string pragma_cmd_str(pragma_cmd_unesc.c_str());
+    lexer_type it = lexer_type(pragma_cmd_str.begin(), pragma_cmd_str.end(),
+        pragma_token.get_position(), ctx.get_language());
+    lexer_type end = lexer_type();
+    for (/**/; it != end; ++it)
+        pragma.push_back(*it);
+
+// analyze the preprocessed token sequence and eventually dispatch to the
+// associated action
+    if (interpret_pragma(ctx, pragma_token, pragma.begin(), pragma.end(),
+        pending))
+    {
+        return true;    // successfully recognized a wave specific pragma
+    }
+
+// unknown pragma token sequence, push it back and return to the caller
+    pending.push_front(token_type(T_SPACE, " ", pragma_token.get_position()));
+    pending.push_front(token_type(T_RIGHTPAREN, ")", pragma_token.get_position()));
+    pending.push_front(token_type(T_STRINGLIT, string_type("\"") + pragma_cmd + "\"",
+        pragma_token.get_position()));
+    pending.push_front(token_type(T_LEFTPAREN, "(", pragma_token.get_position()));
+    pending.push_front(pragma_token);
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Test, whether the result of a concat operator is well formed or not.
+//
+//  This is done by re-scanning (re-tokenizing) the resulting token sequence,
+//  which should give back exactly one token.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename ContainerT>
+inline bool
+macromap<ContextT>::is_valid_concat(string_type new_value,
+    position_type const &pos, ContainerT &rescanned)
+{
+// re-tokenize the newly generated string
+    typedef typename ContextT::lexer_type lexer_type;
+
+    std::string value_to_test(new_value.c_str());
+
+    boost::wave::language_support lang =
+        boost::wave::enable_prefer_pp_numbers(ctx.get_language());
+    lang = boost::wave::enable_single_line(lang);
+
+    lexer_type it = lexer_type(value_to_test.begin(), value_to_test.end(), pos,
+        lang);
+    lexer_type end = lexer_type();
+    for (/**/; it != end && T_EOF != token_id(*it); ++it)
+    {
+        // as of Wave V2.0.7 pasting of tokens is valid only if the resulting
+        // tokens are pp_tokens (as mandated by C++11)
+        if (!is_pp_token(*it))
+            return false;
+        rescanned.push_back(*it);
+    }
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+    if (boost::wave::need_variadics(ctx.get_language()))
+        return true;       // in variadics mode token pasting is well defined
+#endif
+
+// test if the newly generated token sequence contains more than 1 token
+    return 1 == rescanned.size();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Handle all occurrences of the concatenation operator '##' inside the given
+//  token sequence.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename Context>
+inline void report_invalid_concatenation(Context& ctx,
+    typename Context::token_type const& prev,
+    typename Context::token_type const& next,
+    typename Context::position_type const& main_pos)
+{
+typename Context::string_type error_string("\"");
+
+    error_string += prev.get_value();
+    error_string += "\" and \"";
+    error_string += next.get_value();
+    error_string += "\"";
+    BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_concat,
+        error_string.c_str(), main_pos);
+}
+
+template <typename ContextT>
+template <typename ContainerT>
+inline bool
+macromap<ContextT>::concat_tokensequence(ContainerT &expanded)
+{
+    using namespace boost::wave;
+    typedef typename ContainerT::iterator iterator_type;
+
+    iterator_type end = expanded.end();
+    iterator_type prev = end;
+    for (iterator_type it = expanded.begin(); it != end; /**/)
+    {
+        if (T_POUND_POUND == BASE_TOKEN(token_id(*it))) {
+        iterator_type next = it;
+
+            ++next;
+            if (prev == end || next == end) {
+            // error, '##' should be in between two tokens
+                BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+                    ill_formed_operator, "concat ('##')", main_pos);
+                return false;
+            }
+
+        // replace prev##next with the concatenated value, skip whitespace
+        // before and after the '##' operator
+            while (IS_CATEGORY(*next, WhiteSpaceTokenType)) {
+                ++next;
+                if (next == end) {
+                // error, '##' should be in between two tokens
+                    BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+                        ill_formed_operator, "concat ('##')", main_pos);
+                    return false;
+                }
+            }
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+            if (boost::wave::need_variadics(ctx.get_language())) {
+                if (T_PLACEMARKER == token_id(*next)) {
+                // remove the '##' and the next tokens from the sequence
+                iterator_type first_to_delete = prev;
+
+                    expanded.erase(++first_to_delete, ++next);
+                    it = next;
+                    continue;
+                }
+                else if (T_PLACEMARKER == token_id(*prev)) {
+                // remove the '##' and the next tokens from the sequence
+                iterator_type first_to_delete = prev;
+
+                    *prev = *next;
+                    expanded.erase(++first_to_delete, ++next);
+                    it = next;
+                    continue;
+                }
+            }
+#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+
+        // test if the concat operator has to concatenate two unrelated
+        // tokens i.e. the result yields more then one token
+        string_type concat_result;
+        ContainerT rescanned;
+
+            concat_result = ((*prev).get_value() + (*next).get_value());
+
+        // analyze the validity of the concatenation result
+            if (!is_valid_concat(concat_result, (*prev).get_position(),
+                    rescanned) &&
+                !IS_CATEGORY(*prev, WhiteSpaceTokenType) &&
+                !IS_CATEGORY(*next, WhiteSpaceTokenType))
+            {
+                report_invalid_concatenation(ctx, *prev, *next, main_pos);
+                return false;
+            }
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+            if (boost::wave::need_variadics(ctx.get_language())) {
+            // remove the prev, '##' and the next tokens from the sequence
+                expanded.erase(prev, ++next);       // remove not needed tokens
+
+            // some stl implementations clear() the container if we erased all
+            // the elements, which orphans all iterators. we re-initialize these
+            // here
+                if (expanded.empty())
+                    end = next = expanded.end();
+
+            // replace the old token (pointed to by *prev) with the re-tokenized
+            // sequence
+                expanded.splice(next, rescanned);
+
+            // the last token of the inserted sequence is the new previous
+                prev = next;
+                if (next != expanded.end())
+                    --prev;
+            }
+            else
+#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+            {
+            // we leave the token_id unchanged, but unmark the token as
+            // disabled, if appropriate
+                (*prev).set_value(concat_result);
+                if (T_NONREPLACABLE_IDENTIFIER == token_id(*prev))
+                    (*prev).set_token_id(T_IDENTIFIER);
+
+            // remove the '##' and the next tokens from the sequence
+            iterator_type first_to_delete = prev;
+
+                expanded.erase(++first_to_delete, ++next);
+            }
+            it = next;
+            continue;
+        }
+
+    // save last non-whitespace token position
+        if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
+            prev = it;
+
+        ++it;           // next token, please
+    }
+    return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  predefine_macro(): predefine a single macro
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+macromap<ContextT>::predefine_macro(defined_macros_type *scope,
+    string_type const &name, token_type const &t)
+{
+definition_container_type macrodefinition;
+std::vector<token_type> param;
+
+    macrodefinition.push_back(t);
+    add_macro(token_type(T_IDENTIFIER, name, t.get_position()),
+        false, param, macrodefinition, true, scope);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  init_predefined_macros(): init the predefined macros
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+macromap<ContextT>::init_predefined_macros(char const *fname,
+    defined_macros_type *scope, bool at_global_scope)
+{
+// if no scope is given, use the current one
+defined_macros_type *current_scope = scope ? scope : current_macros;
+
+// first, add the static macros
+position_type pos("<built-in>");
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+    if (boost::wave::need_c99(ctx.get_language())) {
+    // define C99 specifics
+        for (int i = 0; 0 != predef.static_data_c99(i).name; ++i) {
+            predefined_macros::static_macros const& m = predef.static_data_c99(i);
+            predefine_macro(current_scope, m.name,
+                token_type(m.token_id, m.value, pos));
+        }
+    }
+    else
+#endif
+    {
+#if BOOST_WAVE_SUPPORT_CPP0X != 0
+        if (boost::wave::need_cpp0x(ctx.get_language())) {
+        // define C++11 specifics
+            for (int i = 0; 0 != predef.static_data_cpp0x(i).name; ++i) {
+                predefined_macros::static_macros const& m = predef.static_data_cpp0x(i);
+                predefine_macro(current_scope, m.name,
+                    token_type(m.token_id, m.value, pos));
+            }
+        }
+        else
+#endif
+        {
+        // define C++ specifics
+            for (int i = 0; 0 != predef.static_data_cpp(i).name; ++i) {
+                predefined_macros::static_macros const& m = predef.static_data_cpp(i);
+                predefine_macro(current_scope, m.name,
+                    token_type(m.token_id, m.value, pos));
+            }
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+        // define __WAVE_HAS_VARIADICS__, if appropriate
+            if (boost::wave::need_variadics(ctx.get_language())) {
+                predefine_macro(current_scope, "__WAVE_HAS_VARIADICS__",
+                    token_type(T_INTLIT, "1", pos));
+            }
+#endif
+        }
+    }
+
+// predefine the __BASE_FILE__ macro which contains the main file name
+    namespace fs = boost::filesystem;
+    if (string_type(fname) != "<Unknown>") {
+    fs::path filename(create_path(fname));
+
+        using boost::wave::util::impl::escape_lit;
+        predefine_macro(current_scope, "__BASE_FILE__",
+            token_type(T_STRINGLIT, string_type("\"") +
+                escape_lit(native_file_string(filename)).c_str() + "\"", pos));
+        base_name = fname;
+    }
+    else if (!base_name.empty()) {
+    fs::path filename(create_path(base_name.c_str()));
+
+        using boost::wave::util::impl::escape_lit;
+        predefine_macro(current_scope, "__BASE_FILE__",
+            token_type(T_STRINGLIT, string_type("\"") +
+                escape_lit(native_file_string(filename)).c_str() + "\"", pos));
+    }
+
+// now add the dynamic macros
+    for (int j = 0; 0 != predef.dynamic_data(j).name; ++j) {
+        predefined_macros::dynamic_macros const& m = predef.dynamic_data(j);
+        predefine_macro(current_scope, m.name,
+            token_type(m.token_id, (predef.* m.generator)(), pos));
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  reset_macromap(): initialize the internal macro symbol namespace
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+macromap<ContextT>::reset_macromap()
+{
+    current_macros->clear();
+    predef.reset();
+    act_token = token_type();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+}}}   // namespace boost::wave::util
+
+#if BOOST_WAVE_SERIALIZATION != 0
+namespace boost { namespace serialization {
+
+template<typename ContextT>
+struct version<boost::wave::util::macromap<ContextT> >
+{
+    typedef boost::wave::util::macromap<ContextT> target_type;
+    typedef mpl::int_<target_type::version> type;
+    typedef mpl::integral_c_tag tag;
+    BOOST_STATIC_CONSTANT(unsigned int, value = version::type::value);
+};
+
+}}    // namespace boost::serialization
+#endif
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED)