Chris@16: /*============================================================================= Chris@16: Boost.Wave: A Standard compliant C++ preprocessor library Chris@16: Chris@16: Definition of the preprocessor iterator 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_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED) Chris@16: #define CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED Chris@16: 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: #include Chris@16: #include Chris@16: #include Chris@16: 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: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0 Chris@16: #include Chris@16: #endif Chris@16: Chris@16: #include 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 { Chris@16: namespace wave { Chris@16: namespace util { Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // retrieve the macro name from the parse tree Chris@16: template < Chris@16: typename ContextT, typename ParseNodeT, typename TokenT, Chris@16: typename PositionT Chris@16: > Chris@16: inline bool Chris@16: retrieve_macroname(ContextT& ctx, ParseNodeT const &node, Chris@16: boost::spirit::classic::parser_id id, TokenT ¯oname, PositionT& act_pos, Chris@16: bool update_position) Chris@16: { Chris@16: ParseNodeT const *name_node = 0; Chris@16: Chris@16: using boost::spirit::classic::find_node; Chris@16: if (!find_node(node, id, &name_node)) Chris@16: { Chris@16: // ill formed define statement (unexpected, should not happen) Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_define_statement, Chris@16: "bad parse tree (unexpected)", act_pos); Chris@16: return false; Chris@16: } Chris@16: Chris@16: typename ParseNodeT::children_t const &children = name_node->children; Chris@16: Chris@16: if (0 == children.size() || Chris@16: children.front().value.begin() == children.front().value.end()) Chris@16: { Chris@16: // ill formed define statement (unexpected, should not happen) Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_define_statement, Chris@16: "bad parse tree (unexpected)", act_pos); Chris@16: return false; Chris@16: } Chris@16: Chris@16: // retrieve the macro name Chris@16: macroname = *children.front().value.begin(); Chris@16: if (update_position) { Chris@16: macroname.set_position(act_pos); Chris@16: act_pos.set_column(act_pos.get_column() + macroname.get_value().size()); Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // retrieve the macro parameters or the macro definition from the parse tree Chris@16: template Chris@16: inline bool Chris@16: retrieve_macrodefinition( Chris@16: ParseNodeT const &node, boost::spirit::classic::parser_id id, Chris@16: ContainerT ¯odefinition, PositionT& act_pos, bool update_position) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: typedef typename ParseNodeT::const_tree_iterator const_tree_iterator; Chris@16: Chris@16: // find macro parameters/macro definition inside the parse tree Chris@16: std::pair nodes; Chris@16: Chris@16: using boost::spirit::classic::get_node_range; Chris@16: if (get_node_range(node, id, nodes)) { Chris@16: // copy all parameters to the supplied container Chris@16: typename ContainerT::iterator last_nonwhite = macrodefinition.end(); Chris@16: const_tree_iterator end = nodes.second; Chris@16: Chris@16: for (const_tree_iterator cit = nodes.first; cit != end; ++cit) { Chris@16: if ((*cit).value.begin() != (*cit).value.end()) { Chris@16: typename ContainerT::iterator inserted = macrodefinition.insert( Chris@16: macrodefinition.end(), *(*cit).value.begin()); Chris@16: Chris@16: if (!IS_CATEGORY(macrodefinition.back(), WhiteSpaceTokenType) && Chris@16: T_NEWLINE != token_id(macrodefinition.back()) && Chris@16: T_EOF != token_id(macrodefinition.back())) Chris@16: { Chris@16: last_nonwhite = inserted; Chris@16: } Chris@16: Chris@16: if (update_position) { Chris@16: (*inserted).set_position(act_pos); Chris@16: act_pos.set_column( Chris@16: act_pos.get_column() + (*inserted).get_value().size()); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: // trim trailing whitespace (leading whitespace is trimmed by the grammar) Chris@16: if (last_nonwhite != macrodefinition.end()) { Chris@16: if (update_position) { Chris@16: act_pos.set_column((*last_nonwhite).get_position().get_column() + Chris@16: (*last_nonwhite).get_value().size()); Chris@16: } Chris@16: macrodefinition.erase(++last_nonwhite, macrodefinition.end()); Chris@16: } Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: #if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0 Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // add an additional predefined macro given by a string (MACRO(x)=definition) Chris@16: template Chris@16: bool add_macro_definition(ContextT &ctx, std::string macrostring, Chris@16: bool is_predefined, boost::wave::language_support language) Chris@16: { Chris@16: typedef typename ContextT::token_type token_type; Chris@16: typedef typename ContextT::lexer_type lexer_type; Chris@16: typedef typename token_type::position_type position_type; Chris@16: typedef boost::wave::grammars::predefined_macros_grammar_gen Chris@16: predef_macros_type; Chris@16: Chris@16: using namespace boost::wave; Chris@16: using namespace std; // isspace is in std namespace for some systems Chris@16: Chris@16: // skip leading whitespace Chris@16: std::string::iterator begin = macrostring.begin(); Chris@16: std::string::iterator end = macrostring.end(); Chris@16: Chris@16: while(begin != end && isspace(*begin)) Chris@16: ++begin; Chris@16: Chris@16: // parse the macro definition Chris@16: position_type act_pos(""); Chris@16: boost::spirit::classic::tree_parse_info hit = Chris@16: predef_macros_type::parse_predefined_macro( Chris@16: lexer_type(begin, end, position_type(), language), lexer_type()); Chris@16: Chris@16: if (!hit.match || (!hit.full && T_EOF != token_id(*hit.stop))) { Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_macro_definition, Chris@16: macrostring.c_str(), act_pos); Chris@16: return false; Chris@16: } Chris@16: Chris@16: // retrieve the macro definition from the parse tree Chris@16: token_type macroname; Chris@16: std::vector macroparameters; Chris@16: typename ContextT::token_sequence_type macrodefinition; Chris@16: bool has_parameters = false; Chris@16: Chris@16: if (!boost::wave::util::retrieve_macroname(ctx, *hit.trees.begin(), Chris@16: BOOST_WAVE_PLAIN_DEFINE_ID, macroname, act_pos, true)) Chris@16: return false; Chris@16: has_parameters = boost::wave::util::retrieve_macrodefinition(*hit.trees.begin(), Chris@16: BOOST_WAVE_MACRO_PARAMETERS_ID, macroparameters, act_pos, true); Chris@16: boost::wave::util::retrieve_macrodefinition(*hit.trees.begin(), Chris@16: BOOST_WAVE_MACRO_DEFINITION_ID, macrodefinition, act_pos, true); Chris@16: Chris@16: // get rid of trailing T_EOF Chris@16: if (!macrodefinition.empty() && token_id(macrodefinition.back()) == T_EOF) Chris@16: macrodefinition.pop_back(); Chris@16: Chris@16: // If no macrodefinition is given, and the macro string does not end with a Chris@16: // '=', then the macro should be defined with the value '1' Chris@16: if (macrodefinition.empty() && '=' != macrostring[macrostring.size()-1]) Chris@16: macrodefinition.push_back(token_type(T_INTLIT, "1", act_pos)); Chris@16: Chris@16: // add the new macro to the macromap Chris@16: return ctx.add_macro_definition(macroname, has_parameters, macroparameters, Chris@16: macrodefinition, is_predefined); Chris@16: } Chris@16: #endif // BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0 Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: } // namespace util Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // forward declaration Chris@16: template class pp_iterator; Chris@16: Chris@16: namespace impl { Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // pp_iterator_functor Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: class pp_iterator_functor { Chris@16: Chris@16: public: Chris@16: // interface to the boost::spirit::classic::iterator_policies::functor_input policy Chris@16: typedef typename ContextT::token_type result_type; Chris@16: Chris@16: // eof token Chris@16: static result_type const eof; Chris@16: Chris@16: private: Chris@16: // type of a token sequence Chris@16: typedef typename ContextT::token_sequence_type token_sequence_type; Chris@16: Chris@16: typedef typename ContextT::lexer_type lexer_type; Chris@16: typedef typename result_type::string_type string_type; Chris@16: typedef typename result_type::position_type position_type; Chris@16: typedef boost::wave::grammars::cpp_grammar_gen Chris@16: cpp_grammar_type; Chris@16: Chris@16: // iteration context related types (an iteration context represents a current Chris@16: // position in an included file) Chris@16: typedef base_iteration_context Chris@16: base_iteration_context_type; Chris@16: typedef iteration_context iteration_context_type; Chris@16: Chris@16: // parse tree related types Chris@16: typedef typename cpp_grammar_type::node_factory_type node_factory_type; Chris@16: typedef boost::spirit::classic::tree_parse_info Chris@16: tree_parse_info_type; Chris@16: typedef boost::spirit::classic::tree_match Chris@16: parse_tree_match_type; Chris@16: typedef typename parse_tree_match_type::node_t parse_node_type; // tree_node > Chris@16: typedef typename parse_tree_match_type::parse_node_t parse_node_value_type; // node_val_data<> Chris@16: typedef typename parse_tree_match_type::container_t parse_tree_type; // parse_node_type::children_t Chris@16: Chris@16: public: Chris@16: template Chris@16: pp_iterator_functor(ContextT &ctx_, IteratorT const &first_, Chris@16: IteratorT const &last_, typename ContextT::position_type const &pos_) Chris@16: : ctx(ctx_), Chris@16: iter_ctx(new base_iteration_context_type(ctx, Chris@16: lexer_type(first_, last_, pos_, Chris@16: boost::wave::enable_prefer_pp_numbers(ctx.get_language())), Chris@16: lexer_type(), Chris@16: pos_.get_file().c_str() Chris@16: )), Chris@16: seen_newline(true), skipped_newline(false), Chris@16: must_emit_line_directive(false), act_pos(ctx_.get_main_pos()), Chris@16: whitespace(boost::wave::need_insert_whitespace(ctx.get_language())) Chris@16: { Chris@16: act_pos.set_file(pos_.get_file()); Chris@16: #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 Chris@16: ctx_.set_current_filename(pos_.get_file().c_str()); Chris@16: #endif Chris@16: iter_ctx->emitted_lines = (unsigned int)(-1); // force #line directive Chris@16: } Chris@16: Chris@16: // get the next preprocessed token Chris@16: result_type const &operator()(); Chris@16: Chris@16: // get the last recognized token (for error processing etc.) Chris@16: result_type const ¤t_token() const { return act_token; } Chris@16: Chris@16: protected: Chris@16: friend class pp_iterator; Chris@16: bool on_include_helper(char const *t, char const *s, bool is_system, Chris@16: bool include_next); Chris@16: Chris@16: protected: Chris@16: result_type const &get_next_token(); Chris@16: result_type const &pp_token(); Chris@16: Chris@16: template Chris@16: bool extract_identifier(IteratorT &it); Chris@16: template Chris@16: bool ensure_is_last_on_line(IteratorT& it, bool call_hook = true); Chris@16: template Chris@16: bool skip_to_eol_with_check(IteratorT &it, bool call_hook = true); Chris@16: Chris@16: bool pp_directive(); Chris@16: template Chris@16: bool handle_pp_directive(IteratorT &it); Chris@16: bool dispatch_directive(tree_parse_info_type const &hit, Chris@16: result_type const& found_directive, Chris@16: token_sequence_type const& found_eoltokens); Chris@16: void replace_undefined_identifiers(token_sequence_type &expanded); Chris@16: Chris@16: void on_include(string_type const &s, bool is_system, bool include_next); Chris@16: void on_include(typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end, bool include_next); Chris@16: Chris@16: void on_define(parse_node_type const &node); Chris@16: void on_undefine(lexer_type const &it); Chris@16: Chris@16: void on_ifdef(result_type const& found_directive, lexer_type const &it); Chris@16: // typename parse_tree_type::const_iterator const &end); Chris@16: void on_ifndef(result_type const& found_directive, lexer_type const& it); Chris@16: // typename parse_tree_type::const_iterator const &end); Chris@16: void on_else(); Chris@16: void on_endif(); Chris@16: void on_illformed(typename result_type::string_type s); Chris@16: Chris@16: void on_line(typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end); Chris@16: void on_if(result_type const& found_directive, Chris@16: typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end); Chris@16: void on_elif(result_type const& found_directive, Chris@16: typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end); Chris@16: void on_error(typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end); Chris@16: #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0 Chris@16: void on_warning(typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end); Chris@16: #endif Chris@16: bool on_pragma(typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end); Chris@16: Chris@16: bool emit_line_directive(); Chris@16: bool returned_from_include(); Chris@16: Chris@16: bool interpret_pragma(token_sequence_type const &pragma_body, Chris@16: token_sequence_type &result); Chris@16: Chris@16: private: Chris@16: ContextT &ctx; // context, this iterator is associated with Chris@16: boost::shared_ptr iter_ctx; Chris@16: Chris@16: bool seen_newline; // needed for recognizing begin of line Chris@16: bool skipped_newline; // a newline has been skipped since last one Chris@16: bool must_emit_line_directive; // must emit a line directive Chris@16: result_type act_token; // current token Chris@16: typename result_type::position_type &act_pos; // current fileposition (references the macromap) Chris@16: Chris@16: token_sequence_type unput_queue; // tokens to be preprocessed again Chris@16: token_sequence_type pending_queue; // tokens already preprocessed Chris@16: Chris@16: // detect whether to insert additional whitespace in between two adjacent Chris@16: // tokens, which otherwise would form a different token type, if Chris@16: // re-tokenized Chris@16: boost::wave::util::insert_whitespace_detection whitespace; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // eof token Chris@16: template Chris@16: typename pp_iterator_functor::result_type const Chris@16: pp_iterator_functor::eof; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // returned_from_include() Chris@16: // Chris@16: // Tests if it is necessary to pop the include file context (eof inside Chris@16: // a file was reached). If yes, it pops this context. Preprocessing will Chris@16: // continue with the next outer file scope. Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline bool Chris@16: pp_iterator_functor::returned_from_include() Chris@16: { Chris@16: if (iter_ctx->first == iter_ctx->last && ctx.get_iteration_depth() > 0) { Chris@16: // call the include policy trace function Chris@16: #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 Chris@16: ctx.get_hooks().returning_from_include_file(); Chris@16: #else Chris@16: ctx.get_hooks().returning_from_include_file(ctx.derived()); Chris@16: #endif Chris@16: Chris@16: // restore the previous iteration context after finishing the preprocessing Chris@16: // of the included file Chris@16: BOOST_WAVE_STRINGTYPE oldfile = iter_ctx->real_filename; Chris@16: position_type old_pos (act_pos); Chris@16: Chris@16: // if this file has include guards handle it as if it had a #pragma once Chris@16: #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 Chris@16: if (need_include_guard_detection(ctx.get_language())) { Chris@16: std::string guard_name; Chris@16: if (iter_ctx->first.has_include_guards(guard_name)) Chris@16: ctx.add_pragma_once_header(ctx.get_current_filename(), guard_name); Chris@16: } Chris@16: #endif Chris@16: iter_ctx = ctx.pop_iteration_context(); Chris@16: Chris@16: must_emit_line_directive = true; Chris@16: iter_ctx->emitted_lines = (unsigned int)(-1); // force #line directive Chris@16: seen_newline = true; Chris@16: Chris@16: // restore current file position Chris@16: act_pos.set_file(iter_ctx->filename); Chris@16: act_pos.set_line(iter_ctx->line); Chris@16: act_pos.set_column(0); Chris@16: Chris@16: // restore the actual current file and directory Chris@16: #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 Chris@16: namespace fs = boost::filesystem; Chris@16: fs::path rfp(wave::util::create_path(iter_ctx->real_filename.c_str())); Chris@16: std::string real_filename(rfp.string()); Chris@16: ctx.set_current_filename(real_filename.c_str()); Chris@16: #endif Chris@16: ctx.set_current_directory(iter_ctx->real_filename.c_str()); Chris@16: ctx.set_current_relative_filename(iter_ctx->real_relative_filename.c_str()); Chris@16: Chris@16: // ensure the integrity of the #if/#endif stack Chris@16: // report unbalanced #if/#endif now to make it possible to recover properly Chris@16: if (iter_ctx->if_block_depth != ctx.get_if_block_depth()) { Chris@16: using boost::wave::util::impl::escape_lit; Chris@16: BOOST_WAVE_STRINGTYPE msg(escape_lit(oldfile)); Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, unbalanced_if_endif, Chris@16: msg.c_str(), old_pos); Chris@16: } Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // operator()(): get the next preprocessed token Chris@16: // Chris@16: // throws a preprocess_exception, if appropriate Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace impl { Chris@16: Chris@16: // It may be necessary to emit a #line directive either Chris@16: // - when comments need to be preserved: if the current token is not a Chris@16: // whitespace, except comments Chris@16: // - when comments are to be skipped: if the current token is not a Chris@16: // whitespace token. Chris@16: template Chris@16: bool consider_emitting_line_directive(ContextT const& ctx, token_id id) Chris@16: { Chris@16: if (need_preserve_comments(ctx.get_language())) Chris@16: { Chris@16: if (!IS_CATEGORY(id, EOLTokenType) && !IS_CATEGORY(id, EOFTokenType)) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: } Chris@16: if (!IS_CATEGORY(id, WhiteSpaceTokenType) && Chris@16: !IS_CATEGORY(id, EOLTokenType) && !IS_CATEGORY(id, EOFTokenType)) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename pp_iterator_functor::result_type const & Chris@16: pp_iterator_functor::operator()() Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: // make sure the cwd has been initialized Chris@16: ctx.init_context(); Chris@16: Chris@16: // loop over skip able whitespace until something significant is found Chris@16: bool was_seen_newline = seen_newline; Chris@16: bool was_skipped_newline = skipped_newline; Chris@16: token_id id = T_UNKNOWN; Chris@16: Chris@16: try { // catch lexer exceptions Chris@16: do { Chris@16: if (skipped_newline) { Chris@16: was_skipped_newline = true; Chris@16: skipped_newline = false; Chris@16: } Chris@16: Chris@16: // get_next_token assigns result to act_token member Chris@16: get_next_token(); Chris@16: Chris@16: // if comments shouldn't be preserved replace them with newlines Chris@16: id = token_id(act_token); Chris@16: if (!need_preserve_comments(ctx.get_language()) && Chris@16: (T_CPPCOMMENT == id || context_policies::util::ccomment_has_newline(act_token))) Chris@16: { Chris@16: act_token.set_token_id(id = T_NEWLINE); Chris@16: act_token.set_value("\n"); Chris@16: } Chris@16: Chris@16: if (IS_CATEGORY(id, EOLTokenType)) Chris@16: seen_newline = true; Chris@16: Chris@16: } while (ctx.get_hooks().may_skip_whitespace(ctx.derived(), act_token, skipped_newline)); Chris@16: } Chris@16: catch (boost::wave::cpplexer::lexing_exception const& e) { Chris@16: // dispatch any lexer exceptions to the context hook function Chris@16: ctx.get_hooks().throw_exception(ctx.derived(), e); Chris@16: return act_token; Chris@16: } Chris@16: Chris@16: // restore the accumulated skipped_newline state for next invocation Chris@16: if (was_skipped_newline) Chris@16: skipped_newline = true; Chris@16: Chris@16: // if there were skipped any newlines, we must emit a #line directive Chris@16: if ((must_emit_line_directive || (was_seen_newline && skipped_newline)) && Chris@16: impl::consider_emitting_line_directive(ctx, id)) Chris@16: { Chris@16: // must emit a #line directive Chris@16: if (need_emit_line_directives(ctx.get_language()) && emit_line_directive()) Chris@16: { Chris@16: skipped_newline = false; Chris@16: ctx.get_hooks().may_skip_whitespace(ctx.derived(), act_token, skipped_newline); // feed ws eater FSM Chris@16: id = token_id(act_token); Chris@16: } Chris@16: } Chris@16: Chris@16: // cleanup of certain tokens required Chris@16: seen_newline = false; Chris@16: switch (static_cast(id)) { Chris@16: case T_NONREPLACABLE_IDENTIFIER: Chris@16: act_token.set_token_id(id = T_IDENTIFIER); Chris@16: break; Chris@16: Chris@16: case T_GENERATEDNEWLINE: // was generated by emit_line_directive() Chris@16: act_token.set_token_id(id = T_NEWLINE); Chris@16: ++iter_ctx->emitted_lines; Chris@16: seen_newline = true; Chris@16: break; Chris@16: Chris@16: case T_NEWLINE: Chris@16: case T_CPPCOMMENT: Chris@16: seen_newline = true; Chris@16: ++iter_ctx->emitted_lines; Chris@16: break; Chris@16: Chris@16: #if BOOST_WAVE_SUPPORT_CPP0X != 0 Chris@16: case T_RAWSTRINGLIT: Chris@16: iter_ctx->emitted_lines += Chris@16: context_policies::util::rawstring_count_newlines(act_token); Chris@16: break; Chris@16: #endif Chris@16: Chris@16: case T_CCOMMENT: // will come here only if whitespace is preserved Chris@16: iter_ctx->emitted_lines += Chris@16: context_policies::util::ccomment_count_newlines(act_token); Chris@16: break; Chris@16: Chris@16: case T_PP_NUMBER: // re-tokenize the pp-number Chris@16: { Chris@16: token_sequence_type rescanned; Chris@16: Chris@16: std::string pp_number( Chris@16: util::to_string(act_token.get_value())); Chris@16: Chris@16: lexer_type it = lexer_type(pp_number.begin(), Chris@16: pp_number.end(), act_token.get_position(), Chris@16: ctx.get_language()); Chris@16: lexer_type end = lexer_type(); Chris@16: Chris@16: for (/**/; it != end && T_EOF != token_id(*it); ++it) Chris@16: rescanned.push_back(*it); Chris@16: Chris@16: pending_queue.splice(pending_queue.begin(), rescanned); Chris@16: act_token = pending_queue.front(); Chris@16: id = token_id(act_token); Chris@16: pending_queue.pop_front(); Chris@16: } Chris@16: break; Chris@16: Chris@16: case T_EOF: Chris@16: seen_newline = true; Chris@16: break; Chris@16: Chris@16: default: // make sure whitespace at line begin keeps seen_newline status Chris@16: if (IS_CATEGORY(id, WhiteSpaceTokenType)) Chris@16: seen_newline = was_seen_newline; Chris@16: break; Chris@16: } Chris@16: Chris@16: if (whitespace.must_insert(id, act_token.get_value())) { Chris@16: // must insert some whitespace into the output stream to avoid adjacent Chris@16: // tokens, which would form different (and wrong) tokens Chris@16: whitespace.shift_tokens(T_SPACE); Chris@16: pending_queue.push_front(act_token); // push this token back Chris@16: return act_token = result_type(T_SPACE, Chris@16: typename result_type::string_type(" "), Chris@16: act_token.get_position()); Chris@16: } Chris@16: whitespace.shift_tokens(id); Chris@16: return ctx.get_hooks().generated_token(ctx.derived(), act_token); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline typename pp_iterator_functor::result_type const & Chris@16: pp_iterator_functor::get_next_token() Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: // if there is something in the unput_queue, then return the next token from Chris@16: // there (all tokens in the queue are preprocessed already) Chris@16: if (!pending_queue.empty() || !unput_queue.empty()) Chris@16: return pp_token(); // return next token Chris@16: Chris@16: // test for EOF, if there is a pending input context, pop it back and continue Chris@16: // parsing with it Chris@16: bool returned_from_include_file = returned_from_include(); Chris@16: Chris@16: // try to generate the next token Chris@16: if (iter_ctx->first != iter_ctx->last) { Chris@16: do { Chris@16: // If there are pending tokens in the queue, we'll have to return Chris@16: // these. This may happen from a #pragma directive, which got replaced Chris@16: // by some token sequence. Chris@16: if (!pending_queue.empty()) { Chris@16: util::on_exit::pop_front Chris@16: pop_front_token(pending_queue); Chris@16: Chris@16: return act_token = pending_queue.front(); Chris@16: } Chris@16: Chris@16: // adjust the current position (line and column) Chris@16: bool was_seen_newline = seen_newline || returned_from_include_file; Chris@16: Chris@16: // fetch the current token Chris@16: act_token = *iter_ctx->first; Chris@16: act_pos = act_token.get_position(); Chris@16: Chris@16: // act accordingly on the current token Chris@16: token_id id = token_id(act_token); Chris@16: Chris@16: if (T_EOF == id) { Chris@16: // returned from an include file, continue with the next token Chris@16: whitespace.shift_tokens(T_EOF); Chris@16: ++iter_ctx->first; Chris@16: Chris@16: // now make sure this line has a newline Chris@16: if ((!seen_newline || act_pos.get_column() > 1) && Chris@16: !need_single_line(ctx.get_language())) Chris@16: { Chris@16: // warn, if this file does not end with a newline Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: last_line_not_terminated, "", act_pos); Chris@16: } Chris@16: continue; // if this is the main file, the while loop breaks Chris@16: } Chris@16: else if (T_NEWLINE == id || T_CPPCOMMENT == id) { Chris@16: // a newline is to be returned ASAP, a C++ comment too Chris@16: // (the C++ comment token includes the trailing newline) Chris@16: seen_newline = true; Chris@16: ++iter_ctx->first; Chris@16: Chris@16: if (!ctx.get_if_block_status()) { Chris@16: // skip this token because of the disabled #if block Chris@16: whitespace.shift_tokens(id); // whitespace controller Chris@16: util::impl::call_skipped_token_hook(ctx, act_token); Chris@16: continue; Chris@16: } Chris@16: return act_token; Chris@16: } Chris@16: seen_newline = false; Chris@16: Chris@16: if (was_seen_newline && pp_directive()) { Chris@16: // a pp directive was found Chris@16: // pending_queue.push_back(result_type(T_NEWLINE, "\n", act_pos)); Chris@16: // seen_newline = true; Chris@16: // must_emit_line_directive = true; Chris@16: Chris@16: // loop to the next token to analyze Chris@16: // simply fall through, since the iterator was already adjusted Chris@16: // correctly Chris@16: } Chris@16: else if (ctx.get_if_block_status()) { Chris@16: // preprocess this token, eat up more, if appropriate, return Chris@16: // the next preprocessed token Chris@16: return pp_token(); Chris@16: } Chris@16: else { Chris@16: // compilation condition is false: if the current token is a Chris@16: // newline, account for it, otherwise discard the actual token and Chris@16: // try the next one Chris@16: if (T_NEWLINE == token_id(act_token)) { Chris@16: seen_newline = true; Chris@16: must_emit_line_directive = true; Chris@16: } Chris@16: Chris@16: // next token Chris@16: util::impl::call_skipped_token_hook(ctx, act_token); Chris@16: ++iter_ctx->first; Chris@16: } Chris@16: Chris@16: } while ((iter_ctx->first != iter_ctx->last) || Chris@16: (returned_from_include_file = returned_from_include())); Chris@16: Chris@16: // overall eof reached Chris@16: if (ctx.get_if_block_depth() > 0 && !need_single_line(ctx.get_language())) Chris@16: { Chris@16: // missing endif directive(s) Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: missing_matching_endif, "", act_pos); Chris@16: } Chris@16: } Chris@16: else { Chris@16: act_token = eof; // this is the last token Chris@16: } Chris@16: Chris@16: // whitespace.shift_tokens(T_EOF); // whitespace controller Chris@16: return act_token; // return eof token Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // emit_line_directive(): emits a line directive from the act_token data Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline bool Chris@16: pp_iterator_functor::emit_line_directive() Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: typename ContextT::position_type pos = act_token.get_position(); Chris@16: Chris@16: // if (must_emit_line_directive && Chris@16: // iter_ctx->emitted_lines+1 == act_pos.get_line() && Chris@16: // iter_ctx->filename == act_pos.get_file()) Chris@16: // { Chris@16: // must_emit_line_directive = false; Chris@16: // return false; Chris@16: // } Chris@16: Chris@16: if (must_emit_line_directive || Chris@16: iter_ctx->emitted_lines+1 != act_pos.get_line()) Chris@16: { Chris@16: // unput the current token Chris@16: pending_queue.push_front(act_token); Chris@16: pos.set_line(act_pos.get_line()); Chris@16: Chris@16: if (iter_ctx->emitted_lines+2 == act_pos.get_line() && act_pos.get_line() != 1) { Chris@16: // prefer to output a single newline instead of the #line directive Chris@16: // whitespace.shift_tokens(T_NEWLINE); Chris@16: act_token = result_type(T_NEWLINE, "\n", pos); Chris@16: } Chris@16: else { Chris@16: // account for the newline emitted here Chris@16: act_pos.set_line(act_pos.get_line()-1); Chris@16: iter_ctx->emitted_lines = act_pos.get_line()-1; Chris@16: Chris@16: token_sequence_type pending; Chris@16: Chris@16: if (!ctx.get_hooks().emit_line_directive(ctx, pending, act_token)) Chris@16: { Chris@16: unsigned int column = 6; Chris@16: Chris@16: // the hook did not generate anything, emit default #line Chris@16: pos.set_column(1); Chris@16: pending.push_back(result_type(T_PP_LINE, "#line", pos)); Chris@16: Chris@16: pos.set_column(column); // account for '#line' Chris@16: pending.push_back(result_type(T_SPACE, " ", pos)); Chris@16: Chris@16: // 21 is the max required size for a 64 bit integer represented as a Chris@16: // string Chris@16: char buffer[22]; Chris@16: Chris@16: using namespace std; // for some systems sprintf is in namespace std Chris@16: sprintf (buffer, "%ld", pos.get_line()); Chris@16: Chris@16: pos.set_column(++column); // account for ' ' Chris@16: pending.push_back(result_type(T_INTLIT, buffer, pos)); Chris@16: pos.set_column(column += (unsigned int)strlen(buffer)); // account for Chris@16: pending.push_back(result_type(T_SPACE, " ", pos)); Chris@16: pos.set_column(++column); // account for ' ' Chris@16: Chris@16: std::string file("\""); Chris@16: boost::filesystem::path filename( Chris@16: wave::util::create_path(act_pos.get_file().c_str())); Chris@16: Chris@16: using wave::util::impl::escape_lit; Chris@16: file += escape_lit(wave::util::native_file_string(filename)) + "\""; Chris@16: Chris@16: pending.push_back(result_type(T_STRINGLIT, file.c_str(), pos)); Chris@16: pos.set_column(column += (unsigned int)file.size()); // account for filename Chris@16: pending.push_back(result_type(T_GENERATEDNEWLINE, "\n", pos)); Chris@16: } Chris@16: Chris@16: // if there is some replacement text, insert it into the pending queue Chris@16: if (!pending.empty()) { Chris@16: pending_queue.splice(pending_queue.begin(), pending); Chris@16: act_token = pending_queue.front(); Chris@16: pending_queue.pop_front(); Chris@16: } Chris@16: } Chris@16: Chris@16: must_emit_line_directive = false; // we are now in sync Chris@16: return true; Chris@16: } Chris@16: Chris@16: must_emit_line_directive = false; // we are now in sync Chris@16: return false; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // pptoken(): return the next preprocessed token Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline typename pp_iterator_functor::result_type const & Chris@16: pp_iterator_functor::pp_token() Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: token_id id = token_id(*iter_ctx->first); Chris@16: Chris@16: // eat all T_PLACEHOLDER tokens, eventually slipped through out of the Chris@16: // macro engine Chris@16: do { Chris@16: if (!pending_queue.empty()) { Chris@16: // if there are pending tokens in the queue, return the first one Chris@16: act_token = pending_queue.front(); Chris@16: pending_queue.pop_front(); Chris@16: act_pos = act_token.get_position(); Chris@16: } Chris@16: else if (!unput_queue.empty() Chris@16: || 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: // call the lexer, preprocess the required number of tokens, put them Chris@16: // into the unput queue Chris@16: act_token = ctx.expand_tokensequence(iter_ctx->first, Chris@16: iter_ctx->last, pending_queue, unput_queue, skipped_newline); Chris@16: } Chris@16: else { Chris@16: // simply return the next token Chris@16: act_token = *iter_ctx->first; Chris@16: ++iter_ctx->first; Chris@16: } Chris@16: id = token_id(act_token); Chris@16: Chris@16: } while (T_PLACEHOLDER == id); Chris@16: return act_token; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // pp_directive(): recognize a preprocessor directive Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace impl { Chris@16: Chris@16: // call 'found_directive' preprocessing hook Chris@16: template Chris@16: bool call_found_directive_hook(ContextT& ctx, Chris@16: typename ContextT::token_type const& found_directive) Chris@16: { Chris@16: #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 Chris@16: ctx.get_hooks().found_directive(found_directive); Chris@16: #else Chris@16: if (ctx.get_hooks().found_directive(ctx.derived(), found_directive)) Chris@16: return true; // skip this directive and return newline only Chris@16: #endif Chris@16: return false; Chris@16: } Chris@16: Chris@16: // // call 'skipped_token' preprocessing hook Chris@16: // template Chris@16: // void call_skipped_token_hook(ContextT& ctx, Chris@16: // typename ContextT::token_type const& skipped) Chris@16: // { Chris@16: // #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 Chris@16: // ctx.get_hooks().skipped_token(skipped); Chris@16: // #else Chris@16: // ctx.get_hooks().skipped_token(ctx.derived(), skipped); Chris@16: // #endif Chris@16: // } Chris@16: Chris@16: template Chris@16: bool next_token_is_pp_directive(ContextT &ctx, IteratorT &it, IteratorT const &end) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: token_id id = T_UNKNOWN; Chris@16: for (/**/; it != end; ++it) { Chris@16: id = token_id(*it); Chris@16: if (!IS_CATEGORY(id, WhiteSpaceTokenType)) Chris@16: break; // skip leading whitespace Chris@16: if (IS_CATEGORY(id, EOLTokenType) || IS_CATEGORY(id, EOFTokenType)) Chris@16: break; // do not enter a new line Chris@16: if (T_CPPCOMMENT == id || Chris@16: context_policies::util::ccomment_has_newline(*it)) Chris@16: { Chris@16: break; Chris@16: } Chris@16: Chris@16: // this token gets skipped Chris@16: util::impl::call_skipped_token_hook(ctx, *it); Chris@16: } Chris@16: BOOST_ASSERT(it == end || id != T_UNKNOWN); Chris@16: return it != end && IS_CATEGORY(id, PPTokenType); Chris@16: } Chris@16: Chris@16: // verify that there isn't anything significant left on the line Chris@16: template Chris@16: bool pp_is_last_on_line(ContextT &ctx, IteratorT &it, IteratorT const &end, Chris@16: bool call_hook = true) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: // this token gets skipped Chris@16: if (call_hook) Chris@16: util::impl::call_skipped_token_hook(ctx, *it); Chris@16: Chris@16: for (++it; it != end; ++it) { Chris@16: token_id id = token_id(*it); Chris@16: Chris@16: if (T_CPPCOMMENT == id || T_NEWLINE == id || Chris@16: context_policies::util::ccomment_has_newline(*it)) Chris@16: { Chris@16: if (call_hook) Chris@16: util::impl::call_skipped_token_hook(ctx, *it); Chris@16: ++it; // skip eol/C/C++ comment Chris@16: return true; // no more significant tokens on this line Chris@16: } Chris@16: Chris@16: if (!IS_CATEGORY(id, WhiteSpaceTokenType)) Chris@16: break; Chris@16: Chris@16: // this token gets skipped Chris@16: if (call_hook) Chris@16: util::impl::call_skipped_token_hook(ctx, *it); Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: bool skip_to_eol(ContextT &ctx, IteratorT &it, IteratorT const &end, Chris@16: bool call_hook = true) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: for (/**/; it != end; ++it) { Chris@16: token_id id = token_id(*it); Chris@16: Chris@16: if (T_CPPCOMMENT == id || T_NEWLINE == id || Chris@16: context_policies::util::ccomment_has_newline(*it)) Chris@16: { Chris@16: // always call hook for eol Chris@16: util::impl::call_skipped_token_hook(ctx, *it); Chris@16: ++it; // skip eol/C/C++ comment Chris@16: return true; // found eol Chris@16: } Chris@16: Chris@16: if (call_hook) Chris@16: util::impl::call_skipped_token_hook(ctx, *it); Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void Chris@16: remove_leading_whitespace(ContextT &ctx, ContainerT& c, bool call_hook = true) Chris@16: { Chris@16: typename ContainerT::iterator it = c.begin(); Chris@16: while (IS_CATEGORY(*it, WhiteSpaceTokenType)) { Chris@16: typename ContainerT::iterator save = it++; Chris@16: if (call_hook) Chris@16: util::impl::call_skipped_token_hook(ctx, *save); Chris@16: c.erase(save); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: template Chris@16: inline bool Chris@16: pp_iterator_functor::extract_identifier(IteratorT &it) Chris@16: { Chris@16: token_id id = util::impl::skip_whitespace(it, iter_ctx->last); 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: IteratorT save = it; Chris@16: if (impl::pp_is_last_on_line(ctx, save, iter_ctx->last, false)) Chris@16: return true; Chris@16: } Chris@16: Chris@16: // report the ill formed directive Chris@16: impl::skip_to_eol(ctx, it, iter_ctx->last); Chris@16: Chris@16: string_type str(util::impl::as_string(iter_ctx->first, it)); Chris@16: Chris@16: seen_newline = true; Chris@16: iter_ctx->first = it; Chris@16: on_illformed(str); Chris@16: return false; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: template Chris@16: inline bool Chris@16: pp_iterator_functor::ensure_is_last_on_line(IteratorT& it, bool call_hook) Chris@16: { Chris@16: if (!impl::pp_is_last_on_line(ctx, it, iter_ctx->last, call_hook)) Chris@16: { Chris@16: // enable error recovery (start over with the next line) Chris@16: impl::skip_to_eol(ctx, it, iter_ctx->last); Chris@16: Chris@16: string_type str(util::impl::as_string( Chris@16: iter_ctx->first, it)); Chris@16: Chris@16: seen_newline = true; Chris@16: iter_ctx->first = it; Chris@16: Chris@16: // report an invalid directive Chris@16: on_illformed(str); Chris@16: return false; Chris@16: } Chris@16: Chris@16: if (it == iter_ctx->last && !need_single_line(ctx.get_language())) Chris@16: { Chris@16: // The line doesn't end with an eol but eof token. Chris@16: seen_newline = true; // allow to resume after warning Chris@16: iter_ctx->first = it; Chris@16: Chris@16: // Trigger a warning that the last line was not terminated with a Chris@16: // newline. Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: last_line_not_terminated, "", act_pos); Chris@16: Chris@16: return false; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: template Chris@16: template Chris@16: inline bool Chris@16: pp_iterator_functor::skip_to_eol_with_check(IteratorT &it, bool call_hook) Chris@16: { Chris@16: typename ContextT::string_type value ((*it).get_value()); Chris@16: if (!impl::skip_to_eol(ctx, it, iter_ctx->last, call_hook) && Chris@16: !need_single_line(ctx.get_language())) Chris@16: { Chris@16: // The line doesn't end with an eol but eof token. Chris@16: seen_newline = true; // allow to resume after warning Chris@16: iter_ctx->first = it; Chris@16: Chris@16: // Trigger a warning, that the last line was not terminated with a Chris@16: // newline. Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: last_line_not_terminated, "", act_pos); Chris@16: return false; Chris@16: } Chris@16: Chris@16: // normal line ending reached, adjust iterator and flag Chris@16: seen_newline = true; Chris@16: iter_ctx->first = it; Chris@16: return true; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // handle_pp_directive: handle certain pp_directives Chris@16: template Chris@16: template Chris@16: inline bool Chris@16: pp_iterator_functor::handle_pp_directive(IteratorT &it) Chris@16: { Chris@16: token_id id = token_id(*it); Chris@16: bool can_exit = true; Chris@16: bool call_hook_in_skip = true; Chris@16: if (!ctx.get_if_block_status()) { Chris@16: if (IS_EXTCATEGORY(*it, PPConditionalTokenType)) { Chris@16: // simulate the if block hierarchy Chris@16: switch (static_cast(id)) { Chris@16: case T_PP_IFDEF: // #ifdef Chris@16: case T_PP_IFNDEF: // #ifndef Chris@16: case T_PP_IF: // #if Chris@16: ctx.enter_if_block(false); Chris@16: break; Chris@16: Chris@16: case T_PP_ELIF: // #elif Chris@16: if (!ctx.get_enclosing_if_block_status()) { Chris@16: if (!ctx.enter_elif_block(false)) { Chris@16: // #else without matching #if Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: missing_matching_if, "#elif", act_pos); Chris@16: return true; // do not analyze this directive any further Chris@16: } Chris@16: } Chris@16: else { Chris@16: can_exit = false; // #elif is not always safe to skip Chris@16: } Chris@16: break; Chris@16: Chris@16: case T_PP_ELSE: // #else Chris@16: case T_PP_ENDIF: // #endif Chris@16: { Chris@16: // handle this directive Chris@16: if (T_PP_ELSE == token_id(*it)) Chris@16: on_else(); Chris@16: else Chris@16: on_endif(); Chris@16: Chris@16: // make sure, there are no (non-whitespace) tokens left on Chris@16: // this line Chris@16: ensure_is_last_on_line(it); Chris@16: Chris@16: // we skipped to the end of this line already Chris@16: seen_newline = true; Chris@16: iter_ctx->first = it; Chris@16: } Chris@16: return true; Chris@16: Chris@16: default: // #something else Chris@16: on_illformed((*it).get_value()); Chris@16: break; Chris@16: } Chris@16: } Chris@16: else { Chris@16: util::impl::call_skipped_token_hook(ctx, *it); Chris@16: ++it; Chris@16: } Chris@16: } Chris@16: else { Chris@16: // try to handle the simple pp directives without parsing Chris@16: result_type directive = *it; Chris@16: bool include_next = false; Chris@16: switch (static_cast(id)) { Chris@16: case T_PP_QHEADER: // #include "..." Chris@16: #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 Chris@16: case T_PP_QHEADER_NEXT: Chris@16: #endif Chris@16: include_next = (T_PP_QHEADER_NEXT == id) ? true : false; Chris@16: if (!impl::call_found_directive_hook(ctx, *it)) Chris@16: { Chris@16: string_type dir((*it).get_value()); Chris@16: Chris@16: // make sure, there are no (non-whitespace) tokens left on Chris@16: // this line Chris@16: if (ensure_is_last_on_line(it)) Chris@16: { Chris@16: seen_newline = true; Chris@16: iter_ctx->first = it; Chris@16: on_include (dir, false, include_next); Chris@16: } Chris@16: return true; Chris@16: } Chris@16: break; Chris@16: Chris@16: case T_PP_HHEADER: // #include <...> Chris@16: #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 Chris@16: case T_PP_HHEADER_NEXT: Chris@16: #endif Chris@16: include_next = (T_PP_HHEADER_NEXT == id) ? true : false; Chris@16: if (!impl::call_found_directive_hook(ctx, *it)) Chris@16: { Chris@16: string_type dir((*it).get_value()); Chris@16: Chris@16: // make sure, there are no (non-whitespace) tokens left on Chris@16: // this line Chris@16: if (ensure_is_last_on_line(it)) Chris@16: { Chris@16: seen_newline = true; Chris@16: iter_ctx->first = it; Chris@16: on_include (dir, true, include_next); Chris@16: } Chris@16: return true; Chris@16: } Chris@16: break; Chris@16: Chris@16: case T_PP_ELSE: // #else Chris@16: case T_PP_ENDIF: // #endif Chris@16: if (!impl::call_found_directive_hook(ctx, *it)) Chris@16: { Chris@16: // handle this directive Chris@16: if (T_PP_ELSE == token_id(*it)) Chris@16: on_else(); Chris@16: else Chris@16: on_endif(); Chris@16: Chris@16: // make sure, there are no (non-whitespace) tokens left on Chris@16: // this line Chris@16: ensure_is_last_on_line(it); Chris@16: Chris@16: // we skipped to the end of this line already Chris@16: seen_newline = true; Chris@16: iter_ctx->first = it; Chris@16: return true; Chris@16: } Chris@16: break; Chris@16: Chris@16: // extract everything on this line as arguments Chris@16: // case T_PP_IF: // #if Chris@16: // case T_PP_ELIF: // #elif Chris@16: // case T_PP_ERROR: // #error Chris@16: // case T_PP_WARNING: // #warning Chris@16: // case T_PP_PRAGMA: // #pragma Chris@16: // case T_PP_LINE: // #line Chris@16: // break; Chris@16: Chris@16: // extract first non-whitespace token as argument Chris@16: case T_PP_UNDEF: // #undef Chris@16: if (!impl::call_found_directive_hook(ctx, *it) && Chris@16: extract_identifier(it)) Chris@16: { Chris@16: on_undefine(it); Chris@16: } Chris@16: call_hook_in_skip = false; Chris@16: break; Chris@16: Chris@16: case T_PP_IFDEF: // #ifdef Chris@16: if (!impl::call_found_directive_hook(ctx, *it) && Chris@16: extract_identifier(it)) Chris@16: { Chris@16: on_ifdef(directive, it); Chris@16: } Chris@16: call_hook_in_skip = false; Chris@16: break; Chris@16: Chris@16: case T_PP_IFNDEF: // #ifndef Chris@16: if (!impl::call_found_directive_hook(ctx, *it) && Chris@16: extract_identifier(it)) Chris@16: { Chris@16: on_ifndef(directive, it); Chris@16: } Chris@16: call_hook_in_skip = false; Chris@16: break; Chris@16: Chris@16: #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 Chris@16: // case T_MSEXT_PP_REGION: // #region ... Chris@16: // break; Chris@16: // Chris@16: // case T_MSEXT_PP_ENDREGION: // #endregion Chris@16: // break; Chris@16: #endif Chris@16: Chris@16: default: Chris@16: can_exit = false; Chris@16: break; Chris@16: } Chris@16: } Chris@16: Chris@16: // start over with the next line, if only possible Chris@16: if (can_exit) { Chris@16: skip_to_eol_with_check(it, call_hook_in_skip); Chris@16: return true; // may be safely ignored Chris@16: } Chris@16: return false; // do not ignore this pp directive Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // pp_directive(): recognize a preprocessor directive Chris@16: template Chris@16: inline bool Chris@16: pp_iterator_functor::pp_directive() Chris@16: { Chris@16: using namespace cpplexer; Chris@16: Chris@16: // test, if the next non-whitespace token is a pp directive Chris@16: lexer_type it = iter_ctx->first; Chris@16: Chris@16: if (!impl::next_token_is_pp_directive(ctx, it, iter_ctx->last)) { Chris@16: // skip null pp directive (no need to do it via the parser) Chris@16: if (it != iter_ctx->last && T_POUND == BASE_TOKEN(token_id(*it))) { Chris@16: if (impl::pp_is_last_on_line(ctx, it, iter_ctx->last)) { Chris@16: // start over with the next line Chris@16: seen_newline = true; Chris@16: iter_ctx->first = it; Chris@16: return true; Chris@16: } Chris@16: else if (ctx.get_if_block_status()) { Chris@16: // report invalid pp directive Chris@16: impl::skip_to_eol(ctx, it, iter_ctx->last); Chris@16: seen_newline = true; Chris@16: Chris@16: string_type str(boost::wave::util::impl::as_string( Chris@16: iter_ctx->first, it)); Chris@16: Chris@16: token_sequence_type faulty_line; Chris@16: Chris@16: for (/**/; iter_ctx->first != it; ++iter_ctx->first) Chris@16: faulty_line.push_back(*iter_ctx->first); Chris@16: Chris@16: token_sequence_type pending; Chris@16: if (ctx.get_hooks().found_unknown_directive(ctx, faulty_line, pending)) Chris@16: { Chris@16: // if there is some replacement text, insert it into the pending queue Chris@16: if (!pending.empty()) Chris@16: pending_queue.splice(pending_queue.begin(), pending); Chris@16: return true; Chris@16: } Chris@16: Chris@16: // default behavior is to throw an exception Chris@16: on_illformed(str); Chris@16: } Chris@16: } Chris@16: Chris@16: // this line does not contain a pp directive, so simply return Chris@16: return false; Chris@16: } Chris@16: Chris@16: // found eof Chris@16: if (it == iter_ctx->last) Chris@16: return false; Chris@16: Chris@16: // ignore/handle all pp directives not related to conditional compilation while Chris@16: // if block status is false Chris@16: if (handle_pp_directive(it)) { Chris@16: // we may skip pp directives only if the current if block status is Chris@16: // false or if it was a #include directive we could handle directly Chris@16: return true; // the pp directive has been handled/skipped Chris@16: } Chris@16: Chris@16: // found a pp directive, so try to identify it, start with the pp_token Chris@16: bool found_eof = false; Chris@16: result_type found_directive; Chris@16: token_sequence_type found_eoltokens; Chris@16: Chris@16: tree_parse_info_type hit = cpp_grammar_type::parse_cpp_grammar( Chris@16: it, iter_ctx->last, act_pos, found_eof, found_directive, found_eoltokens); Chris@16: Chris@16: if (hit.match) { Chris@16: // position the iterator past the matched sequence to allow Chris@16: // resynchronization, if an error occurs Chris@16: iter_ctx->first = hit.stop; Chris@16: seen_newline = true; Chris@16: must_emit_line_directive = true; Chris@16: Chris@16: // found a valid pp directive, dispatch to the correct function to handle Chris@16: // the found pp directive Chris@16: bool result = dispatch_directive (hit, found_directive, found_eoltokens); Chris@16: Chris@16: if (found_eof && !need_single_line(ctx.get_language())) { Chris@16: // The line was terminated with an end of file token. Chris@16: // So trigger a warning, that the last line was not terminated with a Chris@16: // newline. Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: last_line_not_terminated, "", act_pos); Chris@16: } Chris@16: return result; Chris@16: } Chris@16: else if (token_id(found_directive) != T_EOF) { Chris@16: // recognized invalid directive Chris@16: impl::skip_to_eol(ctx, it, iter_ctx->last); Chris@16: seen_newline = true; Chris@16: Chris@16: string_type str(boost::wave::util::impl::as_string( Chris@16: iter_ctx->first, it)); Chris@16: iter_ctx->first = it; Chris@16: Chris@16: // report the ill formed directive Chris@16: on_illformed(str); Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // dispatch_directive(): dispatch a recognized preprocessor directive Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline bool Chris@16: pp_iterator_functor::dispatch_directive( Chris@16: tree_parse_info_type const &hit, result_type const& found_directive, Chris@16: token_sequence_type const& found_eoltokens) Chris@16: { Chris@16: using namespace cpplexer; Chris@16: Chris@16: typedef typename parse_tree_type::const_iterator const_child_iterator_t; Chris@16: Chris@16: // this iterator points to the root node of the parse tree Chris@16: const_child_iterator_t begin = hit.trees.begin(); Chris@16: Chris@16: // decide, which preprocessor directive was found Chris@16: parse_tree_type const &root = (*begin).children; Chris@16: parse_node_value_type const &nodeval = get_first_leaf(*root.begin()).value; Chris@16: //long node_id = nodeval.id().to_long(); Chris@16: Chris@16: const_child_iterator_t begin_child_it = (*root.begin()).children.begin(); Chris@16: const_child_iterator_t end_child_it = (*root.begin()).children.end(); Chris@16: Chris@16: token_id id = token_id(found_directive); Chris@16: Chris@16: // call preprocessing hook Chris@16: if (impl::call_found_directive_hook(ctx, found_directive)) Chris@16: return true; // skip this directive and return newline only Chris@16: Chris@16: switch (static_cast(id)) { Chris@16: // case T_PP_QHEADER: // #include "..." Chris@16: // #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 Chris@16: // case T_PP_QHEADER_NEXT: // #include_next "..." Chris@16: // #endif Chris@16: // on_include ((*nodeval.begin()).get_value(), false, Chris@16: // T_PP_QHEADER_NEXT == id); Chris@16: // break; Chris@16: Chris@16: // case T_PP_HHEADER: // #include <...> Chris@16: // #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 Chris@16: // case T_PP_HHEADER_NEXT: // #include_next <...> Chris@16: // #endif Chris@16: // on_include ((*nodeval.begin()).get_value(), true, Chris@16: // T_PP_HHEADER_NEXT == id); Chris@16: // break; Chris@16: Chris@16: case T_PP_INCLUDE: // #include ... Chris@16: #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 Chris@16: case T_PP_INCLUDE_NEXT: // #include_next ... Chris@16: #endif Chris@16: on_include (begin_child_it, end_child_it, T_PP_INCLUDE_NEXT == id); Chris@16: break; Chris@16: Chris@16: case T_PP_DEFINE: // #define Chris@16: on_define (*begin); Chris@16: break; Chris@16: Chris@16: // case T_PP_UNDEF: // #undef Chris@16: // on_undefine(*nodeval.begin()); Chris@16: // break; Chris@16: // Chris@16: // case T_PP_IFDEF: // #ifdef Chris@16: // on_ifdef(found_directive, begin_child_it, end_child_it); Chris@16: // break; Chris@16: // Chris@16: // case T_PP_IFNDEF: // #ifndef Chris@16: // on_ifndef(found_directive, begin_child_it, end_child_it); Chris@16: // break; Chris@16: Chris@16: case T_PP_IF: // #if Chris@16: on_if(found_directive, begin_child_it, end_child_it); Chris@16: break; Chris@16: Chris@16: case T_PP_ELIF: // #elif Chris@16: on_elif(found_directive, begin_child_it, end_child_it); Chris@16: break; Chris@16: Chris@16: // case T_PP_ELSE: // #else Chris@16: // on_else(); Chris@16: // break; Chris@16: Chris@16: // case T_PP_ENDIF: // #endif Chris@16: // on_endif(); Chris@16: // break; Chris@16: Chris@16: case T_PP_LINE: // #line Chris@16: on_line(begin_child_it, end_child_it); Chris@16: break; Chris@16: Chris@16: case T_PP_ERROR: // #error Chris@16: on_error(begin_child_it, end_child_it); Chris@16: break; Chris@16: Chris@16: #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0 Chris@16: case T_PP_WARNING: // #warning Chris@16: on_warning(begin_child_it, end_child_it); Chris@16: break; Chris@16: #endif Chris@16: Chris@16: case T_PP_PRAGMA: // #pragma Chris@16: return on_pragma(begin_child_it, end_child_it); Chris@16: Chris@16: #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 Chris@16: case T_MSEXT_PP_REGION: Chris@16: case T_MSEXT_PP_ENDREGION: Chris@16: break; // ignore these Chris@16: #endif Chris@16: Chris@16: default: // #something else Chris@16: on_illformed((*nodeval.begin()).get_value()); Chris@16: Chris@16: // if we end up here, we have been instructed to ignore the error, so Chris@16: // we simply copy the whole construct to the output Chris@16: { Chris@16: token_sequence_type expanded; Chris@16: get_token_value get_value; Chris@16: Chris@16: std::copy(make_ref_transform_iterator(begin_child_it, get_value), Chris@16: make_ref_transform_iterator(end_child_it, get_value), Chris@16: std::inserter(expanded, expanded.end())); Chris@16: pending_queue.splice(pending_queue.begin(), expanded); Chris@16: } Chris@16: break; Chris@16: } Chris@16: Chris@16: // properly skip trailing newline for all directives Chris@16: typename token_sequence_type::const_iterator eol = found_eoltokens.begin(); Chris@16: impl::skip_to_eol(ctx, eol, found_eoltokens.end()); Chris@16: return true; // return newline only Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_include: handle #include <...> or #include "..." directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_include (string_type const &s, Chris@16: bool is_system, bool include_next) Chris@16: { Chris@16: BOOST_ASSERT(ctx.get_if_block_status()); Chris@16: Chris@16: // strip quotes first, extract filename Chris@16: typename string_type::size_type pos_end = s.find_last_of(is_system ? '>' : '\"'); Chris@16: Chris@16: if (string_type::npos == pos_end) { Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement, Chris@16: s.c_str(), act_pos); Chris@16: return; Chris@16: } Chris@16: Chris@16: typename string_type::size_type pos_begin = Chris@16: s.find_last_of(is_system ? '<' : '\"', pos_end-1); Chris@16: Chris@16: if (string_type::npos == pos_begin) { Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement, Chris@16: s.c_str(), act_pos); Chris@16: return; Chris@16: } Chris@16: Chris@16: std::string file_token(s.substr(pos_begin, pos_end-pos_begin+1).c_str()); Chris@16: std::string file_path(s.substr(pos_begin+1, pos_end-pos_begin-1).c_str()); Chris@16: Chris@16: // finally include the file Chris@16: on_include_helper(file_token.c_str(), file_path.c_str(), is_system, Chris@16: include_next); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool Chris@16: pp_iterator_functor::on_include_helper (char const *f, char const *s, Chris@16: bool is_system, bool include_next) Chris@16: { Chris@16: namespace fs = boost::filesystem; Chris@16: Chris@16: // try to locate the given file, searching through the include path lists Chris@16: std::string file_path(s); Chris@16: std::string dir_path; Chris@16: #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 Chris@16: char const *current_name = include_next ? iter_ctx->real_filename.c_str() : 0; Chris@16: #else Chris@16: char const *current_name = 0; // never try to match current file name Chris@16: #endif Chris@16: Chris@16: // call the 'found_include_directive' hook function Chris@16: #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 Chris@16: ctx.get_hooks().found_include_directive(f, include_next); Chris@16: #else Chris@16: if (ctx.get_hooks().found_include_directive(ctx.derived(), f, include_next)) Chris@16: return true; // client returned false: skip file to include Chris@16: #endif Chris@16: Chris@16: file_path = util::impl::unescape_lit(file_path); Chris@16: std::string native_path_str; Chris@16: Chris@16: if (!ctx.get_hooks().locate_include_file(ctx, file_path, is_system, Chris@16: current_name, dir_path, native_path_str)) Chris@16: { Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_file, Chris@16: file_path.c_str(), act_pos); Chris@16: return false; Chris@16: } Chris@16: Chris@16: // test, if this file is known through a #pragma once directive Chris@16: #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 Chris@16: if (!ctx.has_pragma_once(native_path_str)) Chris@16: #endif Chris@16: { Chris@16: // the new include file determines the actual current directory Chris@16: ctx.set_current_directory(native_path_str.c_str()); Chris@16: Chris@16: // preprocess the opened file Chris@16: boost::shared_ptr new_iter_ctx ( Chris@16: new iteration_context_type(ctx, native_path_str.c_str(), act_pos, Chris@16: boost::wave::enable_prefer_pp_numbers(ctx.get_language()), Chris@16: is_system ? base_iteration_context_type::system_header : Chris@16: base_iteration_context_type::user_header)); Chris@16: Chris@16: // call the include policy trace function Chris@16: #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 Chris@16: ctx.get_hooks().opened_include_file(dir_path, file_path, Chris@16: ctx.get_iteration_depth(), is_system); Chris@16: #else Chris@16: ctx.get_hooks().opened_include_file(ctx.derived(), dir_path, file_path, Chris@16: is_system); Chris@16: #endif Chris@16: Chris@16: // store current file position Chris@16: iter_ctx->real_relative_filename = ctx.get_current_relative_filename().c_str(); Chris@16: iter_ctx->filename = act_pos.get_file(); Chris@16: iter_ctx->line = act_pos.get_line(); Chris@16: iter_ctx->if_block_depth = ctx.get_if_block_depth(); Chris@16: iter_ctx->emitted_lines = (unsigned int)(-1); // force #line directive Chris@16: Chris@16: // push the old iteration context onto the stack and continue with the new Chris@16: ctx.push_iteration_context(act_pos, iter_ctx); Chris@16: iter_ctx = new_iter_ctx; Chris@16: seen_newline = true; // fake a newline to trigger pp_directive Chris@16: must_emit_line_directive = true; Chris@16: Chris@16: act_pos.set_file(iter_ctx->filename); // initialize file position Chris@16: #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 Chris@16: fs::path rfp(wave::util::create_path(iter_ctx->real_filename.c_str())); Chris@16: std::string real_filename(rfp.string()); Chris@16: ctx.set_current_filename(real_filename.c_str()); Chris@16: #endif Chris@16: Chris@16: ctx.set_current_relative_filename(dir_path.c_str()); Chris@16: iter_ctx->real_relative_filename = dir_path.c_str(); Chris@16: Chris@16: act_pos.set_line(iter_ctx->line); Chris@16: act_pos.set_column(0); Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_include(): handle #include ... directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: namespace impl { Chris@16: Chris@16: // trim all whitespace from the beginning and the end of the given string Chris@16: template Chris@16: inline StringT Chris@16: trim_whitespace(StringT const &s) Chris@16: { Chris@16: typedef typename StringT::size_type size_type; Chris@16: Chris@16: size_type first = s.find_first_not_of(" \t\v\f"); Chris@16: if (StringT::npos == first) Chris@16: return StringT(); Chris@16: size_type last = s.find_last_not_of(" \t\v\f"); Chris@16: return s.substr(first, last-first+1); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_include( Chris@16: typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end, bool include_next) Chris@16: { Chris@16: BOOST_ASSERT(ctx.get_if_block_status()); Chris@16: Chris@16: // preprocess the given token sequence (the body of the #include directive) Chris@16: get_token_value get_value; Chris@16: token_sequence_type expanded; Chris@16: token_sequence_type toexpand; Chris@16: Chris@16: std::copy(make_ref_transform_iterator(begin, get_value), Chris@16: make_ref_transform_iterator(end, get_value), Chris@16: std::inserter(toexpand, toexpand.end())); Chris@16: Chris@16: typename token_sequence_type::iterator begin2 = toexpand.begin(); Chris@16: ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded, Chris@16: false); Chris@16: Chris@16: // now, include the file Chris@16: string_type s (impl::trim_whitespace(boost::wave::util::impl::as_string(expanded))); Chris@16: bool is_system = '<' == s[0] && '>' == s[s.size()-1]; Chris@16: Chris@16: if (!is_system && !('\"' == s[0] && '\"' == s[s.size()-1])) { Chris@16: // should resolve into something like <...> or "..." Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement, Chris@16: s.c_str(), act_pos); Chris@16: return; Chris@16: } Chris@16: on_include(s, is_system, include_next); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_define(): handle #define directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_define (parse_node_type const &node) Chris@16: { Chris@16: BOOST_ASSERT(ctx.get_if_block_status()); Chris@16: Chris@16: // retrieve the macro definition from the parse tree Chris@16: result_type macroname; Chris@16: std::vector macroparameters; Chris@16: token_sequence_type macrodefinition; Chris@16: bool has_parameters = false; Chris@16: position_type pos(act_token.get_position()); Chris@16: Chris@16: if (!boost::wave::util::retrieve_macroname(ctx, node, Chris@16: BOOST_WAVE_PLAIN_DEFINE_ID, macroname, pos, false)) Chris@16: return; Chris@16: has_parameters = boost::wave::util::retrieve_macrodefinition(node, Chris@16: BOOST_WAVE_MACRO_PARAMETERS_ID, macroparameters, pos, false); Chris@16: boost::wave::util::retrieve_macrodefinition(node, Chris@16: BOOST_WAVE_MACRO_DEFINITION_ID, macrodefinition, pos, false); Chris@16: Chris@16: if (has_parameters) { Chris@16: #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 Chris@16: if (boost::wave::need_variadics(ctx.get_language())) { Chris@16: // test whether ellipsis are given, and if yes, if these are placed as the Chris@16: // last argument, test if __VA_ARGS__ is used as a macro parameter name Chris@16: using namespace cpplexer; Chris@16: typedef typename std::vector::iterator Chris@16: parameter_iterator_t; Chris@16: Chris@16: bool seen_ellipses = false; Chris@16: parameter_iterator_t end = macroparameters.end(); Chris@16: for (parameter_iterator_t pit = macroparameters.begin(); Chris@16: pit != end; ++pit) Chris@16: { Chris@16: if (seen_ellipses) { Chris@16: // ellipses are not the last given formal argument Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: bad_define_statement, macroname.get_value().c_str(), Chris@16: (*pit).get_position()); Chris@16: return; Chris@16: } Chris@16: if (T_ELLIPSIS == token_id(*pit)) Chris@16: seen_ellipses = true; Chris@16: Chris@16: // can't use __VA_ARGS__ as a argument name Chris@16: if ("__VA_ARGS__" == (*pit).get_value()) { Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: bad_define_statement_va_args, Chris@16: macroname.get_value().c_str(), (*pit).get_position()); Chris@16: return; Chris@16: } Chris@16: } Chris@16: Chris@16: // if there wasn't an ellipsis, then there shouldn't be a __VA_ARGS__ Chris@16: // placeholder in the definition too [C99 Standard 6.10.3.5] Chris@16: if (!seen_ellipses) { Chris@16: typedef typename token_sequence_type::iterator definition_iterator_t; Chris@16: Chris@16: bool seen_va_args = false; Chris@16: definition_iterator_t pend = macrodefinition.end(); Chris@16: for (definition_iterator_t dit = macrodefinition.begin(); Chris@16: dit != pend; ++dit) Chris@16: { Chris@16: if (T_IDENTIFIER == token_id(*dit) && Chris@16: "__VA_ARGS__" == (*dit).get_value()) Chris@16: { Chris@16: seen_va_args = true; Chris@16: } Chris@16: } Chris@16: if (seen_va_args) { Chris@16: // must not have seen __VA_ARGS__ placeholder Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: bad_define_statement_va_args, Chris@16: macroname.get_value().c_str(), act_token.get_position()); Chris@16: return; Chris@16: } Chris@16: } Chris@16: } Chris@16: else Chris@16: #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 Chris@16: { Chris@16: // test, that there is no T_ELLIPSES given Chris@16: using namespace cpplexer; Chris@16: typedef typename std::vector::iterator Chris@16: parameter_iterator_t; Chris@16: Chris@16: parameter_iterator_t end = macroparameters.end(); Chris@16: for (parameter_iterator_t pit = macroparameters.begin(); Chris@16: pit != end; ++pit) Chris@16: { Chris@16: if (T_ELLIPSIS == token_id(*pit)) { Chris@16: // if variadics are disabled, no ellipses should be given Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: bad_define_statement, macroname.get_value().c_str(), Chris@16: (*pit).get_position()); Chris@16: return; Chris@16: } Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: // add the new macro to the macromap Chris@16: ctx.add_macro_definition(macroname, has_parameters, macroparameters, Chris@16: macrodefinition); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_undefine(): handle #undef directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_undefine (lexer_type const &it) Chris@16: { Chris@16: BOOST_ASSERT(ctx.get_if_block_status()); Chris@16: Chris@16: // retrieve the macro name to undefine from the parse tree Chris@16: ctx.remove_macro_definition((*it).get_value()); // throws for predefined macros Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_ifdef(): handle #ifdef directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_ifdef( Chris@16: result_type const& found_directive, lexer_type const &it) Chris@16: // typename parse_tree_type::const_iterator const &it) Chris@16: // typename parse_tree_type::const_iterator const &end) Chris@16: { Chris@16: // get_token_value get_value; Chris@16: // token_sequence_type toexpand; Chris@16: // Chris@16: // std::copy(make_ref_transform_iterator((*begin).children.begin(), get_value), Chris@16: // make_ref_transform_iterator((*begin).children.end(), get_value), Chris@16: // std::inserter(toexpand, toexpand.end())); Chris@16: Chris@16: bool is_defined = false; Chris@16: token_sequence_type directive; Chris@16: Chris@16: directive.insert(directive.end(), *it); Chris@16: Chris@16: #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 Chris@16: is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end()); Chris@16: ctx.get_hooks().evaluated_conditional_expression(directive, is_defined); Chris@16: #else Chris@16: do { Chris@16: is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end()); Chris@16: } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(), Chris@16: found_directive, directive, is_defined)); Chris@16: #endif Chris@16: ctx.enter_if_block(is_defined); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_ifndef(): handle #ifndef directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_ifndef( Chris@16: result_type const& found_directive, lexer_type const &it) Chris@16: // typename parse_tree_type::const_iterator const &it) Chris@16: // typename parse_tree_type::const_iterator const &end) Chris@16: { Chris@16: // get_token_value get_value; Chris@16: // token_sequence_type toexpand; Chris@16: // Chris@16: // std::copy(make_ref_transform_iterator((*begin).children.begin(), get_value), Chris@16: // make_ref_transform_iterator((*begin).children.end(), get_value), Chris@16: // std::inserter(toexpand, toexpand.end())); Chris@16: Chris@16: bool is_defined = false; Chris@16: token_sequence_type directive; Chris@16: Chris@16: directive.insert(directive.end(), *it); Chris@16: Chris@16: #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 Chris@16: is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end()); Chris@16: ctx.get_hooks().evaluated_conditional_expression(directive, is_defined); Chris@16: #else Chris@16: do { Chris@16: is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end()); Chris@16: } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(), Chris@16: found_directive, directive, is_defined)); Chris@16: #endif Chris@16: ctx.enter_if_block(!is_defined); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_else(): handle #else directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_else() Chris@16: { Chris@16: if (!ctx.enter_else_block()) { Chris@16: // #else without matching #if Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if, Chris@16: "#else", act_pos); Chris@16: } Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_endif(): handle #endif directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_endif() Chris@16: { Chris@16: if (!ctx.exit_if_block()) { Chris@16: // #endif without matching #if Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if, Chris@16: "#endif", act_pos); Chris@16: } Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // replace all remaining (== undefined) identifiers with an integer literal '0' Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::replace_undefined_identifiers( Chris@16: token_sequence_type &expanded) Chris@16: { Chris@16: typename token_sequence_type::iterator exp_end = expanded.end(); Chris@16: for (typename token_sequence_type::iterator exp_it = expanded.begin(); Chris@16: exp_it != exp_end; ++exp_it) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: token_id id = token_id(*exp_it); Chris@16: if (IS_CATEGORY(id, IdentifierTokenType) || Chris@16: IS_CATEGORY(id, KeywordTokenType)) Chris@16: { Chris@16: (*exp_it).set_token_id(T_INTLIT); Chris@16: (*exp_it).set_value("0"); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_if(): handle #if directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_if( Chris@16: result_type const& found_directive, Chris@16: typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end) Chris@16: { Chris@16: // preprocess the given sequence into the provided list Chris@16: get_token_value get_value; Chris@16: token_sequence_type toexpand; Chris@16: Chris@16: std::copy(make_ref_transform_iterator(begin, get_value), Chris@16: make_ref_transform_iterator(end, get_value), Chris@16: std::inserter(toexpand, toexpand.end())); Chris@16: Chris@16: impl::remove_leading_whitespace(ctx, toexpand); Chris@16: Chris@16: bool if_status = false; Chris@16: grammars::value_error status = grammars::error_noerror; Chris@16: token_sequence_type expanded; Chris@16: Chris@16: do { Chris@16: expanded.clear(); Chris@16: Chris@16: typename token_sequence_type::iterator begin2 = toexpand.begin(); Chris@16: ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded); Chris@16: Chris@16: // replace all remaining (== undefined) identifiers with an integer literal '0' Chris@16: replace_undefined_identifiers(expanded); Chris@16: Chris@16: #if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0 Chris@16: { Chris@16: string_type outstr(boost::wave::util::impl::as_string(toexpand)); Chris@16: outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")"; Chris@16: BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#if " << outstr Chris@16: << std::endl; Chris@16: } Chris@16: #endif Chris@16: try { Chris@16: // parse the expression and enter the #if block Chris@16: if_status = grammars::expression_grammar_gen:: Chris@16: evaluate(expanded.begin(), expanded.end(), act_pos, Chris@16: ctx.get_if_block_status(), status); Chris@16: } Chris@16: catch (boost::wave::preprocess_exception const& e) { Chris@16: // any errors occurred have to be dispatched to the context hooks Chris@16: ctx.get_hooks().throw_exception(ctx.derived(), e); Chris@16: break; Chris@16: } Chris@16: Chris@16: #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 Chris@16: ctx.get_hooks().evaluated_conditional_expression(toexpand, if_status); Chris@16: } while (false); Chris@16: #else Chris@16: } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(), Chris@16: found_directive, toexpand, if_status) Chris@16: && status == grammars::error_noerror); Chris@16: #endif Chris@16: Chris@16: ctx.enter_if_block(if_status); Chris@16: if (grammars::error_noerror != status) { Chris@16: // division or other error by zero occurred Chris@16: string_type expression = util::impl::as_string(expanded); Chris@16: if (0 == expression.size()) Chris@16: expression = ""; Chris@16: Chris@16: if (grammars::error_division_by_zero & status) { Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, division_by_zero, Chris@16: expression.c_str(), act_pos); Chris@16: } Chris@16: else if (grammars::error_integer_overflow & status) { Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, integer_overflow, Chris@16: expression.c_str(), act_pos); Chris@16: } Chris@16: else if (grammars::error_character_overflow & status) { Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: character_literal_out_of_range, expression.c_str(), act_pos); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_elif(): handle #elif directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_elif( Chris@16: result_type const& found_directive, Chris@16: typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end) Chris@16: { Chris@16: // preprocess the given sequence into the provided list Chris@16: get_token_value get_value; Chris@16: token_sequence_type toexpand; Chris@16: Chris@16: std::copy(make_ref_transform_iterator(begin, get_value), Chris@16: make_ref_transform_iterator(end, get_value), Chris@16: std::inserter(toexpand, toexpand.end())); Chris@16: Chris@16: impl::remove_leading_whitespace(ctx, toexpand); Chris@16: Chris@16: // check current if block status Chris@16: if (ctx.get_if_block_some_part_status()) { Chris@16: if (!ctx.enter_elif_block(false)) { Chris@16: // #else without matching #if Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: missing_matching_if, "#elif", act_pos); Chris@16: // fall through... Chris@16: } Chris@16: Chris@16: // skip all the expression and the trailing whitespace Chris@16: typename token_sequence_type::iterator begin2 = toexpand.begin(); Chris@16: Chris@16: impl::skip_to_eol(ctx, begin2, toexpand.end()); Chris@16: return; // one of previous #if/#elif was true, so don't enter this #elif Chris@16: } Chris@16: Chris@16: // preprocess the given sequence into the provided list Chris@16: bool if_status = false; Chris@16: grammars::value_error status = grammars::error_noerror; Chris@16: token_sequence_type expanded; Chris@16: Chris@16: do { Chris@16: expanded.clear(); Chris@16: Chris@16: typename token_sequence_type::iterator begin2 = toexpand.begin(); Chris@16: ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded); Chris@16: Chris@16: // replace all remaining (== undefined) identifiers with an integer literal '0' Chris@16: replace_undefined_identifiers(expanded); Chris@16: Chris@16: #if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0 Chris@16: { Chris@16: string_type outstr(boost::wave::util::impl::as_string(toexpand)); Chris@16: outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")"; Chris@16: BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#elif " << outstr << std::endl; Chris@16: } Chris@16: #endif Chris@16: Chris@16: try { Chris@16: // parse the expression and enter the #elif block Chris@16: if_status = grammars::expression_grammar_gen:: Chris@16: evaluate(expanded.begin(), expanded.end(), act_pos, Chris@16: ctx.get_if_block_status(), status); Chris@16: } Chris@16: catch (boost::wave::preprocess_exception const& e) { Chris@16: // any errors occurred have to be dispatched to the context hooks Chris@16: ctx.get_hooks().throw_exception(ctx.derived(), e); Chris@16: } Chris@16: Chris@16: #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 Chris@16: ctx.get_hooks().evaluated_conditional_expression(toexpand, if_status); Chris@16: } while (false); Chris@16: #else Chris@16: } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(), Chris@16: found_directive, toexpand, if_status) Chris@16: && status == grammars::error_noerror); Chris@16: #endif Chris@16: Chris@16: if (!ctx.enter_elif_block(if_status)) { Chris@16: // #elif without matching #if Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if, Chris@16: "#elif", act_pos); Chris@16: return; Chris@16: } Chris@16: Chris@16: if (grammars::error_noerror != status) { Chris@16: // division or other error by zero occurred Chris@16: string_type expression = util::impl::as_string(expanded); Chris@16: if (0 == expression.size()) Chris@16: expression = ""; Chris@16: Chris@16: if (grammars::error_division_by_zero & status) { Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, division_by_zero, Chris@16: expression.c_str(), act_pos); Chris@16: } Chris@16: else if (grammars::error_integer_overflow & status) { Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: integer_overflow, expression.c_str(), act_pos); Chris@16: } Chris@16: else if (grammars::error_character_overflow & status) { Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, Chris@16: character_literal_out_of_range, expression.c_str(), act_pos); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_illformed(): handles the illegal directive Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_illformed( Chris@16: typename result_type::string_type s) Chris@16: { Chris@16: BOOST_ASSERT(ctx.get_if_block_status()); Chris@16: Chris@16: // some messages have more than one newline at the end Chris@16: typename string_type::size_type p = s.find_last_not_of('\n'); Chris@16: if (string_type::npos != p) Chris@16: s = s.substr(0, p+1); Chris@16: Chris@16: // throw the exception Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_directive, Chris@16: s.c_str(), act_pos); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_line(): handle #line directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: namespace impl { Chris@16: Chris@16: template Chris@16: bool retrieve_line_info (IteratorT first, IteratorT const &last, Chris@16: unsigned int &line, StringT &file, Chris@16: boost::wave::preprocess_exception::error_code& error) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: token_id id = token_id(*first); Chris@16: if (T_PP_NUMBER == id || T_INTLIT == id) { Chris@16: // extract line number Chris@16: using namespace std; // some systems have atoi in namespace std Chris@16: line = (unsigned int)atoi((*first).get_value().c_str()); Chris@16: if (0 == line) Chris@16: error = preprocess_exception::bad_line_number; Chris@16: Chris@16: // re-extract line number with spirit to diagnose overflow Chris@16: using namespace boost::spirit::classic; Chris@16: if (!parse((*first).get_value().c_str(), int_p).full) Chris@16: error = preprocess_exception::bad_line_number; Chris@16: Chris@16: // extract file name (if it is given) Chris@16: while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType)) Chris@16: /**/; // skip whitespace Chris@16: Chris@16: if (first != last) { Chris@16: if (T_STRINGLIT != token_id(*first)) { Chris@16: error = preprocess_exception::bad_line_filename; Chris@16: return false; Chris@16: } Chris@16: Chris@16: StringT const &file_lit = (*first).get_value(); Chris@16: Chris@16: if ('L' == file_lit[0]) { Chris@16: error = preprocess_exception::bad_line_filename; Chris@16: return false; // shouldn't be a wide character string Chris@16: } Chris@16: Chris@16: file = file_lit.substr(1, file_lit.size()-2); Chris@16: Chris@16: // test if there is other junk on this line Chris@16: while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType)) Chris@16: /**/; // skip whitespace Chris@16: } Chris@16: return first == last; Chris@16: } Chris@16: error = preprocess_exception::bad_line_statement; Chris@16: return false; Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_line( Chris@16: typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end) Chris@16: { Chris@16: BOOST_ASSERT(ctx.get_if_block_status()); Chris@16: Chris@16: // Try to extract the line number and file name from the given token list Chris@16: // directly. If that fails, preprocess the whole token sequence and try again Chris@16: // to extract this information. Chris@16: token_sequence_type expanded; Chris@16: get_token_value get_value; Chris@16: Chris@16: typedef typename ref_transform_iterator_generator< Chris@16: get_token_value, Chris@16: typename parse_tree_type::const_iterator Chris@16: >::type const_tree_iterator_t; Chris@16: Chris@16: const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value); Chris@16: const_tree_iterator_t last = make_ref_transform_iterator(end, get_value); Chris@16: Chris@16: // try to interpret the #line body as a number followed by an optional Chris@16: // string literal Chris@16: unsigned int line = 0; Chris@16: preprocess_exception::error_code error = preprocess_exception::no_error; Chris@16: string_type file_name; Chris@16: token_sequence_type toexpand; Chris@16: Chris@16: std::copy(first, last, std::inserter(toexpand, toexpand.end())); Chris@16: if (!impl::retrieve_line_info(first, last, line, file_name, error)) { Chris@16: // preprocess the body of this #line message Chris@16: typename token_sequence_type::iterator begin2 = toexpand.begin(); Chris@16: ctx.expand_whole_tokensequence(begin2, toexpand.end(), Chris@16: expanded, false); Chris@16: Chris@16: error = preprocess_exception::no_error; Chris@16: if (!impl::retrieve_line_info(expanded.begin(), expanded.end(), Chris@16: line, file_name, error)) Chris@16: { Chris@16: typename ContextT::string_type msg( Chris@16: boost::wave::util::impl::as_string(expanded)); Chris@16: BOOST_WAVE_THROW_VAR_CTX(ctx, preprocess_exception, error, Chris@16: msg.c_str(), act_pos); Chris@16: return; Chris@16: } Chris@16: Chris@16: // call the corresponding pp hook function Chris@16: ctx.get_hooks().found_line_directive(ctx.derived(), expanded, line, Chris@16: file_name.c_str()); Chris@16: } Chris@16: else { Chris@16: // call the corresponding pp hook function Chris@16: ctx.get_hooks().found_line_directive(ctx.derived(), toexpand, line, Chris@16: file_name.c_str()); Chris@16: } Chris@16: Chris@16: // the queues should be empty at this point Chris@16: BOOST_ASSERT(unput_queue.empty()); Chris@16: BOOST_ASSERT(pending_queue.empty()); Chris@16: Chris@16: // make sure error recovery starts on the next line Chris@16: must_emit_line_directive = true; Chris@16: Chris@16: // diagnose possible error in detected line directive Chris@16: if (error != preprocess_exception::no_error) { Chris@16: typename ContextT::string_type msg( Chris@16: boost::wave::util::impl::as_string(expanded)); Chris@16: BOOST_WAVE_THROW_VAR_CTX(ctx, preprocess_exception, error, Chris@16: msg.c_str(), act_pos); Chris@16: return; Chris@16: } Chris@16: Chris@16: // set new line number/filename only if ok Chris@16: if (!file_name.empty()) { // reuse current file name Chris@16: using boost::wave::util::impl::unescape_lit; Chris@16: act_pos.set_file(unescape_lit(file_name).c_str()); Chris@16: } Chris@16: act_pos.set_line(line); Chris@16: iter_ctx->first.set_position(act_pos); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_error(): handle #error directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_error( Chris@16: typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end) Chris@16: { Chris@16: BOOST_ASSERT(ctx.get_if_block_status()); Chris@16: Chris@16: // preprocess the given sequence into the provided list Chris@16: token_sequence_type expanded; Chris@16: get_token_value get_value; Chris@16: Chris@16: typename ref_transform_iterator_generator< Chris@16: get_token_value, Chris@16: typename parse_tree_type::const_iterator Chris@16: >::type first = make_ref_transform_iterator(begin, get_value); Chris@16: Chris@16: #if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0 Chris@16: // preprocess the body of this #error message Chris@16: token_sequence_type toexpand; Chris@16: Chris@16: std::copy(first, make_ref_transform_iterator(end, get_value), Chris@16: std::inserter(toexpand, toexpand.end())); Chris@16: Chris@16: typename token_sequence_type::iterator begin2 = toexpand.begin(); Chris@16: ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded, Chris@16: false); Chris@16: if (!ctx.get_hooks().found_error_directive(ctx.derived(), toexpand)) Chris@16: #else Chris@16: // simply copy the body of this #error message to the issued diagnostic Chris@16: // message Chris@16: std::copy(first, make_ref_transform_iterator(end, get_value), Chris@16: std::inserter(expanded, expanded.end())); Chris@16: if (!ctx.get_hooks().found_error_directive(ctx.derived(), expanded)) Chris@16: #endif Chris@16: { Chris@16: // report the corresponding error Chris@16: BOOST_WAVE_STRINGTYPE msg(boost::wave::util::impl::as_string(expanded)); Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, error_directive, Chris@16: msg.c_str(), act_pos); Chris@16: } Chris@16: } Chris@16: Chris@16: #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0 Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_warning(): handle #warning directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void Chris@16: pp_iterator_functor::on_warning( Chris@16: typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end) Chris@16: { Chris@16: BOOST_ASSERT(ctx.get_if_block_status()); Chris@16: Chris@16: // preprocess the given sequence into the provided list Chris@16: token_sequence_type expanded; Chris@16: get_token_value get_value; Chris@16: Chris@16: typename ref_transform_iterator_generator< Chris@16: get_token_value, Chris@16: typename parse_tree_type::const_iterator Chris@16: >::type first = make_ref_transform_iterator(begin, get_value); Chris@16: Chris@16: #if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0 Chris@16: // preprocess the body of this #warning message Chris@16: token_sequence_type toexpand; Chris@16: Chris@16: std::copy(first, make_ref_transform_iterator(end, get_value), Chris@16: std::inserter(toexpand, toexpand.end())); Chris@16: Chris@16: typename token_sequence_type::iterator begin2 = toexpand.begin(); Chris@16: ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded, Chris@16: false); Chris@16: if (!ctx.get_hooks().found_warning_directive(ctx.derived(), toexpand)) Chris@16: #else Chris@16: // simply copy the body of this #warning message to the issued diagnostic Chris@16: // message Chris@16: std::copy(first, make_ref_transform_iterator(end, get_value), Chris@16: std::inserter(expanded, expanded.end())); Chris@16: if (!ctx.get_hooks().found_warning_directive(ctx.derived(), expanded)) Chris@16: #endif Chris@16: { Chris@16: // report the corresponding error Chris@16: BOOST_WAVE_STRINGTYPE msg(boost::wave::util::impl::as_string(expanded)); Chris@16: BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, warning_directive, Chris@16: msg.c_str(), act_pos); Chris@16: } Chris@16: } Chris@16: #endif // BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0 Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // on_pragma(): handle #pragma directives Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline bool Chris@16: pp_iterator_functor::on_pragma( Chris@16: typename parse_tree_type::const_iterator const &begin, Chris@16: typename parse_tree_type::const_iterator const &end) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: BOOST_ASSERT(ctx.get_if_block_status()); Chris@16: Chris@16: // Look at the pragma token sequence and decide, if the first token is STDC Chris@16: // (see C99 standard [6.10.6.2]), if it is, the sequence must _not_ be Chris@16: // preprocessed. Chris@16: token_sequence_type expanded; Chris@16: get_token_value get_value; Chris@16: Chris@16: typedef typename ref_transform_iterator_generator< Chris@16: get_token_value, Chris@16: typename parse_tree_type::const_iterator Chris@16: >::type const_tree_iterator_t; Chris@16: Chris@16: const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value); Chris@16: const_tree_iterator_t last = make_ref_transform_iterator(end, get_value); Chris@16: Chris@16: expanded.push_back(result_type(T_PP_PRAGMA, "#pragma", act_token.get_position())); Chris@16: expanded.push_back(result_type(T_SPACE, " ", act_token.get_position())); Chris@16: Chris@16: while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType)) Chris@16: expanded.push_back(*first); // skip whitespace Chris@16: Chris@16: if (first != last) { Chris@16: if (T_IDENTIFIER == token_id(*first) && Chris@16: boost::wave::need_c99(ctx.get_language()) && Chris@16: (*first).get_value() == "STDC") Chris@16: { Chris@16: // do _not_ preprocess the token sequence Chris@16: std::copy(first, last, std::inserter(expanded, expanded.end())); Chris@16: } Chris@16: else { Chris@16: #if BOOST_WAVE_PREPROCESS_PRAGMA_BODY != 0 Chris@16: // preprocess the given tokensequence Chris@16: token_sequence_type toexpand; Chris@16: Chris@16: std::copy(first, last, std::inserter(toexpand, toexpand.end())); Chris@16: Chris@16: typename token_sequence_type::iterator begin2 = toexpand.begin(); Chris@16: ctx.expand_whole_tokensequence(begin2, toexpand.end(), Chris@16: expanded, false); Chris@16: #else Chris@16: // do _not_ preprocess the token sequence Chris@16: std::copy(first, last, std::inserter(expanded, expanded.end())); Chris@16: #endif Chris@16: } Chris@16: } Chris@16: expanded.push_back(result_type(T_NEWLINE, "\n", act_token.get_position())); Chris@16: Chris@16: // the queues should be empty at this point Chris@16: BOOST_ASSERT(unput_queue.empty()); Chris@16: BOOST_ASSERT(pending_queue.empty()); Chris@16: Chris@16: // try to interpret the expanded #pragma body Chris@16: token_sequence_type pending; Chris@16: if (interpret_pragma(expanded, pending)) { Chris@16: // if there is some replacement text, insert it into the pending queue Chris@16: if (!pending.empty()) Chris@16: pending_queue.splice(pending_queue.begin(), pending); Chris@16: return true; // this #pragma was successfully recognized Chris@16: } Chris@16: Chris@16: #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0 Chris@16: // Move the resulting token sequence into the pending_queue, so it will be Chris@16: // returned to the caller. Chris@16: if (boost::wave::need_emit_pragma_directives(ctx.get_language())) { Chris@16: pending_queue.splice(pending_queue.begin(), expanded); Chris@16: return false; // return the whole #pragma directive Chris@16: } Chris@16: #endif Chris@16: return true; // skip the #pragma at all Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool Chris@16: pp_iterator_functor::interpret_pragma( Chris@16: token_sequence_type const &pragma_body, token_sequence_type &result) Chris@16: { Chris@16: using namespace cpplexer; Chris@16: Chris@16: typename token_sequence_type::const_iterator end = pragma_body.end(); Chris@16: typename token_sequence_type::const_iterator it = pragma_body.begin(); Chris@16: for (++it; it != end && IS_CATEGORY(*it, WhiteSpaceTokenType); ++it) Chris@16: /**/; // skip whitespace Chris@16: Chris@16: if (it == end) // eof reached Chris@16: return false; Chris@16: Chris@16: return boost::wave::util::interpret_pragma( Chris@16: ctx.derived(), act_token, it, end, result); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: } // namespace impl Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // pp_iterator Chris@16: // Chris@16: // The boost::wave::pp_iterator template is the iterator, through which Chris@16: // the resulting preprocessed input stream is accessible. Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: template Chris@16: class pp_iterator Chris@16: : public boost::spirit::classic::multi_pass< Chris@16: boost::wave::impl::pp_iterator_functor, Chris@16: boost::wave::util::functor_input Chris@16: > Chris@16: { Chris@16: public: Chris@16: typedef boost::wave::impl::pp_iterator_functor input_policy_type; Chris@16: Chris@16: private: Chris@16: typedef Chris@16: boost::spirit::classic::multi_pass Chris@16: base_type; Chris@16: typedef pp_iterator self_type; Chris@16: typedef boost::wave::util::functor_input functor_input_type; Chris@16: Chris@16: public: Chris@16: pp_iterator() Chris@16: {} Chris@16: Chris@16: template Chris@16: pp_iterator(ContextT &ctx, IteratorT const &first, IteratorT const &last, Chris@16: typename ContextT::position_type const &pos) Chris@16: : base_type(input_policy_type(ctx, first, last, pos)) Chris@16: {} Chris@16: Chris@16: bool force_include(char const *path_, bool is_last) Chris@16: { Chris@16: bool result = this->get_functor().on_include_helper(path_, path_, Chris@16: false, false); Chris@16: if (is_last) { Chris@16: this->functor_input_type:: Chris@16: template inner::advance_input(); Chris@16: } Chris@16: return result; Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: } // namespace wave Chris@16: } // namespace boost 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_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED)