Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:53:41

0001 /*=============================================================================
0002     Boost.Wave: A Standard compliant C++ preprocessor library
0003 
0004     Definition of the preprocessor iterator
0005 
0006     http://www.boost.org/
0007 
0008     Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
0009     Software License, Version 1.0. (See accompanying file
0010     LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0011 =============================================================================*/
0012 
0013 #if !defined(BOOST_CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED)
0014 #define BOOST_CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED
0015 
0016 #include <string>
0017 #include <vector>
0018 #include <list>
0019 #include <cstdlib>
0020 #include <cctype>
0021 
0022 #include <boost/assert.hpp>
0023 #include <boost/shared_ptr.hpp>
0024 #include <boost/filesystem/path.hpp>
0025 #include <boost/filesystem/operations.hpp>
0026 #include <boost/lexical_cast.hpp>
0027 #include <boost/spirit/include/classic_multi_pass.hpp>
0028 #include <boost/spirit/include/classic_parse_tree_utils.hpp>
0029 
0030 #include <boost/wave/wave_config.hpp>
0031 #include <boost/pool/pool_alloc.hpp>
0032 
0033 #include <boost/wave/util/insert_whitespace_detection.hpp>
0034 #include <boost/wave/util/macro_helpers.hpp>
0035 #include <boost/wave/util/cpp_macromap_utils.hpp>
0036 #include <boost/wave/util/interpret_pragma.hpp>
0037 #include <boost/wave/util/transform_iterator.hpp>
0038 #include <boost/wave/util/functor_input.hpp>
0039 #include <boost/wave/util/filesystem_compatibility.hpp>
0040 
0041 #include <boost/wave/grammars/cpp_grammar_gen.hpp>
0042 #include <boost/wave/grammars/cpp_expression_grammar_gen.hpp>
0043 #if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0
0044 #include <boost/wave/grammars/cpp_predef_macros_gen.hpp>
0045 #endif
0046 
0047 #include <boost/wave/whitespace_handling.hpp>
0048 #include <boost/wave/cpp_iteration_context.hpp>
0049 #include <boost/wave/cpp_exceptions.hpp>
0050 #include <boost/wave/language_support.hpp>
0051 
0052 // this must occur after all of the includes and before any code appears
0053 #ifdef BOOST_HAS_ABI_HEADERS
0054 #include BOOST_ABI_PREFIX
0055 #endif
0056 
0057 ///////////////////////////////////////////////////////////////////////////////
0058 namespace boost {
0059 namespace wave {
0060 namespace util {
0061 
0062 ///////////////////////////////////////////////////////////////////////////////
0063 // retrieve the macro name from the parse tree
0064 template <
0065     typename ContextT, typename ParseNodeT, typename TokenT,
0066     typename PositionT
0067 >
0068 inline bool
0069 retrieve_macroname(ContextT& ctx, ParseNodeT const &node,
0070     boost::spirit::classic::parser_id id, TokenT &macroname, PositionT& act_pos,
0071     bool update_position)
0072 {
0073     ParseNodeT const* name_node = 0;
0074 
0075     using boost::spirit::classic::find_node;
0076     if (!find_node(node, id, &name_node))
0077     {
0078         // ill formed define statement (unexpected, should not happen)
0079         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_define_statement,
0080             "bad parse tree (unexpected)", act_pos);
0081         return false;
0082     }
0083 
0084     typename ParseNodeT::children_t const& children = name_node->children;
0085 
0086     if (0 == children.size() ||
0087         children.front().value.begin() == children.front().value.end())
0088     {
0089         // ill formed define statement (unexpected, should not happen)
0090         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_define_statement,
0091             "bad parse tree (unexpected)", act_pos);
0092         return false;
0093     }
0094 
0095     // retrieve the macro name
0096     macroname = *children.front().value.begin();
0097     if (update_position) {
0098         macroname.set_position(act_pos);
0099         act_pos.set_column(act_pos.get_column() + macroname.get_value().size());
0100     }
0101     return true;
0102 }
0103 
0104 ///////////////////////////////////////////////////////////////////////////////
0105 // retrieve the macro parameters or the macro definition from the parse tree
0106 template <typename ParseNodeT, typename ContainerT, typename PositionT>
0107 inline bool
0108 retrieve_macrodefinition(
0109     ParseNodeT const &node, boost::spirit::classic::parser_id id,
0110     ContainerT &macrodefinition, PositionT& act_pos, bool update_position)
0111 {
0112     using namespace boost::wave;
0113     typedef typename ParseNodeT::const_tree_iterator const_tree_iterator;
0114 
0115     // find macro parameters/macro definition inside the parse tree
0116     std::pair<const_tree_iterator, const_tree_iterator> nodes;
0117 
0118     using boost::spirit::classic::get_node_range;
0119     if (get_node_range(node, id, nodes)) {
0120         // copy all parameters to the supplied container
0121         typename ContainerT::iterator last_nonwhite = macrodefinition.end();
0122         const_tree_iterator end = nodes.second;
0123 
0124         for (const_tree_iterator cit = nodes.first; cit != end; ++cit) {
0125             if ((*cit).value.begin() != (*cit).value.end()) {
0126                 typename ContainerT::iterator inserted = macrodefinition.insert(
0127                     macrodefinition.end(), *(*cit).value.begin());
0128 
0129                 if (!IS_CATEGORY(macrodefinition.back(), WhiteSpaceTokenType) &&
0130                     T_NEWLINE != token_id(macrodefinition.back()) &&
0131                     T_EOF != token_id(macrodefinition.back()))
0132                 {
0133                     last_nonwhite = inserted;
0134                 }
0135 
0136                 if (update_position) {
0137                     (*inserted).set_position(act_pos);
0138                     act_pos.set_column(
0139                         act_pos.get_column() + (*inserted).get_value().size());
0140                 }
0141             }
0142         }
0143 
0144         // trim trailing whitespace (leading whitespace is trimmed by the grammar)
0145         if (last_nonwhite != macrodefinition.end()) {
0146             if (update_position) {
0147                 act_pos.set_column((*last_nonwhite).get_position().get_column() +
0148                     (*last_nonwhite).get_value().size());
0149             }
0150             macrodefinition.erase(++last_nonwhite, macrodefinition.end());
0151         }
0152         return true;
0153     }
0154     return false;
0155 }
0156 
0157 #if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0
0158 ///////////////////////////////////////////////////////////////////////////////
0159 //  add an additional predefined macro given by a string (MACRO(x)=definition)
0160 template <typename ContextT>
0161 bool add_macro_definition(ContextT &ctx, std::string macrostring,
0162     bool is_predefined, boost::wave::language_support language)
0163 {
0164     typedef typename ContextT::token_type token_type;
0165     typedef typename ContextT::lexer_type lexer_type;
0166     typedef typename token_type::position_type position_type;
0167     typedef boost::wave::grammars::predefined_macros_grammar_gen<lexer_type>
0168         predef_macros_type;
0169 
0170     using namespace boost::wave;
0171     using namespace std;    // isspace is in std namespace for some systems
0172 
0173     // skip leading whitespace
0174     std::string::iterator begin = macrostring.begin();
0175     std::string::iterator end = macrostring.end();
0176 
0177     while(begin != end && isspace(*begin))
0178         ++begin;
0179 
0180     // parse the macro definition
0181     position_type act_pos("<command line>");
0182     boost::spirit::classic::tree_parse_info<lexer_type> hit =
0183         predef_macros_type::parse_predefined_macro(
0184             lexer_type(begin, end, position_type(), language), lexer_type());
0185 
0186     if (!hit.match || (!hit.full && T_EOF != token_id(*hit.stop))) {
0187         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_macro_definition,
0188             macrostring.c_str(), act_pos);
0189         return false;
0190     }
0191 
0192     // retrieve the macro definition from the parse tree
0193     token_type macroname;
0194     std::vector<token_type> macroparameters;
0195     typename ContextT::token_sequence_type macrodefinition;
0196     bool has_parameters = false;
0197 
0198     if (!boost::wave::util::retrieve_macroname(ctx, *hit.trees.begin(),
0199             BOOST_WAVE_PLAIN_DEFINE_ID, macroname, act_pos, true))
0200         return false;
0201     has_parameters = boost::wave::util::retrieve_macrodefinition(*hit.trees.begin(),
0202         BOOST_WAVE_MACRO_PARAMETERS_ID, macroparameters, act_pos, true);
0203     boost::wave::util::retrieve_macrodefinition(*hit.trees.begin(),
0204         BOOST_WAVE_MACRO_DEFINITION_ID, macrodefinition, act_pos, true);
0205 
0206     // get rid of trailing T_EOF
0207     if (!macrodefinition.empty() && token_id(macrodefinition.back()) == T_EOF)
0208         macrodefinition.pop_back();
0209 
0210     //  If no macrodefinition is given, and the macro string does not end with a
0211     //  '=', then the macro should be defined with the value '1'
0212     if (macrodefinition.empty() && '=' != macrostring[macrostring.size()-1])
0213         macrodefinition.push_back(token_type(T_INTLIT, "1", act_pos));
0214 
0215     // add the new macro to the macromap
0216     return ctx.add_macro_definition(macroname, has_parameters, macroparameters,
0217         macrodefinition, is_predefined);
0218 }
0219 #endif // BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0
0220 
0221 ///////////////////////////////////////////////////////////////////////////////
0222 }   // namespace util
0223 
0224 ///////////////////////////////////////////////////////////////////////////////
0225 //  forward declaration
0226 template <typename ContextT> class pp_iterator;
0227 
0228 namespace impl {
0229 
0230 ///////////////////////////////////////////////////////////////////////////////
0231 //
0232 //  pp_iterator_functor
0233 //
0234 ///////////////////////////////////////////////////////////////////////////////
0235 template <typename ContextT>
0236 class pp_iterator_functor {
0237 
0238 public:
0239     // interface to the boost::spirit::classic::iterator_policies::functor_input policy
0240     typedef typename ContextT::token_type               result_type;
0241 
0242     //  eof token
0243     static result_type const eof;
0244 
0245 private:
0246     // type of a token sequence
0247     typedef typename ContextT::token_sequence_type      token_sequence_type;
0248 
0249     typedef typename ContextT::lexer_type               lexer_type;
0250     typedef typename result_type::string_type           string_type;
0251     typedef typename result_type::position_type         position_type;
0252     typedef boost::wave::grammars::cpp_grammar_gen<lexer_type, token_sequence_type>
0253         cpp_grammar_type;
0254 
0255     //  iteration context related types (an iteration context represents a current
0256     //  position in an included file)
0257     typedef base_iteration_context<ContextT, lexer_type>
0258         base_iteration_context_type;
0259     typedef iteration_context<ContextT, lexer_type> iteration_context_type;
0260 
0261     // parse tree related types
0262     typedef typename cpp_grammar_type::node_factory_type node_factory_type;
0263     typedef boost::spirit::classic::tree_parse_info<lexer_type, node_factory_type>
0264         tree_parse_info_type;
0265     typedef boost::spirit::classic::tree_match<lexer_type, node_factory_type>
0266         parse_tree_match_type;
0267     typedef typename parse_tree_match_type::node_t       parse_node_type;       // tree_node<node_val_data<> >
0268     typedef typename parse_tree_match_type::parse_node_t parse_node_value_type; // node_val_data<>
0269     typedef typename parse_tree_match_type::container_t  parse_tree_type;       // parse_node_type::children_t
0270 
0271 public:
0272     template <typename IteratorT>
0273     pp_iterator_functor(ContextT &ctx_, IteratorT const &first_,
0274             IteratorT const &last_, typename ContextT::position_type const &pos_)
0275     :   ctx(ctx_),
0276         iter_ctx(new base_iteration_context_type(ctx,
0277                 lexer_type(first_, last_, pos_,
0278                     boost::wave::enable_prefer_pp_numbers(ctx.get_language())),
0279                 lexer_type(),
0280                 pos_.get_file().c_str()
0281             )),
0282         seen_newline(true), skipped_newline(false),
0283         must_emit_line_directive(false), act_pos(ctx_.get_main_pos()),
0284         whitespace(boost::wave::need_insert_whitespace(ctx.get_language()))
0285     {
0286         act_pos.set_file(pos_.get_file());
0287 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
0288         ctx_.set_current_filename(pos_.get_file().c_str());
0289 #endif
0290         iter_ctx->emitted_lines = (unsigned int)(-1);   // force #line directive
0291     }
0292 
0293     // get the next preprocessed token
0294     result_type const &operator()();
0295 
0296     // get the last recognized token (for error processing etc.)
0297     result_type const &current_token() const { return act_token; }
0298 
0299 protected:
0300     friend class pp_iterator<ContextT>;
0301     bool on_include_helper(char const *t, char const *s, bool is_system,
0302         bool include_next);
0303 
0304 protected:
0305     result_type const &get_next_token();
0306     result_type const &pp_token();
0307 
0308     template <typename IteratorT>
0309     bool extract_identifier(IteratorT &it);
0310     template <typename IteratorT>
0311     bool ensure_is_last_on_line(IteratorT& it, bool call_hook = true);
0312     template <typename IteratorT>
0313     bool skip_to_eol_with_check(IteratorT &it, bool call_hook = true);
0314 
0315     bool pp_directive();
0316     template <typename IteratorT>
0317     bool handle_pp_directive(IteratorT &it);
0318     bool dispatch_directive(tree_parse_info_type const &hit,
0319         result_type const& found_directive,
0320         token_sequence_type const& found_eoltokens);
0321     void replace_undefined_identifiers(token_sequence_type &expanded);
0322 
0323     void on_include(string_type const &s, bool is_system, bool include_next);
0324     void on_include(typename parse_tree_type::const_iterator const &begin,
0325         typename parse_tree_type::const_iterator const &end, bool include_next);
0326 
0327     void on_define(parse_node_type const &node);
0328     void on_undefine(lexer_type const &it);
0329 
0330     void on_ifdef(result_type const& found_directive,
0331         typename parse_tree_type::const_iterator const &begin,
0332         typename parse_tree_type::const_iterator const &end);
0333     void on_ifndef(result_type const& found_directive,
0334         typename parse_tree_type::const_iterator const &begin,
0335         typename parse_tree_type::const_iterator const &end);
0336     void on_else();
0337     void on_endif();
0338     void on_illformed(typename result_type::string_type s);
0339 
0340     void on_line(typename parse_tree_type::const_iterator const &begin,
0341         typename parse_tree_type::const_iterator const &end);
0342     void on_if(result_type const& found_directive,
0343         typename parse_tree_type::const_iterator const &begin,
0344         typename parse_tree_type::const_iterator const &end);
0345     void on_elif(result_type const& found_directive,
0346         typename parse_tree_type::const_iterator const &begin,
0347         typename parse_tree_type::const_iterator const &end);
0348     void on_error(typename parse_tree_type::const_iterator const &begin,
0349         typename parse_tree_type::const_iterator const &end);
0350 #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
0351     void on_warning(typename parse_tree_type::const_iterator const &begin,
0352         typename parse_tree_type::const_iterator const &end);
0353 #endif
0354     bool on_pragma(typename parse_tree_type::const_iterator const &begin,
0355         typename parse_tree_type::const_iterator const &end);
0356 
0357     bool emit_line_directive();
0358     bool returned_from_include();
0359 
0360     bool interpret_pragma(token_sequence_type const &pragma_body,
0361         token_sequence_type &result);
0362 
0363 private:
0364     ContextT &ctx;              // context, this iterator is associated with
0365     boost::shared_ptr<base_iteration_context_type> iter_ctx;
0366 
0367     bool seen_newline;              // needed for recognizing begin of line
0368     bool skipped_newline;           // a newline has been skipped since last one
0369     bool must_emit_line_directive;  // must emit a line directive
0370     result_type act_token;          // current token
0371     typename result_type::position_type &act_pos;   // current fileposition (references the macromap)
0372 
0373     token_sequence_type unput_queue;     // tokens to be preprocessed again
0374     token_sequence_type pending_queue;   // tokens already preprocessed
0375 
0376     // detect whether to insert additional whitespace in between two adjacent
0377     // tokens, which otherwise would form a different token type, if
0378     // re-tokenized
0379     boost::wave::util::insert_whitespace_detection whitespace;
0380 };
0381 
0382 ///////////////////////////////////////////////////////////////////////////////
0383 //  eof token
0384 template <typename ContextT>
0385 typename pp_iterator_functor<ContextT>::result_type const
0386     pp_iterator_functor<ContextT>::eof;
0387 
0388 ///////////////////////////////////////////////////////////////////////////////
0389 //
0390 //  returned_from_include()
0391 //
0392 //      Tests if it is necessary to pop the include file context (eof inside
0393 //      a file was reached). If yes, it pops this context. Preprocessing will
0394 //      continue with the next outer file scope.
0395 //
0396 ///////////////////////////////////////////////////////////////////////////////
0397 template <typename ContextT>
0398 inline bool
0399 pp_iterator_functor<ContextT>::returned_from_include()
0400 {
0401     if (iter_ctx->first == iter_ctx->last && ctx.get_iteration_depth() > 0) {
0402         // call the include policy trace function
0403         ctx.get_hooks().returning_from_include_file(ctx.derived());
0404 
0405     // restore the previous iteration context after finishing the preprocessing
0406     // of the included file
0407         BOOST_WAVE_STRINGTYPE oldfile = iter_ctx->real_filename;
0408         position_type old_pos (act_pos);
0409 
0410         // if this file has include guards handle it as if it had a #pragma once
0411 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
0412         if (need_include_guard_detection(ctx.get_language())) {
0413             std::string guard_name;
0414             if (iter_ctx->first.has_include_guards(guard_name))
0415                 ctx.add_pragma_once_header(ctx.get_current_filename(), guard_name);
0416         }
0417 #endif
0418         iter_ctx = ctx.pop_iteration_context();
0419 
0420         must_emit_line_directive = true;
0421         iter_ctx->emitted_lines = (unsigned int)(-1);   // force #line directive
0422         seen_newline = true;
0423 
0424         // restore current file position
0425         act_pos.set_file(iter_ctx->filename);
0426         act_pos.set_line(iter_ctx->line);
0427         act_pos.set_column(0);
0428 
0429         // restore the actual current file and directory
0430 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
0431         namespace fs = boost::filesystem;
0432         fs::path rfp(wave::util::create_path(iter_ctx->real_filename.c_str()));
0433         std::string real_filename(rfp.string());
0434         ctx.set_current_filename(real_filename.c_str());
0435 #endif
0436         ctx.set_current_directory(iter_ctx->real_filename.c_str());
0437         ctx.set_current_relative_filename(iter_ctx->real_relative_filename.c_str());
0438 
0439         // ensure the integrity of the #if/#endif stack
0440         // report unbalanced #if/#endif now to make it possible to recover properly
0441         if (iter_ctx->if_block_depth != ctx.get_if_block_depth()) {
0442             using boost::wave::util::impl::escape_lit;
0443             BOOST_WAVE_STRINGTYPE msg(escape_lit(oldfile));
0444             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, unbalanced_if_endif,
0445                 msg.c_str(), old_pos);
0446         }
0447         return true;
0448     }
0449     return false;
0450 }
0451 
0452 ///////////////////////////////////////////////////////////////////////////////
0453 //
0454 //  operator()(): get the next preprocessed token
0455 //
0456 //      throws a preprocess_exception, if appropriate
0457 //
0458 ///////////////////////////////////////////////////////////////////////////////
0459 namespace impl {
0460 
0461     //  It may be necessary to emit a #line directive either
0462     //  - when comments need to be preserved: if the current token is not a
0463     //    whitespace, except comments
0464     //  - when comments are to be skipped: if the current token is not a
0465     //    whitespace token.
0466     template <typename ContextT>
0467     bool consider_emitting_line_directive(ContextT const& ctx, token_id id)
0468     {
0469         if (need_preserve_comments(ctx.get_language()))
0470         {
0471             if (!IS_CATEGORY(id, EOLTokenType) && !IS_CATEGORY(id, EOFTokenType))
0472             {
0473                 return true;
0474             }
0475         }
0476         if (!IS_CATEGORY(id, WhiteSpaceTokenType) &&
0477             !IS_CATEGORY(id, EOLTokenType) && !IS_CATEGORY(id, EOFTokenType))
0478         {
0479             return true;
0480         }
0481         return false;
0482     }
0483 }
0484 
0485 template <typename ContextT>
0486 inline typename pp_iterator_functor<ContextT>::result_type const &
0487 pp_iterator_functor<ContextT>::operator()()
0488 {
0489     using namespace boost::wave;
0490 
0491     // make sure the cwd has been initialized
0492     ctx.init_context();
0493 
0494     // loop over skip able whitespace until something significant is found
0495     bool was_seen_newline = seen_newline;
0496     bool was_skipped_newline = skipped_newline;
0497     token_id id = T_UNKNOWN;
0498 
0499     try {   // catch lexer exceptions
0500         do {
0501             if (skipped_newline) {
0502                 was_skipped_newline = true;
0503                 skipped_newline = false;
0504             }
0505 
0506             // get_next_token assigns result to act_token member
0507             get_next_token();
0508 
0509             // if comments shouldn't be preserved replace them with newlines
0510             id = token_id(act_token);
0511             if (!need_preserve_comments(ctx.get_language()) &&
0512                 (T_CPPCOMMENT == id || context_policies::util::ccomment_has_newline(act_token)))
0513             {
0514                 act_token.set_token_id(id = T_NEWLINE);
0515                 act_token.set_value("\n");
0516             }
0517 
0518             if (IS_CATEGORY(id, EOLTokenType))
0519                 seen_newline = true;
0520 
0521         } while (ctx.get_hooks().may_skip_whitespace(ctx.derived(), act_token, skipped_newline));
0522     }
0523     catch (boost::wave::cpplexer::lexing_exception const& e) {
0524         // dispatch any lexer exceptions to the context hook function
0525         ctx.get_hooks().throw_exception(ctx.derived(), e);
0526         return act_token;
0527     }
0528 
0529     // restore the accumulated skipped_newline state for next invocation
0530     if (was_skipped_newline)
0531         skipped_newline = true;
0532 
0533     // if there were skipped any newlines, we must emit a #line directive
0534     if ((must_emit_line_directive || (was_seen_newline && skipped_newline)) &&
0535         impl::consider_emitting_line_directive(ctx, id))
0536     {
0537         // must emit a #line directive
0538         if (need_emit_line_directives(ctx.get_language()) && emit_line_directive())
0539         {
0540             skipped_newline = false;
0541             ctx.get_hooks().may_skip_whitespace(ctx.derived(), act_token, skipped_newline);     // feed ws eater FSM
0542             id = token_id(act_token);
0543         }
0544     }
0545 
0546     // cleanup of certain tokens required
0547     seen_newline = false;
0548     switch (id) {
0549     case T_NONREPLACABLE_IDENTIFIER:
0550         act_token.set_token_id(id = T_IDENTIFIER);
0551         break;
0552 
0553     case T_GENERATEDNEWLINE:  // was generated by emit_line_directive()
0554         act_token.set_token_id(id = T_NEWLINE);
0555         ++iter_ctx->emitted_lines;
0556         seen_newline = true;
0557         break;
0558 
0559     case T_NEWLINE:
0560     case T_CPPCOMMENT:
0561         seen_newline = true;
0562         ++iter_ctx->emitted_lines;
0563         break;
0564 
0565 #if BOOST_WAVE_SUPPORT_CPP0X != 0
0566     case T_RAWSTRINGLIT:
0567         iter_ctx->emitted_lines +=
0568             context_policies::util::rawstring_count_newlines(act_token);
0569         break;
0570 #endif
0571 
0572     case T_CCOMMENT:          // will come here only if whitespace is preserved
0573         iter_ctx->emitted_lines +=
0574             context_policies::util::ccomment_count_newlines(act_token);
0575         break;
0576 
0577     case T_PP_NUMBER:        // re-tokenize the pp-number
0578         {
0579             token_sequence_type rescanned;
0580 
0581             std::string pp_number(
0582                 util::to_string<std::string>(act_token.get_value()));
0583 
0584             lexer_type it = lexer_type(pp_number.begin(),
0585                 pp_number.end(), act_token.get_position(),
0586                 ctx.get_language());
0587             lexer_type end = lexer_type();
0588 
0589             for (/**/; it != end && T_EOF != token_id(*it); ++it)
0590                 rescanned.push_back(*it);
0591 
0592             pending_queue.splice(pending_queue.begin(), rescanned);
0593             act_token = pending_queue.front();
0594             id = token_id(act_token);
0595             pending_queue.pop_front();
0596         }
0597         break;
0598 
0599     case T_EOF:
0600         seen_newline = true;
0601         break;
0602 
0603     default:    // make sure whitespace at line begin keeps seen_newline status
0604         if (IS_CATEGORY(id, WhiteSpaceTokenType))
0605             seen_newline = was_seen_newline;
0606         break;
0607     }
0608 
0609     if (token_is_valid(act_token) && whitespace.must_insert(id, act_token.get_value())) {
0610         // must insert some whitespace into the output stream to avoid adjacent
0611         // tokens, which would form different (and wrong) tokens
0612         whitespace.shift_tokens(T_SPACE);
0613         pending_queue.push_front(act_token);        // push this token back
0614         return act_token = result_type(T_SPACE,
0615             typename result_type::string_type(" "),
0616             act_token.get_position());
0617     }
0618     whitespace.shift_tokens(id);
0619     return ctx.get_hooks().generated_token(ctx.derived(), act_token);
0620 }
0621 
0622 ///////////////////////////////////////////////////////////////////////////////
0623 template <typename ContextT>
0624 inline typename pp_iterator_functor<ContextT>::result_type const &
0625 pp_iterator_functor<ContextT>::get_next_token()
0626 {
0627     using namespace boost::wave;
0628 
0629     // if there is something in the unput_queue, then return the next token from
0630     // there (all tokens in the queue are preprocessed already)
0631     if (!pending_queue.empty() || !unput_queue.empty())
0632         return pp_token();      // return next token
0633 
0634     // test for EOF, if there is a pending input context, pop it back and continue
0635     // parsing with it
0636     bool returned_from_include_file = returned_from_include();
0637 
0638     // try to generate the next token
0639     if (iter_ctx->first != iter_ctx->last) {
0640         do {
0641             // If there are pending tokens in the queue, we'll have to return
0642             // these. This may happen from a #pragma directive, which got replaced
0643             // by some token sequence.
0644             if (!pending_queue.empty()) {
0645                 util::on_exit::pop_front<token_sequence_type>
0646                     pop_front_token(pending_queue);
0647 
0648                 return act_token = pending_queue.front();
0649             }
0650 
0651             // adjust the current position (line and column)
0652             bool was_seen_newline = seen_newline || returned_from_include_file;
0653 
0654             // fetch the current token
0655             act_token = *iter_ctx->first;
0656             act_pos = act_token.get_position();
0657 
0658             // act accordingly on the current token
0659             token_id id = token_id(act_token);
0660 
0661             if (T_EOF == id) {
0662                 // returned from an include file, continue with the next token
0663                 whitespace.shift_tokens(T_EOF);
0664                 ++iter_ctx->first;
0665 
0666                 // now make sure this line has a newline
0667                 if ((!seen_newline || act_pos.get_column() > 1) &&
0668                     !need_single_line(ctx.get_language()))
0669                 {
0670                     if (need_no_newline_at_end_of_file(ctx.get_language()))
0671                     {
0672                         seen_newline = true;
0673                         pending_queue.push_back(
0674                             result_type(T_NEWLINE, "\n", act_pos)
0675                         );
0676                     }
0677                     else
0678                     {
0679                         // warn, if this file does not end with a newline
0680                         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
0681                             last_line_not_terminated, "", act_pos);
0682                     }
0683                 }
0684                 continue;   // if this is the main file, the while loop breaks
0685             }
0686             else if (T_NEWLINE == id || T_CPPCOMMENT == id) {
0687                 // a newline is to be returned ASAP, a C++ comment too
0688                 // (the C++ comment token includes the trailing newline)
0689                 seen_newline = true;
0690                 ++iter_ctx->first;
0691 
0692                 if (!ctx.get_if_block_status()) {
0693                     // skip this token because of the disabled #if block
0694                     whitespace.shift_tokens(id);  // whitespace controller
0695                     util::impl::call_skipped_token_hook(ctx, act_token);
0696                     continue;
0697                 }
0698                 return act_token;
0699             }
0700             seen_newline = false;
0701 
0702             if (was_seen_newline && pp_directive()) {
0703                 // a pp directive was found
0704 //                 pending_queue.push_back(result_type(T_NEWLINE, "\n", act_pos));
0705 //                 seen_newline = true;
0706 //                 must_emit_line_directive = true;
0707                 if (iter_ctx->first == iter_ctx->last)
0708                 {
0709                     seen_newline = true;
0710                     act_token = result_type(T_NEWLINE, "\n", act_pos);
0711                 }
0712 
0713                 // loop to the next token to analyze
0714                 // simply fall through, since the iterator was already adjusted
0715                 // correctly
0716             }
0717             else if (ctx.get_if_block_status()) {
0718                 // preprocess this token, eat up more, if appropriate, return
0719                 // the next preprocessed token
0720                 return pp_token();
0721             }
0722             else {
0723                 // compilation condition is false: if the current token is a
0724                 // newline, account for it, otherwise discard the actual token and
0725                 // try the next one
0726                 if (T_NEWLINE == token_id(act_token)) {
0727                     seen_newline = true;
0728                     must_emit_line_directive = true;
0729                 }
0730 
0731                 // next token
0732                 util::impl::call_skipped_token_hook(ctx, act_token);
0733                 ++iter_ctx->first;
0734             }
0735 
0736         } while ((iter_ctx->first != iter_ctx->last) ||
0737                  (returned_from_include_file = returned_from_include()));
0738 
0739         // overall eof reached
0740         if (ctx.get_if_block_depth() > 0 && !need_single_line(ctx.get_language()))
0741         {
0742             // missing endif directive(s)
0743             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
0744                 missing_matching_endif, "", act_pos);
0745         }
0746     }
0747     else {
0748         act_token = eof;            // this is the last token
0749     }
0750 
0751 //  whitespace.shift_tokens(T_EOF);     // whitespace controller
0752     return act_token;                   // return eof token
0753 }
0754 
0755 ///////////////////////////////////////////////////////////////////////////////
0756 //
0757 //  emit_line_directive(): emits a line directive from the act_token data
0758 //
0759 ///////////////////////////////////////////////////////////////////////////////
0760 template <typename ContextT>
0761 inline bool
0762 pp_iterator_functor<ContextT>::emit_line_directive()
0763 {
0764     using namespace boost::wave;
0765 
0766     typename ContextT::position_type pos = act_token.get_position();
0767 
0768 //     if (must_emit_line_directive &&
0769 //         iter_ctx->emitted_lines+1 == act_pos.get_line() &&
0770 //         iter_ctx->filename == act_pos.get_file())
0771 //     {
0772 //         must_emit_line_directive = false;
0773 //         return false;
0774 //     }
0775 
0776     if (must_emit_line_directive ||
0777         iter_ctx->emitted_lines+1 != act_pos.get_line())
0778     {
0779         // unput the current token
0780         pending_queue.push_front(act_token);
0781         pos.set_line(act_pos.get_line());
0782 
0783         if (iter_ctx->emitted_lines+2 == act_pos.get_line() && act_pos.get_line() != 1) {
0784             // prefer to output a single newline instead of the #line directive
0785 //             whitespace.shift_tokens(T_NEWLINE);
0786             act_token = result_type(T_NEWLINE, "\n", pos);
0787         }
0788         else {
0789             // account for the newline emitted here
0790             act_pos.set_line(act_pos.get_line()-1);
0791             iter_ctx->emitted_lines = act_pos.get_line()-1;
0792 
0793             token_sequence_type pending;
0794 
0795             if (!ctx.get_hooks().emit_line_directive(ctx, pending, act_token))
0796             {
0797                 unsigned int column = 6;
0798 
0799                 // the hook did not generate anything, emit default #line
0800                 pos.set_column(1);
0801                 pending.push_back(result_type(T_PP_LINE, "#line", pos));
0802 
0803                 pos.set_column(column);      // account for '#line'
0804                 pending.push_back(result_type(T_SPACE, " ", pos));
0805 
0806                 // 21 is the max required size for a 64 bit integer represented as a
0807                 // string
0808 
0809                 std::string buffer = lexical_cast<std::string>(pos.get_line());
0810 
0811                 pos.set_column(++column);                 // account for ' '
0812                 pending.push_back(result_type(T_INTLIT, buffer.c_str(), pos));
0813                 pos.set_column(column += (unsigned int)buffer.size()); // account for <number>
0814                 pending.push_back(result_type(T_SPACE, " ", pos));
0815                 pos.set_column(++column);                 // account for ' '
0816 
0817                 std::string file("\"");
0818                 boost::filesystem::path filename(
0819                     wave::util::create_path(act_pos.get_file().c_str()));
0820 
0821                 using wave::util::impl::escape_lit;
0822                 file += escape_lit(wave::util::native_file_string(filename)) + "\"";
0823 
0824                 pending.push_back(result_type(T_STRINGLIT, file.c_str(), pos));
0825                 pos.set_column(column += (unsigned int)file.size());    // account for filename
0826                 pending.push_back(result_type(T_GENERATEDNEWLINE, "\n", pos));
0827             }
0828 
0829             // if there is some replacement text, insert it into the pending queue
0830             if (!pending.empty()) {
0831                 pending_queue.splice(pending_queue.begin(), pending);
0832                 act_token = pending_queue.front();
0833                 pending_queue.pop_front();
0834             }
0835         }
0836 
0837         must_emit_line_directive = false;     // we are now in sync
0838         return true;
0839     }
0840 
0841     must_emit_line_directive = false;         // we are now in sync
0842     return false;
0843 }
0844 
0845 ///////////////////////////////////////////////////////////////////////////////
0846 //
0847 //  pptoken(): return the next preprocessed token
0848 //
0849 ///////////////////////////////////////////////////////////////////////////////
0850 template <typename ContextT>
0851 inline typename pp_iterator_functor<ContextT>::result_type const &
0852 pp_iterator_functor<ContextT>::pp_token()
0853 {
0854     using namespace boost::wave;
0855 
0856     token_id id = token_id(*iter_ctx->first);
0857 
0858     // eat all T_PLACEHOLDER tokens, eventually slipped through out of the
0859     // macro engine
0860     do {
0861         if (!pending_queue.empty()) {
0862             // if there are pending tokens in the queue, return the first one
0863             act_token = pending_queue.front();
0864             pending_queue.pop_front();
0865             act_pos = act_token.get_position();
0866         }
0867         else if (!unput_queue.empty()
0868               || T_IDENTIFIER == id
0869               || IS_CATEGORY(id, KeywordTokenType)
0870               || IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType)
0871               || IS_CATEGORY(id, BoolLiteralTokenType))
0872         {
0873             //  call the lexer, preprocess the required number of tokens, put them
0874             //  into the unput queue
0875             act_token = ctx.expand_tokensequence(iter_ctx->first,
0876                 iter_ctx->last, pending_queue, unput_queue, skipped_newline);
0877         }
0878         else {
0879             // simply return the next token
0880             act_token = *iter_ctx->first;
0881             ++iter_ctx->first;
0882         }
0883         id = token_id(act_token);
0884 
0885     } while (T_PLACEHOLDER == id);
0886     return act_token;
0887 }
0888 
0889 ///////////////////////////////////////////////////////////////////////////////
0890 //
0891 //  pp_directive(): recognize a preprocessor directive
0892 //
0893 ///////////////////////////////////////////////////////////////////////////////
0894 namespace impl {
0895 
0896     // call 'found_directive' preprocessing hook
0897     template <typename ContextT>
0898     bool call_found_directive_hook(ContextT& ctx,
0899         typename ContextT::token_type const& found_directive)
0900     {
0901         if (ctx.get_hooks().found_directive(ctx.derived(), found_directive))
0902             return true;    // skip this directive and return newline only
0903         return false;
0904     }
0905 
0906 //     // call 'skipped_token' preprocessing hook
0907 //     template <typename ContextT>
0908 //     void call_skipped_token_hook(ContextT& ctx,
0909 //         typename ContextT::token_type const& skipped)
0910 //     {
0911 //         ctx.get_hooks().skipped_token(ctx.derived(), skipped);
0912 //     }
0913 
0914     template <typename ContextT, typename IteratorT>
0915     bool next_token_is_pp_directive(ContextT &ctx, IteratorT &it, IteratorT const &end)
0916     {
0917         using namespace boost::wave;
0918 
0919         token_id id = T_UNKNOWN;
0920         for (/**/; it != end; ++it) {
0921             id = token_id(*it);
0922             if (!IS_CATEGORY(id, WhiteSpaceTokenType))
0923                 break;          // skip leading whitespace
0924             if (IS_CATEGORY(id, EOLTokenType) || IS_CATEGORY(id, EOFTokenType))
0925                 break;          // do not enter a new line
0926             if (T_CPPCOMMENT == id ||
0927                 context_policies::util::ccomment_has_newline(*it))
0928             {
0929                 break;
0930             }
0931 
0932             // this token gets skipped
0933             util::impl::call_skipped_token_hook(ctx, *it);
0934         }
0935         BOOST_ASSERT(it == end || id != T_UNKNOWN);
0936         return it != end && IS_CATEGORY(id, PPTokenType);
0937     }
0938 
0939     // verify that there isn't anything significant left on the line
0940     template <typename ContextT, typename IteratorT>
0941     bool pp_is_last_on_line(ContextT &ctx, IteratorT &it, IteratorT const &end,
0942         bool call_hook = true)
0943     {
0944         using namespace boost::wave;
0945 
0946         // this token gets skipped
0947         if (call_hook)
0948             util::impl::call_skipped_token_hook(ctx, *it);
0949 
0950         for (++it; it != end; ++it) {
0951             token_id id = token_id(*it);
0952 
0953             if (T_CPPCOMMENT == id || T_NEWLINE == id ||
0954                 context_policies::util::ccomment_has_newline(*it))
0955             {
0956                 if (call_hook)
0957                     util::impl::call_skipped_token_hook(ctx, *it);
0958                 ++it;           // skip eol/C/C++ comment
0959                 return true;    // no more significant tokens on this line
0960             }
0961 
0962             if (!IS_CATEGORY(id, WhiteSpaceTokenType))
0963                 break;
0964 
0965             // this token gets skipped
0966             if (call_hook)
0967                 util::impl::call_skipped_token_hook(ctx, *it);
0968         }
0969         return need_no_newline_at_end_of_file(ctx.get_language()) &&
0970             ((it == end) || (T_EOF == token_id(*it)));
0971     }
0972 
0973     ///////////////////////////////////////////////////////////////////////////
0974     template <typename ContextT, typename IteratorT>
0975     bool skip_to_eol(ContextT &ctx, IteratorT &it, IteratorT const &end,
0976         bool call_hook = true)
0977     {
0978         using namespace boost::wave;
0979 
0980         for (/**/; it != end; ++it) {
0981         token_id id = token_id(*it);
0982 
0983             if (T_CPPCOMMENT == id || T_NEWLINE == id ||
0984                 context_policies::util::ccomment_has_newline(*it))
0985             {
0986                 // always call hook for eol
0987                 util::impl::call_skipped_token_hook(ctx, *it);
0988                 ++it;           // skip eol/C/C++ comment
0989                 return true;    // found eol
0990             }
0991 
0992             if (call_hook)
0993                 util::impl::call_skipped_token_hook(ctx, *it);
0994         }
0995         return false;
0996     }
0997 
0998     ///////////////////////////////////////////////////////////////////////////
0999     template <typename ContextT, typename ContainerT>
1000     inline void
1001     remove_leading_whitespace(ContextT &ctx, ContainerT& c, bool call_hook = true)
1002     {
1003         typename ContainerT::iterator it = c.begin();
1004         while (IS_CATEGORY(*it, WhiteSpaceTokenType)) {
1005             typename ContainerT::iterator save = it++;
1006             if (call_hook)
1007                 util::impl::call_skipped_token_hook(ctx, *save);
1008             c.erase(save);
1009         }
1010     }
1011 }
1012 
1013 ///////////////////////////////////////////////////////////////////////////////
1014 template <typename ContextT>
1015 template <typename IteratorT>
1016 inline bool
1017 pp_iterator_functor<ContextT>::extract_identifier(IteratorT &it)
1018 {
1019     token_id id = util::impl::skip_whitespace(it, iter_ctx->last);
1020     if (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType) ||
1021         IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
1022         IS_CATEGORY(id, BoolLiteralTokenType))
1023     {
1024         IteratorT save = it;
1025         if (impl::pp_is_last_on_line(ctx, save, iter_ctx->last, false))
1026             return true;
1027     }
1028 
1029     // report the ill formed directive
1030     impl::skip_to_eol(ctx, it, iter_ctx->last);
1031 
1032     string_type str(util::impl::as_string<string_type>(iter_ctx->first, it));
1033 
1034     seen_newline = true;
1035     iter_ctx->first = it;
1036     on_illformed(str);
1037     return false;
1038 }
1039 
1040 ///////////////////////////////////////////////////////////////////////////////
1041 template <typename ContextT>
1042 template <typename IteratorT>
1043 inline bool
1044 pp_iterator_functor<ContextT>::ensure_is_last_on_line(IteratorT& it, bool call_hook)
1045 {
1046     if (!impl::pp_is_last_on_line(ctx, it, iter_ctx->last, call_hook))
1047     {
1048         // enable error recovery (start over with the next line)
1049         impl::skip_to_eol(ctx, it, iter_ctx->last);
1050 
1051         string_type str(util::impl::as_string<string_type>(iter_ctx->first, it));
1052 
1053         seen_newline = true;
1054         iter_ctx->first = it;
1055 
1056         // report an invalid directive
1057         on_illformed(str);
1058         return false;
1059     }
1060 
1061     if (it == iter_ctx->last && !need_single_line(ctx.get_language()))
1062     {
1063         // The line doesn't end with an eol but eof token.
1064         seen_newline = true;    // allow to resume after warning
1065         iter_ctx->first = it;
1066 
1067         if (!need_no_newline_at_end_of_file(ctx.get_language()))
1068         {
1069             // Trigger a warning that the last line was not terminated with a
1070             // newline.
1071             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1072                 last_line_not_terminated, "", act_pos);
1073         }
1074 
1075         return false;
1076     }
1077     return true;
1078 }
1079 
1080 template <typename ContextT>
1081 template <typename IteratorT>
1082 inline bool
1083 pp_iterator_functor<ContextT>::skip_to_eol_with_check(IteratorT &it, bool call_hook)
1084 {
1085     typename ContextT::string_type value ((*it).get_value());
1086     if (!impl::skip_to_eol(ctx, it, iter_ctx->last, call_hook) &&
1087         !need_single_line(ctx.get_language()))
1088     {
1089         // The line doesn't end with an eol but eof token.
1090         seen_newline = true;    // allow to resume after warning
1091         iter_ctx->first = it;
1092 
1093         if (!need_no_newline_at_end_of_file(ctx.get_language()))
1094         {
1095             // Trigger a warning, that the last line was not terminated with a
1096             // newline.
1097             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1098                 last_line_not_terminated, "", act_pos);
1099         }
1100         return false;
1101     }
1102 
1103     // normal line ending reached, adjust iterator and flag
1104     seen_newline = true;
1105     iter_ctx->first = it;
1106     return true;
1107 }
1108 
1109 ///////////////////////////////////////////////////////////////////////////////
1110 //  handle_pp_directive: handle certain pp_directives
1111 template <typename ContextT>
1112 template <typename IteratorT>
1113 inline bool
1114 pp_iterator_functor<ContextT>::handle_pp_directive(IteratorT &it)
1115 {
1116     token_id id = token_id(*it);
1117     bool can_exit = true;
1118     bool call_hook_in_skip = true;
1119     if (!ctx.get_if_block_status()) {
1120         if (IS_EXTCATEGORY(*it, PPConditionalTokenType)) {
1121             // simulate the if block hierarchy
1122             switch (id) {
1123             case T_PP_IFDEF:        // #ifdef
1124             case T_PP_IFNDEF:       // #ifndef
1125             case T_PP_IF:           // #if
1126                 ctx.enter_if_block(false);
1127                 break;
1128 
1129             case T_PP_ELIF:         // #elif
1130                 if (!ctx.get_enclosing_if_block_status()) {
1131                     if (!ctx.enter_elif_block(false)) {
1132                         // #else without matching #if
1133                         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1134                             missing_matching_if, "#elif", act_pos);
1135                         return true;  // do not analyze this directive any further
1136                     }
1137                 }
1138                 else {
1139                     can_exit = false;   // #elif is not always safe to skip
1140                 }
1141                 break;
1142 
1143             case T_PP_ELSE:         // #else
1144             case T_PP_ENDIF:        // #endif
1145                 {
1146                 // handle this directive
1147                     if (T_PP_ELSE == token_id(*it))
1148                         on_else();
1149                     else
1150                         on_endif();
1151 
1152                 // make sure, there are no (non-whitespace) tokens left on
1153                 // this line
1154                     ensure_is_last_on_line(it);
1155 
1156                 // we skipped to the end of this line already
1157                     seen_newline = true;
1158                     iter_ctx->first = it;
1159                 }
1160                 if (T_PP_ENDIF == id)
1161                     must_emit_line_directive = true;
1162                 return true;
1163 
1164             default:                // #something else
1165                 on_illformed((*it).get_value());
1166                 break;
1167             }
1168         }
1169         else {
1170             util::impl::call_skipped_token_hook(ctx, *it);
1171             ++it;
1172         }
1173     }
1174     else {
1175         // try to handle the simple pp directives without parsing
1176         result_type directive = *it;
1177         bool include_next = false;
1178         switch (id) {
1179         case T_PP_QHEADER:        // #include "..."
1180 #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
1181         case T_PP_QHEADER_NEXT:
1182 #endif
1183             include_next = (T_PP_QHEADER_NEXT == id) ? true : false;
1184             if (!impl::call_found_directive_hook(ctx, *it))
1185             {
1186                 string_type dir((*it).get_value());
1187 
1188                 // make sure, there are no (non-whitespace) tokens left on
1189                 // this line
1190                 if (ensure_is_last_on_line(it))
1191                 {
1192                     seen_newline = true;
1193                     iter_ctx->first = it;
1194                     on_include (dir, false, include_next);
1195                 }
1196                 return true;
1197             }
1198             break;
1199 
1200         case T_PP_HHEADER:        // #include <...>
1201 #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
1202         case T_PP_HHEADER_NEXT:
1203 #endif
1204             include_next = (T_PP_HHEADER_NEXT == id) ? true : false;
1205             if (!impl::call_found_directive_hook(ctx, *it))
1206             {
1207                 string_type dir((*it).get_value());
1208 
1209                 // make sure, there are no (non-whitespace) tokens left on
1210                 // this line
1211                 if (ensure_is_last_on_line(it))
1212                 {
1213                     seen_newline = true;
1214                     iter_ctx->first = it;
1215                     on_include (dir, true, include_next);
1216                 }
1217                 return true;
1218             }
1219             break;
1220 
1221         case T_PP_ELSE:         // #else
1222         case T_PP_ENDIF:        // #endif
1223             if (!impl::call_found_directive_hook(ctx, *it))
1224             {
1225                 // handle this directive
1226                 if (T_PP_ELSE == token_id(*it))
1227                     on_else();
1228                 else
1229                     on_endif();
1230 
1231                 // make sure, there are no (non-whitespace) tokens left on
1232                 // this line
1233                 ensure_is_last_on_line(it);
1234 
1235                 // we skipped to the end of this line already
1236                 seen_newline = true;
1237                 iter_ctx->first = it;
1238                 if (T_PP_ENDIF == id)
1239                     must_emit_line_directive = true;
1240                 return true;
1241             }
1242             break;
1243 
1244             // extract everything on this line as arguments
1245 //         case T_PP_IF:                   // #if
1246 //         case T_PP_ELIF:                 // #elif
1247 //         case T_PP_ERROR:                // #error
1248 //         case T_PP_WARNING:              // #warning
1249 //         case T_PP_PRAGMA:               // #pragma
1250 //         case T_PP_LINE:                 // #line
1251 //             break;
1252 
1253         // extract first non-whitespace token as argument
1254         case T_PP_UNDEF:                // #undef
1255             if (!impl::call_found_directive_hook(ctx, *it) &&
1256                 extract_identifier(it))
1257             {
1258                 on_undefine(it);
1259             }
1260             call_hook_in_skip = false;
1261             break;
1262 
1263 #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
1264 //         case T_MSEXT_PP_REGION:         // #region ...
1265 //             break;
1266 //
1267 //         case T_MSEXT_PP_ENDREGION:      // #endregion
1268 //             break;
1269 #endif
1270 
1271         default:
1272             can_exit = false;
1273             break;
1274         }
1275     }
1276 
1277     // start over with the next line, if only possible
1278     if (can_exit) {
1279         skip_to_eol_with_check(it, call_hook_in_skip);
1280         return true;    // may be safely ignored
1281     }
1282     return false;   // do not ignore this pp directive
1283 }
1284 
1285 ///////////////////////////////////////////////////////////////////////////////
1286 //  pp_directive(): recognize a preprocessor directive
1287 template <typename ContextT>
1288 inline bool
1289 pp_iterator_functor<ContextT>::pp_directive()
1290 {
1291     using namespace cpplexer;
1292 
1293     // test, if the next non-whitespace token is a pp directive
1294     lexer_type it = iter_ctx->first;
1295 
1296     if (!impl::next_token_is_pp_directive(ctx, it, iter_ctx->last)) {
1297         // skip null pp directive (no need to do it via the parser)
1298         if (it != iter_ctx->last && T_POUND == BASE_TOKEN(token_id(*it))) {
1299             if (impl::pp_is_last_on_line(ctx, it, iter_ctx->last)) {
1300                 // start over with the next line
1301                 seen_newline = true;
1302                 iter_ctx->first = it;
1303                 return true;
1304             }
1305             else if (ctx.get_if_block_status()) {
1306                 // report invalid pp directive
1307                 impl::skip_to_eol(ctx, it, iter_ctx->last);
1308                 seen_newline = true;
1309 
1310                 string_type str(boost::wave::util::impl::as_string<string_type>(
1311                     iter_ctx->first, it));
1312 
1313                 token_sequence_type faulty_line;
1314 
1315                 for (/**/; iter_ctx->first != it; ++iter_ctx->first)
1316                     faulty_line.push_back(*iter_ctx->first);
1317 
1318                 token_sequence_type pending;
1319                 if (ctx.get_hooks().found_unknown_directive(ctx, faulty_line, pending))
1320                 {
1321                     // if there is some replacement text, insert it into the pending queue
1322                     if (!pending.empty())
1323                         pending_queue.splice(pending_queue.begin(), pending);
1324                     return true;
1325                 }
1326 
1327                 // default behavior is to throw an exception
1328                 on_illformed(str);
1329             }
1330         }
1331 
1332         // this line does not contain a pp directive, so simply return
1333         return false;
1334     }
1335 
1336     // found eof
1337     if (it == iter_ctx->last)
1338         return false;
1339 
1340     // ignore/handle all pp directives not related to conditional compilation while
1341     // if block status is false
1342     if (handle_pp_directive(it)) {
1343         // we may skip pp directives only if the current if block status is
1344         // false or if it was a #include directive we could handle directly
1345         return true;    //  the pp directive has been handled/skipped
1346     }
1347 
1348     // found a pp directive, so try to identify it, start with the pp_token
1349     bool found_eof = false;
1350     result_type found_directive;
1351     token_sequence_type found_eoltokens;
1352 
1353     tree_parse_info_type hit = cpp_grammar_type::parse_cpp_grammar(
1354         it, iter_ctx->last, act_pos, found_eof, found_directive, found_eoltokens);
1355 
1356     if (hit.match) {
1357         // position the iterator past the matched sequence to allow
1358         // resynchronization, if an error occurs
1359         iter_ctx->first = hit.stop;
1360         seen_newline = true;
1361         must_emit_line_directive = true;
1362 
1363         // found a valid pp directive, dispatch to the correct function to handle
1364         // the found pp directive
1365         bool result = dispatch_directive(hit, found_directive, found_eoltokens);
1366 
1367         if (found_eof && !need_single_line(ctx.get_language()) &&
1368             !need_no_newline_at_end_of_file(ctx.get_language()))
1369         {
1370             // The line was terminated with an end of file token.
1371             // So trigger a warning, that the last line was not terminated with a
1372             // newline.
1373             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1374                 last_line_not_terminated, "", act_pos);
1375         }
1376         return result;
1377     }
1378     else if (token_id(found_directive) != T_EOF) {
1379         // recognized invalid directive
1380         impl::skip_to_eol(ctx, it, iter_ctx->last);
1381         seen_newline = true;
1382 
1383         string_type str(boost::wave::util::impl::as_string<string_type>(
1384             iter_ctx->first, it));
1385         iter_ctx->first = it;
1386 
1387         // report the ill formed directive
1388         on_illformed(str);
1389     }
1390     return false;
1391 }
1392 
1393 ///////////////////////////////////////////////////////////////////////////////
1394 //
1395 //  dispatch_directive(): dispatch a recognized preprocessor directive
1396 //
1397 ///////////////////////////////////////////////////////////////////////////////
1398 template <typename ContextT>
1399 inline bool
1400 pp_iterator_functor<ContextT>::dispatch_directive(
1401     tree_parse_info_type const &hit, result_type const& found_directive,
1402     token_sequence_type const& found_eoltokens)
1403 {
1404     using namespace cpplexer;
1405 
1406     typedef typename parse_tree_type::const_iterator const_child_iterator_t;
1407 
1408     // this iterator points to the root node of the parse tree
1409     const_child_iterator_t begin = hit.trees.begin();
1410 
1411     // decide, which preprocessor directive was found
1412     parse_tree_type const& root = (*begin).children;
1413     parse_node_value_type const& nodeval = get_first_leaf(*root.begin()).value;
1414     //long node_id = nodeval.id().to_long();
1415 
1416     const_child_iterator_t begin_child_it = (*root.begin()).children.begin();
1417     const_child_iterator_t end_child_it = (*root.begin()).children.end();
1418 
1419     token_id id = token_id(found_directive);
1420 
1421     // call preprocessing hook
1422     if (impl::call_found_directive_hook(ctx, found_directive))
1423         return true;    // skip this directive and return newline only
1424 
1425     switch (id) {
1426 //     case T_PP_QHEADER:      // #include "..."
1427 // #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
1428 //     case T_PP_QHEADER_NEXT: // #include_next "..."
1429 // #endif
1430 //         on_include ((*nodeval.begin()).get_value(), false,
1431 //             T_PP_QHEADER_NEXT == id);
1432 //         break;
1433 
1434 //     case T_PP_HHEADER:      // #include <...>
1435 // #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
1436 //     case T_PP_HHEADER_NEXT: // #include_next <...>
1437 // #endif
1438 //         on_include ((*nodeval.begin()).get_value(), true,
1439 //             T_PP_HHEADER_NEXT == id);
1440 //         break;
1441 
1442     case T_PP_INCLUDE:      // #include ...
1443 #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
1444     case T_PP_INCLUDE_NEXT: // #include_next ...
1445 #endif
1446         on_include (begin_child_it, end_child_it, T_PP_INCLUDE_NEXT == id);
1447         break;
1448 
1449     case T_PP_DEFINE:       // #define
1450         on_define (*begin);
1451         break;
1452 
1453 //     case T_PP_UNDEF:        // #undef
1454 //         on_undefine(*nodeval.begin());
1455 //         break;
1456 //
1457     case T_PP_IFDEF:        // #ifdef
1458         on_ifdef(found_directive, begin_child_it, end_child_it);
1459         break;
1460 
1461     case T_PP_IFNDEF:       // #ifndef
1462         on_ifndef(found_directive, begin_child_it, end_child_it);
1463         break;
1464 
1465     case T_PP_IF:           // #if
1466         on_if(found_directive, begin_child_it, end_child_it);
1467         break;
1468 
1469     case T_PP_ELIF:         // #elif
1470         on_elif(found_directive, begin_child_it, end_child_it);
1471         break;
1472 
1473 //     case T_PP_ELSE:         // #else
1474 //         on_else();
1475 //         break;
1476 
1477 //     case T_PP_ENDIF:        // #endif
1478 //         on_endif();
1479 //         break;
1480 
1481     case T_PP_LINE:         // #line
1482         on_line(begin_child_it, end_child_it);
1483         break;
1484 
1485     case T_PP_ERROR:        // #error
1486         on_error(begin_child_it, end_child_it);
1487         break;
1488 
1489 #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
1490     case T_PP_WARNING:      // #warning
1491         on_warning(begin_child_it, end_child_it);
1492         break;
1493 #endif
1494 
1495     case T_PP_PRAGMA:       // #pragma
1496         return on_pragma(begin_child_it, end_child_it);
1497 
1498 #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
1499     case T_MSEXT_PP_REGION:
1500     case T_MSEXT_PP_ENDREGION:
1501         break;              // ignore these
1502 #endif
1503 
1504     default:                // #something else
1505         on_illformed((*nodeval.begin()).get_value());
1506 
1507         // if we end up here, we have been instructed to ignore the error, so
1508         // we simply copy the whole construct to the output
1509         {
1510             token_sequence_type expanded;
1511             get_token_value<result_type, parse_node_type> get_value;
1512 
1513             std::copy(make_ref_transform_iterator(begin_child_it, get_value),
1514                 make_ref_transform_iterator(end_child_it, get_value),
1515                 std::inserter(expanded, expanded.end()));
1516             pending_queue.splice(pending_queue.begin(), expanded);
1517         }
1518         break;
1519     }
1520 
1521     // properly skip trailing newline for all directives
1522     typename token_sequence_type::const_iterator eol = found_eoltokens.begin();
1523     impl::skip_to_eol(ctx, eol, found_eoltokens.end());
1524     return true;    // return newline only
1525 }
1526 
1527 ///////////////////////////////////////////////////////////////////////////////
1528 //
1529 //  on_include: handle #include <...> or #include "..." directives
1530 //
1531 ///////////////////////////////////////////////////////////////////////////////
1532 template <typename ContextT>
1533 inline void
1534 pp_iterator_functor<ContextT>::on_include (string_type const &s,
1535     bool is_system, bool include_next)
1536 {
1537     BOOST_ASSERT(ctx.get_if_block_status());
1538 
1539 // strip quotes first, extract filename
1540 typename string_type::size_type pos_end = s.find_last_of(is_system ? '>' : '\"');
1541 
1542     if (string_type::npos == pos_end) {
1543         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
1544             s.c_str(), act_pos);
1545         return;
1546     }
1547 
1548 typename string_type::size_type pos_begin =
1549     s.find_last_of(is_system ? '<' : '\"', pos_end-1);
1550 
1551     if (string_type::npos == pos_begin) {
1552         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
1553             s.c_str(), act_pos);
1554         return;
1555     }
1556 
1557     std::string file_token(s.substr(pos_begin, pos_end - pos_begin + 1).c_str());
1558     std::string file_path(s.substr(pos_begin + 1, pos_end - pos_begin - 1).c_str());
1559 
1560     // finally include the file
1561     on_include_helper(file_token.c_str(), file_path.c_str(), is_system,
1562         include_next);
1563 }
1564 
1565 template <typename ContextT>
1566 inline bool
1567 pp_iterator_functor<ContextT>::on_include_helper(char const* f, char const* s,
1568     bool is_system, bool include_next)
1569 {
1570     namespace fs = boost::filesystem;
1571 
1572     // try to locate the given file, searching through the include path lists
1573     std::string file_path(s);
1574     std::string dir_path;
1575 #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
1576     char const* current_name = include_next ? iter_ctx->real_filename.c_str() : 0;
1577 #else
1578     char const* current_name = 0; // never try to match current file name
1579 #endif
1580 
1581 // call the 'found_include_directive' hook function
1582     if (ctx.get_hooks().found_include_directive(ctx.derived(), f, include_next))
1583         return true;    // client returned false: skip file to include
1584 
1585     file_path = util::impl::unescape_lit(file_path);
1586     std::string native_path_str;
1587 
1588     if (!ctx.get_hooks().locate_include_file(ctx, file_path, is_system,
1589             current_name, dir_path, native_path_str))
1590     {
1591         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_file,
1592             file_path.c_str(), act_pos);
1593         return false;
1594     }
1595 
1596 // test, if this file is known through a #pragma once directive
1597 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
1598     if (!ctx.has_pragma_once(native_path_str))
1599 #endif
1600     {
1601         // the new include file determines the actual current directory
1602         ctx.set_current_directory(native_path_str.c_str());
1603 
1604         // preprocess the opened file
1605         boost::shared_ptr<base_iteration_context_type> new_iter_ctx(
1606             new iteration_context_type(ctx, native_path_str.c_str(), act_pos,
1607                 boost::wave::enable_prefer_pp_numbers(ctx.get_language()),
1608                 is_system ? base_iteration_context_type::system_header :
1609                             base_iteration_context_type::user_header));
1610 
1611         // call the include policy trace function
1612         ctx.get_hooks().opened_include_file(ctx.derived(), dir_path, file_path,
1613             is_system);
1614 
1615         // store current file position
1616         iter_ctx->real_relative_filename = ctx.get_current_relative_filename().c_str();
1617         iter_ctx->filename = act_pos.get_file();
1618         iter_ctx->line = act_pos.get_line();
1619         iter_ctx->if_block_depth = ctx.get_if_block_depth();
1620         iter_ctx->emitted_lines = (unsigned int)(-1);   // force #line directive
1621 
1622         // push the old iteration context onto the stack and continue with the new
1623         ctx.push_iteration_context(act_pos, iter_ctx);
1624         iter_ctx = new_iter_ctx;
1625         seen_newline = true;        // fake a newline to trigger pp_directive
1626         must_emit_line_directive = true;
1627 
1628         act_pos.set_file(iter_ctx->filename);  // initialize file position
1629 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
1630         fs::path rfp(wave::util::create_path(iter_ctx->real_filename.c_str()));
1631         std::string real_filename(rfp.string());
1632         ctx.set_current_filename(real_filename.c_str());
1633 #endif
1634 
1635         ctx.set_current_relative_filename(dir_path.c_str());
1636         iter_ctx->real_relative_filename = dir_path.c_str();
1637 
1638         act_pos.set_line(iter_ctx->line);
1639         act_pos.set_column(0);
1640     }
1641     return true;
1642 }
1643 
1644 ///////////////////////////////////////////////////////////////////////////////
1645 //
1646 //  on_include(): handle #include ... directives
1647 //
1648 ///////////////////////////////////////////////////////////////////////////////
1649 
1650 template <typename ContextT>
1651 inline void
1652 pp_iterator_functor<ContextT>::on_include(
1653     typename parse_tree_type::const_iterator const &begin,
1654     typename parse_tree_type::const_iterator const &end, bool include_next)
1655 {
1656     BOOST_ASSERT(ctx.get_if_block_status());
1657 
1658     // preprocess the given token sequence (the body of the #include directive)
1659     get_token_value<result_type, parse_node_type> get_value;
1660     token_sequence_type expanded;
1661     token_sequence_type toexpand;
1662 
1663     std::copy(make_ref_transform_iterator(begin, get_value),
1664         make_ref_transform_iterator(end, get_value),
1665         std::inserter(toexpand, toexpand.end()));
1666 
1667     typename token_sequence_type::iterator begin2 = toexpand.begin();
1668     // expanding the computed include
1669     ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
1670                                    false, false);
1671 
1672     // now, include the file
1673     using namespace boost::wave::util::impl;
1674     string_type s (trim_whitespace(as_string(expanded)));
1675     bool is_system = '<' == s[0] && '>' == s[s.size()-1];
1676 
1677     if (!is_system && !('\"' == s[0] && '\"' == s[s.size()-1])) {
1678     // should resolve into something like <...> or "..."
1679         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
1680             s.c_str(), act_pos);
1681         return;
1682     }
1683     on_include(s, is_system, include_next);
1684 }
1685 
1686 ///////////////////////////////////////////////////////////////////////////////
1687 //
1688 //  on_define(): handle #define directives
1689 //
1690 ///////////////////////////////////////////////////////////////////////////////
1691 
1692 template <typename ContextT>
1693 inline void
1694 pp_iterator_functor<ContextT>::on_define (parse_node_type const &node)
1695 {
1696     BOOST_ASSERT(ctx.get_if_block_status());
1697 
1698     // retrieve the macro definition from the parse tree
1699     result_type macroname;
1700     std::vector<result_type> macroparameters;
1701     token_sequence_type macrodefinition;
1702     bool has_parameters = false;
1703     position_type pos(act_token.get_position());
1704 
1705     if (!boost::wave::util::retrieve_macroname(ctx, node,
1706             BOOST_WAVE_PLAIN_DEFINE_ID, macroname, pos, false))
1707         return;
1708     has_parameters = boost::wave::util::retrieve_macrodefinition(node,
1709         BOOST_WAVE_MACRO_PARAMETERS_ID, macroparameters, pos, false);
1710     boost::wave::util::retrieve_macrodefinition(node,
1711         BOOST_WAVE_MACRO_DEFINITION_ID, macrodefinition, pos, false);
1712 
1713     if (has_parameters) {
1714 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1715         if (boost::wave::need_variadics(ctx.get_language())) {
1716             // test whether ellipsis are given, and if yes, if these are placed as the
1717             // last argument, test if __VA_ARGS__ is used as a macro parameter name
1718             using namespace cpplexer;
1719             typedef typename std::vector<result_type>::iterator
1720                 parameter_iterator_t;
1721 
1722             bool seen_ellipses = false;
1723             parameter_iterator_t end = macroparameters.end();
1724             for (parameter_iterator_t pit = macroparameters.begin();
1725                 pit != end; ++pit)
1726             {
1727                 if (seen_ellipses) {
1728                     // ellipses are not the last given formal argument
1729                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1730                         bad_define_statement, macroname.get_value().c_str(),
1731                         (*pit).get_position());
1732                     return;
1733                 }
1734                 if (T_ELLIPSIS == token_id(*pit))
1735                     seen_ellipses = true;
1736 
1737                 // can't use __VA_ARGS__ as a argument name
1738                 if ("__VA_ARGS__" == (*pit).get_value()) {
1739                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1740                         bad_define_statement_va_args,
1741                         macroname.get_value().c_str(), (*pit).get_position());
1742                     return;
1743                 }
1744 
1745 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1746                 // can't use __VA_OPT__ either
1747                 if (boost::wave::need_va_opt(ctx.get_language()) &&
1748                     ("__VA_OPT__" == (*pit).get_value())) {
1749                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1750                         bad_define_statement_va_opt,
1751                         macroname.get_value().c_str(), (*pit).get_position());
1752                     return;
1753                 }
1754 #endif
1755             }
1756 
1757             // if there wasn't an ellipsis, then there shouldn't be a __VA_ARGS__
1758             // placeholder in the definition too [C99 Standard 6.10.3.5]
1759             if (!seen_ellipses) {
1760                 typedef typename token_sequence_type::iterator definition_iterator_t;
1761 
1762                 bool seen_va_args = false;
1763 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1764                 bool seen_va_opt = false;
1765 #endif
1766                 definition_iterator_t pend = macrodefinition.end();
1767                 for (definition_iterator_t dit = macrodefinition.begin();
1768                      dit != pend; ++dit)
1769                 {
1770                     if (T_IDENTIFIER == token_id(*dit) &&
1771                         "__VA_ARGS__" == (*dit).get_value())
1772                     {
1773                         seen_va_args = true;
1774                     }
1775 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1776                     if (T_IDENTIFIER == token_id(*dit) &&
1777                         "__VA_OPT__" == (*dit).get_value())
1778                     {
1779                         seen_va_opt = true;
1780                     }
1781 #endif
1782                 }
1783                 if (seen_va_args) {
1784                     // must not have seen __VA_ARGS__ placeholder
1785                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1786                         bad_define_statement_va_args,
1787                         macroname.get_value().c_str(), act_token.get_position());
1788                     return;
1789                 }
1790 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1791                 if (seen_va_opt) {
1792                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1793                         bad_define_statement_va_opt,
1794                         macroname.get_value().c_str(), act_token.get_position());
1795                     return;
1796                 }
1797 #endif
1798             }
1799         }
1800         else
1801 #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1802         {
1803             // test, that there is no T_ELLIPSES given
1804             using namespace cpplexer;
1805             typedef typename std::vector<result_type>::iterator
1806                 parameter_iterator_t;
1807 
1808             parameter_iterator_t end = macroparameters.end();
1809             for (parameter_iterator_t pit = macroparameters.begin();
1810                 pit != end; ++pit)
1811             {
1812                 if (T_ELLIPSIS == token_id(*pit)) {
1813                     // if variadics are disabled, no ellipses should be given
1814                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1815                         bad_define_statement, macroname.get_value().c_str(),
1816                         (*pit).get_position());
1817                     return;
1818                 }
1819             }
1820         }
1821     }
1822 
1823     // add the new macro to the macromap
1824     ctx.add_macro_definition(macroname, has_parameters, macroparameters,
1825         macrodefinition);
1826 }
1827 
1828 ///////////////////////////////////////////////////////////////////////////////
1829 //
1830 //  on_undefine(): handle #undef directives
1831 //
1832 ///////////////////////////////////////////////////////////////////////////////
1833 template <typename ContextT>
1834 inline void
1835 pp_iterator_functor<ContextT>::on_undefine (lexer_type const &it)
1836 {
1837     BOOST_ASSERT(ctx.get_if_block_status());
1838 
1839     // retrieve the macro name to undefine from the parse tree
1840     ctx.remove_macro_definition((*it).get_value()); // throws for predefined macros
1841 }
1842 
1843 ///////////////////////////////////////////////////////////////////////////////
1844 //
1845 //  on_ifdef(): handle #ifdef directives
1846 //
1847 ///////////////////////////////////////////////////////////////////////////////
1848 template <typename ContextT>
1849 inline void
1850 pp_iterator_functor<ContextT>::on_ifdef(
1851     result_type const& found_directive,
1852     typename parse_tree_type::const_iterator const &begin,
1853     typename parse_tree_type::const_iterator const &end)
1854 {
1855     get_token_value<result_type, parse_node_type> get_value;
1856     token_sequence_type toexpand;
1857 
1858     std::copy(make_ref_transform_iterator((*begin).children.begin(), get_value),
1859               make_ref_transform_iterator((*begin).children.end(), get_value),
1860               std::inserter(toexpand, toexpand.end()));
1861 
1862     bool is_defined = false;
1863 
1864     do {
1865         is_defined = ctx.is_defined_macro(toexpand.begin(), toexpand.end());
1866     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
1867              found_directive, toexpand, is_defined));
1868     ctx.enter_if_block(is_defined);
1869 }
1870 
1871 ///////////////////////////////////////////////////////////////////////////////
1872 //
1873 //  on_ifndef(): handle #ifndef directives
1874 //
1875 ///////////////////////////////////////////////////////////////////////////////
1876 template <typename ContextT>
1877 inline void
1878 pp_iterator_functor<ContextT>::on_ifndef(
1879     result_type const& found_directive,
1880     typename parse_tree_type::const_iterator const &begin,
1881     typename parse_tree_type::const_iterator const &end)
1882 {
1883     get_token_value<result_type, parse_node_type> get_value;
1884     token_sequence_type toexpand;
1885 
1886     std::copy(make_ref_transform_iterator((*begin).children.begin(), get_value),
1887               make_ref_transform_iterator((*begin).children.end(), get_value),
1888               std::inserter(toexpand, toexpand.end()));
1889 
1890     bool is_defined = false;
1891 
1892     do {
1893         is_defined = ctx.is_defined_macro(toexpand.begin(), toexpand.end());
1894     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
1895              found_directive, toexpand, is_defined));
1896     ctx.enter_if_block(!is_defined);
1897 }
1898 
1899 ///////////////////////////////////////////////////////////////////////////////
1900 //
1901 //  on_else(): handle #else directives
1902 //
1903 ///////////////////////////////////////////////////////////////////////////////
1904 template <typename ContextT>
1905 inline void
1906 pp_iterator_functor<ContextT>::on_else()
1907 {
1908     if (!ctx.enter_else_block()) {
1909         // #else without matching #if
1910         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
1911             "#else", act_pos);
1912     }
1913 }
1914 
1915 ///////////////////////////////////////////////////////////////////////////////
1916 //
1917 //  on_endif(): handle #endif directives
1918 //
1919 ///////////////////////////////////////////////////////////////////////////////
1920 template <typename ContextT>
1921 inline void
1922 pp_iterator_functor<ContextT>::on_endif()
1923 {
1924     if (!ctx.exit_if_block()) {
1925         // #endif without matching #if
1926         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
1927             "#endif", act_pos);
1928     }
1929 }
1930 
1931 ///////////////////////////////////////////////////////////////////////////////
1932 //  replace all remaining (== undefined) identifiers with an integer literal '0'
1933 template <typename ContextT>
1934 inline void
1935 pp_iterator_functor<ContextT>::replace_undefined_identifiers(
1936     token_sequence_type &expanded)
1937 {
1938     typename token_sequence_type::iterator exp_end = expanded.end();
1939     for (typename token_sequence_type::iterator exp_it = expanded.begin();
1940          exp_it != exp_end; ++exp_it)
1941     {
1942         using namespace boost::wave;
1943 
1944         token_id id = token_id(*exp_it);
1945         if (IS_CATEGORY(id, IdentifierTokenType) ||
1946             IS_CATEGORY(id, KeywordTokenType))
1947         {
1948             (*exp_it).set_token_id(T_INTLIT);
1949             (*exp_it).set_value("0");
1950         }
1951     }
1952 }
1953 
1954 ///////////////////////////////////////////////////////////////////////////////
1955 //
1956 //  on_if(): handle #if directives
1957 //
1958 ///////////////////////////////////////////////////////////////////////////////
1959 template <typename ContextT>
1960 inline void
1961 pp_iterator_functor<ContextT>::on_if(
1962     result_type const& found_directive,
1963     typename parse_tree_type::const_iterator const &begin,
1964     typename parse_tree_type::const_iterator const &end)
1965 {
1966     // preprocess the given sequence into the provided list
1967     get_token_value<result_type, parse_node_type> get_value;
1968     token_sequence_type toexpand;
1969 
1970     std::copy(make_ref_transform_iterator(begin, get_value),
1971         make_ref_transform_iterator(end, get_value),
1972         std::inserter(toexpand, toexpand.end()));
1973 
1974     impl::remove_leading_whitespace(ctx, toexpand);
1975 
1976     bool if_status = false;
1977     grammars::value_error status = grammars::error_noerror;
1978     token_sequence_type expanded;
1979 
1980     do {
1981         expanded.clear();
1982 
1983         typename token_sequence_type::iterator begin2 = toexpand.begin();
1984         ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded);
1985 
1986         // replace all remaining (== undefined) identifiers with an integer literal '0'
1987         replace_undefined_identifiers(expanded);
1988 
1989 #if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0
1990         {
1991             string_type outstr(boost::wave::util::impl::as_string(toexpand));
1992             outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")";
1993             BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#if " << outstr
1994                 << std::endl;
1995         }
1996 #endif
1997         try {
1998             // parse the expression and enter the #if block
1999             if_status = grammars::expression_grammar_gen<result_type>::
2000                     evaluate(expanded.begin(), expanded.end(), act_pos,
2001                         ctx.get_if_block_status(), status);
2002         }
2003         catch (boost::wave::preprocess_exception const& e) {
2004             // any errors occurred have to be dispatched to the context hooks
2005             ctx.get_hooks().throw_exception(ctx.derived(), e);
2006             break;
2007         }
2008 
2009     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
2010                 found_directive, toexpand, if_status)
2011              && status == grammars::error_noerror);
2012 
2013     ctx.enter_if_block(if_status);
2014     if (grammars::error_noerror != status) {
2015         // division or other error by zero occurred
2016         string_type expression = util::impl::as_string(expanded);
2017         if (0 == expression.size())
2018             expression = "<empty expression>";
2019 
2020         if (grammars::error_division_by_zero & status) {
2021             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, division_by_zero,
2022                 expression.c_str(), act_pos);
2023         }
2024         else if (grammars::error_integer_overflow & status) {
2025             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, integer_overflow,
2026                 expression.c_str(), act_pos);
2027         }
2028         else if (grammars::error_character_overflow & status) {
2029             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2030                 character_literal_out_of_range, expression.c_str(), act_pos);
2031         }
2032     }
2033 }
2034 
2035 ///////////////////////////////////////////////////////////////////////////////
2036 //
2037 //  on_elif(): handle #elif directives
2038 //
2039 ///////////////////////////////////////////////////////////////////////////////
2040 template <typename ContextT>
2041 inline void
2042 pp_iterator_functor<ContextT>::on_elif(
2043     result_type const& found_directive,
2044     typename parse_tree_type::const_iterator const &begin,
2045     typename parse_tree_type::const_iterator const &end)
2046 {
2047     // preprocess the given sequence into the provided list
2048     get_token_value<result_type, parse_node_type> get_value;
2049     token_sequence_type toexpand;
2050 
2051     std::copy(make_ref_transform_iterator(begin, get_value),
2052         make_ref_transform_iterator(end, get_value),
2053         std::inserter(toexpand, toexpand.end()));
2054 
2055     impl::remove_leading_whitespace(ctx, toexpand);
2056 
2057     // check current if block status
2058     if (ctx.get_if_block_some_part_status()) {
2059         if (!ctx.enter_elif_block(false)) {
2060             // #else without matching #if
2061             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2062                 missing_matching_if, "#elif", act_pos);
2063             // fall through...
2064         }
2065 
2066         // skip all the expression and the trailing whitespace
2067         typename token_sequence_type::iterator begin2 = toexpand.begin();
2068 
2069         impl::skip_to_eol(ctx, begin2, toexpand.end());
2070         return;     // one of previous #if/#elif was true, so don't enter this #elif
2071     }
2072 
2073     // preprocess the given sequence into the provided list
2074     bool if_status = false;
2075     grammars::value_error status = grammars::error_noerror;
2076     token_sequence_type expanded;
2077 
2078     do {
2079         expanded.clear();
2080 
2081         typename token_sequence_type::iterator begin2 = toexpand.begin();
2082         ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded);
2083 
2084         // replace all remaining (== undefined) identifiers with an integer literal '0'
2085         replace_undefined_identifiers(expanded);
2086 
2087 #if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0
2088         {
2089             string_type outstr(boost::wave::util::impl::as_string(toexpand));
2090             outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")";
2091             BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#elif " << outstr << std::endl;
2092         }
2093 #endif
2094 
2095         try {
2096             // parse the expression and enter the #elif block
2097             if_status = grammars::expression_grammar_gen<result_type>::
2098                 evaluate(expanded.begin(), expanded.end(), act_pos,
2099                     ctx.get_if_block_status(), status);
2100         }
2101         catch (boost::wave::preprocess_exception const& e) {
2102             // any errors occurred have to be dispatched to the context hooks
2103             ctx.get_hooks().throw_exception(ctx.derived(), e);
2104         }
2105 
2106     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
2107                 found_directive, toexpand, if_status)
2108              && status == grammars::error_noerror);
2109 
2110     if (!ctx.enter_elif_block(if_status)) {
2111         // #elif without matching #if
2112         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
2113             "#elif", act_pos);
2114         return;
2115     }
2116 
2117     if (grammars::error_noerror != status) {
2118         // division or other error by zero occurred
2119         string_type expression = util::impl::as_string(expanded);
2120         if (0 == expression.size())
2121             expression = "<empty expression>";
2122 
2123         if (grammars::error_division_by_zero & status) {
2124             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, division_by_zero,
2125                 expression.c_str(), act_pos);
2126         }
2127         else if (grammars::error_integer_overflow & status) {
2128             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2129                 integer_overflow, expression.c_str(), act_pos);
2130         }
2131         else if (grammars::error_character_overflow & status) {
2132             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2133                 character_literal_out_of_range, expression.c_str(), act_pos);
2134         }
2135     }
2136 }
2137 
2138 ///////////////////////////////////////////////////////////////////////////////
2139 //
2140 //  on_illformed(): handles the illegal directive
2141 //
2142 ///////////////////////////////////////////////////////////////////////////////
2143 template <typename ContextT>
2144 inline void
2145 pp_iterator_functor<ContextT>::on_illformed(
2146     typename result_type::string_type s)
2147 {
2148     BOOST_ASSERT(ctx.get_if_block_status());
2149 
2150     // some messages have more than one newline at the end
2151     typename string_type::size_type p = s.find_last_not_of('\n');
2152     if (string_type::npos != p)
2153         s = s.substr(0, p+1);
2154 
2155     // throw the exception
2156     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_directive,
2157         s.c_str(), act_pos);
2158 }
2159 
2160 ///////////////////////////////////////////////////////////////////////////////
2161 //
2162 //  on_line(): handle #line directives
2163 //
2164 ///////////////////////////////////////////////////////////////////////////////
2165 
2166 namespace impl {
2167 
2168     template <typename IteratorT, typename StringT>
2169     bool retrieve_line_info (IteratorT first, IteratorT const &last,
2170         unsigned int &line, StringT &file,
2171         boost::wave::preprocess_exception::error_code& error)
2172     {
2173         using namespace boost::wave;
2174         token_id id = token_id(*first);
2175         if (T_PP_NUMBER == id || T_INTLIT == id) {
2176         // extract line number
2177             using namespace std;    // some systems have atoi in namespace std
2178             line = (unsigned int)atoi((*first).get_value().c_str());
2179             if (0 == line)
2180                 error = preprocess_exception::bad_line_number;
2181 
2182         // re-extract line number with spirit to diagnose overflow
2183             using namespace boost::spirit::classic;
2184             if (!parse((*first).get_value().c_str(), int_p).full)
2185                 error = preprocess_exception::bad_line_number;
2186 
2187         // extract file name (if it is given)
2188             while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
2189                 /**/;   // skip whitespace
2190 
2191             if (first != last) {
2192                 if (T_STRINGLIT != token_id(*first)) {
2193                     error = preprocess_exception::bad_line_filename;
2194                     return false;
2195                 }
2196 
2197                 StringT const& file_lit = (*first).get_value();
2198 
2199                 if ('L' == file_lit[0]) {
2200                     error = preprocess_exception::bad_line_filename;
2201                     return false;       // shouldn't be a wide character string
2202                 }
2203 
2204                 file = file_lit.substr(1, file_lit.size()-2);
2205 
2206             // test if there is other junk on this line
2207                 while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
2208                     /**/;   // skip whitespace
2209             }
2210             return first == last;
2211         }
2212         error = preprocess_exception::bad_line_statement;
2213         return false;
2214     }
2215 }
2216 
2217 template <typename ContextT>
2218 inline void
2219 pp_iterator_functor<ContextT>::on_line(
2220     typename parse_tree_type::const_iterator const &begin,
2221     typename parse_tree_type::const_iterator const &end)
2222 {
2223     BOOST_ASSERT(ctx.get_if_block_status());
2224 
2225     // Try to extract the line number and file name from the given token list
2226     // directly. If that fails, preprocess the whole token sequence and try again
2227     // to extract this information.
2228     token_sequence_type expanded;
2229     get_token_value<result_type, parse_node_type> get_value;
2230 
2231     typedef typename ref_transform_iterator_generator<
2232             get_token_value<result_type, parse_node_type>,
2233             typename parse_tree_type::const_iterator
2234         >::type const_tree_iterator_t;
2235 
2236     const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value);
2237     const_tree_iterator_t last = make_ref_transform_iterator(end, get_value);
2238 
2239     // try to interpret the #line body as a number followed by an optional
2240     // string literal
2241     unsigned int line = 0;
2242     preprocess_exception::error_code error = preprocess_exception::no_error;
2243     string_type file_name;
2244     token_sequence_type toexpand;
2245 
2246     std::copy(first, last, std::inserter(toexpand, toexpand.end()));
2247     if (!impl::retrieve_line_info(first, last, line, file_name, error)) {
2248         // preprocess the body of this #line message
2249         typename token_sequence_type::iterator begin2 = toexpand.begin();
2250         ctx.expand_whole_tokensequence(begin2, toexpand.end(),
2251                                        expanded, false, false);
2252 
2253         error = preprocess_exception::no_error;
2254         if (!impl::retrieve_line_info(expanded.begin(), expanded.end(),
2255             line, file_name, error))
2256         {
2257             typename ContextT::string_type msg(
2258                 boost::wave::util::impl::as_string(expanded));
2259             BOOST_WAVE_THROW_VAR_CTX(ctx, preprocess_exception, error,
2260                 msg.c_str(), act_pos);
2261             return;
2262         }
2263 
2264         // call the corresponding pp hook function
2265         ctx.get_hooks().found_line_directive(ctx.derived(), expanded, line,
2266             file_name.c_str());
2267     }
2268     else {
2269         // call the corresponding pp hook function
2270         ctx.get_hooks().found_line_directive(ctx.derived(), toexpand, line,
2271             file_name.c_str());
2272     }
2273 
2274     // the queues should be empty at this point
2275     BOOST_ASSERT(unput_queue.empty());
2276     BOOST_ASSERT(pending_queue.empty());
2277 
2278     // make sure error recovery starts on the next line
2279     must_emit_line_directive = true;
2280 
2281     // diagnose possible error in detected line directive
2282     if (error != preprocess_exception::no_error) {
2283         typename ContextT::string_type msg(
2284             boost::wave::util::impl::as_string(expanded));
2285         BOOST_WAVE_THROW_VAR_CTX(ctx, preprocess_exception, error,
2286             msg.c_str(), act_pos);
2287         return;
2288     }
2289 
2290     // set new line number/filename only if ok
2291     if (!file_name.empty()) {    // reuse current file name
2292         using boost::wave::util::impl::unescape_lit;
2293         act_pos.set_file(unescape_lit(file_name).c_str());
2294     }
2295     act_pos.set_line(line);
2296     if (iter_ctx->first != iter_ctx->last)
2297     {
2298       iter_ctx->first.set_position(act_pos);
2299     }
2300 }
2301 
2302 ///////////////////////////////////////////////////////////////////////////////
2303 //
2304 //  on_error(): handle #error directives
2305 //
2306 ///////////////////////////////////////////////////////////////////////////////
2307 template <typename ContextT>
2308 inline void
2309 pp_iterator_functor<ContextT>::on_error(
2310     typename parse_tree_type::const_iterator const &begin,
2311     typename parse_tree_type::const_iterator const &end)
2312 {
2313     BOOST_ASSERT(ctx.get_if_block_status());
2314 
2315     // preprocess the given sequence into the provided list
2316     token_sequence_type expanded;
2317     get_token_value<result_type, parse_node_type> get_value;
2318 
2319     typename ref_transform_iterator_generator<
2320         get_token_value<result_type, parse_node_type>,
2321         typename parse_tree_type::const_iterator
2322     >::type first = make_ref_transform_iterator(begin, get_value);
2323 
2324 #if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0
2325     // preprocess the body of this #error message
2326     token_sequence_type toexpand;
2327 
2328     std::copy(first, make_ref_transform_iterator(end, get_value),
2329         std::inserter(toexpand, toexpand.end()));
2330 
2331     typename token_sequence_type::iterator begin2 = toexpand.begin();
2332     ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
2333                                    false, false);
2334     if (!ctx.get_hooks().found_error_directive(ctx.derived(), toexpand))
2335 #else
2336     // simply copy the body of this #error message to the issued diagnostic
2337     // message
2338     std::copy(first, make_ref_transform_iterator(end, get_value),
2339         std::inserter(expanded, expanded.end()));
2340     if (!ctx.get_hooks().found_error_directive(ctx.derived(), expanded))
2341 #endif
2342     {
2343         // report the corresponding error
2344         BOOST_WAVE_STRINGTYPE msg(boost::wave::util::impl::as_string(expanded));
2345         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, error_directive,
2346             msg.c_str(), act_pos);
2347     }
2348 }
2349 
2350 #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
2351 ///////////////////////////////////////////////////////////////////////////////
2352 //
2353 //  on_warning(): handle #warning directives
2354 //
2355 ///////////////////////////////////////////////////////////////////////////////
2356 template <typename ContextT>
2357 inline void
2358 pp_iterator_functor<ContextT>::on_warning(
2359     typename parse_tree_type::const_iterator const &begin,
2360     typename parse_tree_type::const_iterator const &end)
2361 {
2362     BOOST_ASSERT(ctx.get_if_block_status());
2363 
2364     // preprocess the given sequence into the provided list
2365     token_sequence_type expanded;
2366     get_token_value<result_type, parse_node_type> get_value;
2367 
2368     typename ref_transform_iterator_generator<
2369         get_token_value<result_type, parse_node_type>,
2370         typename parse_tree_type::const_iterator
2371     >::type first = make_ref_transform_iterator(begin, get_value);
2372 
2373 #if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0
2374     // preprocess the body of this #warning message
2375     token_sequence_type toexpand;
2376 
2377     std::copy(first, make_ref_transform_iterator(end, get_value),
2378         std::inserter(toexpand, toexpand.end()));
2379 
2380     typename token_sequence_type::iterator begin2 = toexpand.begin();
2381     ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
2382                                    false, false);
2383     if (!ctx.get_hooks().found_warning_directive(ctx.derived(), toexpand))
2384 #else
2385     // simply copy the body of this #warning message to the issued diagnostic
2386     // message
2387     std::copy(first, make_ref_transform_iterator(end, get_value),
2388         std::inserter(expanded, expanded.end()));
2389     if (!ctx.get_hooks().found_warning_directive(ctx.derived(), expanded))
2390 #endif
2391     {
2392         // report the corresponding error
2393         BOOST_WAVE_STRINGTYPE msg(boost::wave::util::impl::as_string(expanded));
2394         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, warning_directive,
2395             msg.c_str(), act_pos);
2396     }
2397 }
2398 #endif // BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
2399 
2400 ///////////////////////////////////////////////////////////////////////////////
2401 //
2402 //  on_pragma(): handle #pragma directives
2403 //
2404 ///////////////////////////////////////////////////////////////////////////////
2405 template <typename ContextT>
2406 inline bool
2407 pp_iterator_functor<ContextT>::on_pragma(
2408     typename parse_tree_type::const_iterator const &begin,
2409     typename parse_tree_type::const_iterator const &end)
2410 {
2411     using namespace boost::wave;
2412 
2413     BOOST_ASSERT(ctx.get_if_block_status());
2414 
2415     // Look at the pragma token sequence and decide, if the first token is STDC
2416     // (see C99 standard [6.10.6.2]), if it is, the sequence must _not_ be
2417     // preprocessed.
2418     token_sequence_type expanded;
2419     get_token_value<result_type, parse_node_type> get_value;
2420 
2421     typedef typename ref_transform_iterator_generator<
2422             get_token_value<result_type, parse_node_type>,
2423             typename parse_tree_type::const_iterator
2424         >::type const_tree_iterator_t;
2425 
2426     const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value);
2427     const_tree_iterator_t last = make_ref_transform_iterator(end, get_value);
2428 
2429     expanded.push_back(result_type(T_PP_PRAGMA, "#pragma", act_token.get_position()));
2430 
2431     while (first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
2432         expanded.push_back(*first++);   // skip whitespace
2433 
2434     if (first != last) {
2435         if (T_IDENTIFIER == token_id(*first) &&
2436             boost::wave::need_c99(ctx.get_language()) &&
2437             (*first).get_value() == "STDC")
2438         {
2439         // do _not_ preprocess the token sequence
2440             std::copy(first, last, std::inserter(expanded, expanded.end()));
2441         }
2442         else {
2443 #if BOOST_WAVE_PREPROCESS_PRAGMA_BODY != 0
2444             // preprocess the given tokensequence
2445             token_sequence_type toexpand;
2446 
2447             std::copy(first, last, std::inserter(toexpand, toexpand.end()));
2448 
2449             typename token_sequence_type::iterator begin2 = toexpand.begin();
2450             ctx.expand_whole_tokensequence(begin2, toexpand.end(),
2451                                            expanded, false, false);
2452 #else
2453             // do _not_ preprocess the token sequence
2454             std::copy(first, last, std::inserter(expanded, expanded.end()));
2455 #endif
2456         }
2457     }
2458 
2459     // the queues should be empty at this point
2460     BOOST_ASSERT(unput_queue.empty());
2461     BOOST_ASSERT(pending_queue.empty());
2462 
2463     // try to interpret the expanded #pragma body
2464     token_sequence_type pending;
2465     if (interpret_pragma(expanded, pending)) {
2466         // if there is some replacement text, insert it into the pending queue
2467         if (!pending.empty())
2468             pending_queue.splice(pending_queue.begin(), pending);
2469         return true;        // this #pragma was successfully recognized
2470     }
2471 
2472 #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
2473     // Move the resulting token sequence into the pending_queue, so it will be
2474     // returned to the caller.
2475     if (boost::wave::need_emit_pragma_directives(ctx.get_language())) {
2476         pending_queue.splice(pending_queue.begin(), expanded);
2477         return false;       // return the whole #pragma directive
2478     }
2479 #endif
2480     return true;            // skip the #pragma at all
2481 }
2482 
2483 template <typename ContextT>
2484 inline bool
2485 pp_iterator_functor<ContextT>::interpret_pragma(
2486     token_sequence_type const &pragma_body, token_sequence_type &result)
2487 {
2488     using namespace cpplexer;
2489 
2490     typename token_sequence_type::const_iterator end = pragma_body.end();
2491     typename token_sequence_type::const_iterator it = pragma_body.begin();
2492     for (++it; it != end && IS_CATEGORY(*it, WhiteSpaceTokenType); ++it)
2493         /**/;   // skip whitespace
2494 
2495     if (it == end)      // eof reached
2496         return false;
2497 
2498     return boost::wave::util::interpret_pragma(
2499         ctx.derived(), act_token, it, end, result);
2500 }
2501 
2502 ///////////////////////////////////////////////////////////////////////////////
2503 }   // namespace impl
2504 
2505 ///////////////////////////////////////////////////////////////////////////////
2506 //
2507 //  pp_iterator
2508 //
2509 //      The boost::wave::pp_iterator template is the iterator, through which
2510 //      the resulting preprocessed input stream is accessible.
2511 //
2512 ///////////////////////////////////////////////////////////////////////////////
2513 
2514 template <typename ContextT>
2515 class pp_iterator
2516 :   public boost::spirit::classic::multi_pass<
2517         boost::wave::impl::pp_iterator_functor<ContextT>,
2518         boost::wave::util::functor_input
2519     >
2520 {
2521 public:
2522     typedef boost::wave::impl::pp_iterator_functor<ContextT> input_policy_type;
2523 
2524 private:
2525     typedef
2526         boost::spirit::classic::multi_pass<input_policy_type, boost::wave::util::functor_input>
2527         base_type;
2528     typedef pp_iterator<ContextT> self_type;
2529     typedef boost::wave::util::functor_input functor_input_type;
2530 
2531 public:
2532     pp_iterator()
2533     {}
2534 
2535     template <typename IteratorT>
2536     pp_iterator(ContextT &ctx, IteratorT const &first, IteratorT const &last,
2537         typename ContextT::position_type const &pos)
2538     :   base_type(input_policy_type(ctx, first, last, pos))
2539     {}
2540 
2541     bool force_include(char const *path_, bool is_last)
2542     {
2543         bool result = this->get_functor().on_include_helper(path_, path_,
2544             false, false);
2545         if (is_last) {
2546             this->functor_input_type::
2547                 template inner<input_policy_type>::advance_input();
2548         }
2549         return result;
2550     }
2551 };
2552 
2553 ///////////////////////////////////////////////////////////////////////////////
2554 }   // namespace wave
2555 }   // namespace boost
2556 
2557 // the suffix header occurs after all of the code
2558 #ifdef BOOST_HAS_ABI_HEADERS
2559 #include BOOST_ABI_SUFFIX
2560 #endif
2561 
2562 #endif // !defined(BOOST_CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED)