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