Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:52:58

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 true: 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         new_iter_ctx->emitted_lines = (unsigned int)(-1); // force #line directive
1611 
1612         // call the include policy trace function
1613         ctx.get_hooks().opened_include_file(ctx.derived(), dir_path, file_path,
1614             is_system);
1615 
1616         // store current file position
1617         iter_ctx->real_relative_filename = ctx.get_current_relative_filename().c_str();
1618         iter_ctx->filename = act_pos.get_file();
1619         iter_ctx->line = act_pos.get_line();
1620         iter_ctx->if_block_depth = ctx.get_if_block_depth();
1621         iter_ctx->emitted_lines = (unsigned int)(-1);   // force #line directive
1622 
1623         // push the old iteration context onto the stack and continue with the new
1624         ctx.push_iteration_context(act_pos, iter_ctx);
1625         iter_ctx = new_iter_ctx;
1626         seen_newline = true;        // fake a newline to trigger pp_directive
1627         must_emit_line_directive = true;
1628 
1629         act_pos.set_file(iter_ctx->filename);  // initialize file position
1630 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
1631         fs::path rfp(wave::util::create_path(iter_ctx->real_filename.c_str()));
1632         std::string real_filename(rfp.string());
1633         ctx.set_current_filename(real_filename.c_str());
1634 #endif
1635 
1636         ctx.set_current_relative_filename(dir_path.c_str());
1637         iter_ctx->real_relative_filename = dir_path.c_str();
1638 
1639         act_pos.set_line(iter_ctx->line);
1640         act_pos.set_column(0);
1641     }
1642     return true;
1643 }
1644 
1645 ///////////////////////////////////////////////////////////////////////////////
1646 //
1647 //  on_include(): handle #include ... directives
1648 //
1649 ///////////////////////////////////////////////////////////////////////////////
1650 
1651 template <typename ContextT>
1652 inline void
1653 pp_iterator_functor<ContextT>::on_include(
1654     typename parse_tree_type::const_iterator const &begin,
1655     typename parse_tree_type::const_iterator const &end, bool include_next)
1656 {
1657     BOOST_ASSERT(ctx.get_if_block_status());
1658 
1659     // preprocess the given token sequence (the body of the #include directive)
1660     get_token_value<result_type, parse_node_type> get_value;
1661     token_sequence_type expanded;
1662     token_sequence_type toexpand;
1663 
1664     std::copy(make_ref_transform_iterator(begin, get_value),
1665         make_ref_transform_iterator(end, get_value),
1666         std::inserter(toexpand, toexpand.end()));
1667 
1668     typename token_sequence_type::iterator begin2 = toexpand.begin();
1669     // expanding the computed include
1670     ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
1671                                    false, false);
1672 
1673     // now, include the file
1674     using namespace boost::wave::util::impl;
1675     string_type s (trim_whitespace(as_string(expanded)));
1676     bool is_system = '<' == s[0] && '>' == s[s.size()-1];
1677 
1678     if (!is_system && !('\"' == s[0] && '\"' == s[s.size()-1])) {
1679     // should resolve into something like <...> or "..."
1680         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
1681             s.c_str(), act_pos);
1682         return;
1683     }
1684     on_include(s, is_system, include_next);
1685 }
1686 
1687 ///////////////////////////////////////////////////////////////////////////////
1688 //
1689 //  on_define(): handle #define directives
1690 //
1691 ///////////////////////////////////////////////////////////////////////////////
1692 
1693 template <typename ContextT>
1694 inline void
1695 pp_iterator_functor<ContextT>::on_define (parse_node_type const &node)
1696 {
1697     BOOST_ASSERT(ctx.get_if_block_status());
1698 
1699     // retrieve the macro definition from the parse tree
1700     result_type macroname;
1701     std::vector<result_type> macroparameters;
1702     token_sequence_type macrodefinition;
1703     bool has_parameters = false;
1704     position_type pos(act_token.get_position());
1705 
1706     if (!boost::wave::util::retrieve_macroname(ctx, node,
1707             BOOST_WAVE_PLAIN_DEFINE_ID, macroname, pos, false))
1708         return;
1709     has_parameters = boost::wave::util::retrieve_macrodefinition(node,
1710         BOOST_WAVE_MACRO_PARAMETERS_ID, macroparameters, pos, false);
1711     boost::wave::util::retrieve_macrodefinition(node,
1712         BOOST_WAVE_MACRO_DEFINITION_ID, macrodefinition, pos, false);
1713 
1714     if (has_parameters) {
1715 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1716         if (boost::wave::need_variadics(ctx.get_language())) {
1717             // test whether ellipsis are given, and if yes, if these are placed as the
1718             // last argument, test if __VA_ARGS__ is used as a macro parameter name
1719             using namespace cpplexer;
1720             typedef typename std::vector<result_type>::iterator
1721                 parameter_iterator_t;
1722 
1723             bool seen_ellipses = false;
1724             parameter_iterator_t end = macroparameters.end();
1725             for (parameter_iterator_t pit = macroparameters.begin();
1726                 pit != end; ++pit)
1727             {
1728                 if (seen_ellipses) {
1729                     // ellipses are not the last given formal argument
1730                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1731                         bad_define_statement, macroname.get_value().c_str(),
1732                         (*pit).get_position());
1733                     return;
1734                 }
1735                 if (T_ELLIPSIS == token_id(*pit))
1736                     seen_ellipses = true;
1737 
1738                 // can't use __VA_ARGS__ as a argument name
1739                 if ("__VA_ARGS__" == (*pit).get_value()) {
1740                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1741                         bad_define_statement_va_args,
1742                         macroname.get_value().c_str(), (*pit).get_position());
1743                     return;
1744                 }
1745 
1746 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1747                 // can't use __VA_OPT__ either
1748                 if (boost::wave::need_va_opt(ctx.get_language()) &&
1749                     ("__VA_OPT__" == (*pit).get_value())) {
1750                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1751                         bad_define_statement_va_opt,
1752                         macroname.get_value().c_str(), (*pit).get_position());
1753                     return;
1754                 }
1755 #endif
1756             }
1757 
1758             // if there wasn't an ellipsis, then there shouldn't be a __VA_ARGS__
1759             // placeholder in the definition too [C99 Standard 6.10.3.5]
1760             if (!seen_ellipses) {
1761                 typedef typename token_sequence_type::iterator definition_iterator_t;
1762 
1763                 bool seen_va_args = false;
1764 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1765                 bool seen_va_opt = false;
1766 #endif
1767                 definition_iterator_t pend = macrodefinition.end();
1768                 for (definition_iterator_t dit = macrodefinition.begin();
1769                      dit != pend; ++dit)
1770                 {
1771                     if (T_IDENTIFIER == token_id(*dit) &&
1772                         "__VA_ARGS__" == (*dit).get_value())
1773                     {
1774                         seen_va_args = true;
1775                     }
1776 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1777                     if (T_IDENTIFIER == token_id(*dit) &&
1778                         "__VA_OPT__" == (*dit).get_value())
1779                     {
1780                         seen_va_opt = true;
1781                     }
1782 #endif
1783                 }
1784                 if (seen_va_args) {
1785                     // must not have seen __VA_ARGS__ placeholder
1786                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1787                         bad_define_statement_va_args,
1788                         macroname.get_value().c_str(), act_token.get_position());
1789                     return;
1790                 }
1791 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1792                 if (seen_va_opt) {
1793                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1794                         bad_define_statement_va_opt,
1795                         macroname.get_value().c_str(), act_token.get_position());
1796                     return;
1797                 }
1798 #endif
1799             }
1800         }
1801         else
1802 #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1803         {
1804             // test, that there is no T_ELLIPSES given
1805             using namespace cpplexer;
1806             typedef typename std::vector<result_type>::iterator
1807                 parameter_iterator_t;
1808 
1809             parameter_iterator_t end = macroparameters.end();
1810             for (parameter_iterator_t pit = macroparameters.begin();
1811                 pit != end; ++pit)
1812             {
1813                 if (T_ELLIPSIS == token_id(*pit)) {
1814                     // if variadics are disabled, no ellipses should be given
1815                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1816                         bad_define_statement, macroname.get_value().c_str(),
1817                         (*pit).get_position());
1818                     return;
1819                 }
1820             }
1821         }
1822     }
1823 
1824     // add the new macro to the macromap
1825     ctx.add_macro_definition(macroname, has_parameters, macroparameters,
1826         macrodefinition);
1827 }
1828 
1829 ///////////////////////////////////////////////////////////////////////////////
1830 //
1831 //  on_undefine(): handle #undef directives
1832 //
1833 ///////////////////////////////////////////////////////////////////////////////
1834 template <typename ContextT>
1835 inline void
1836 pp_iterator_functor<ContextT>::on_undefine (lexer_type const &it)
1837 {
1838     BOOST_ASSERT(ctx.get_if_block_status());
1839 
1840     // retrieve the macro name to undefine from the parse tree
1841     ctx.remove_macro_definition((*it).get_value()); // throws for predefined macros
1842 }
1843 
1844 ///////////////////////////////////////////////////////////////////////////////
1845 //
1846 //  on_ifdef(): handle #ifdef directives
1847 //
1848 ///////////////////////////////////////////////////////////////////////////////
1849 template <typename ContextT>
1850 inline void
1851 pp_iterator_functor<ContextT>::on_ifdef(
1852     result_type const& found_directive,
1853     typename parse_tree_type::const_iterator const &begin,
1854     typename parse_tree_type::const_iterator const &end)
1855 {
1856     get_token_value<result_type, parse_node_type> get_value;
1857     token_sequence_type toexpand;
1858 
1859     std::copy(make_ref_transform_iterator((*begin).children.begin(), get_value),
1860               make_ref_transform_iterator((*begin).children.end(), get_value),
1861               std::inserter(toexpand, toexpand.end()));
1862 
1863     bool is_defined = false;
1864 
1865     do {
1866         is_defined = ctx.is_defined_macro(toexpand.begin(), toexpand.end());
1867     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
1868              found_directive, toexpand, is_defined));
1869     ctx.enter_if_block(is_defined);
1870 }
1871 
1872 ///////////////////////////////////////////////////////////////////////////////
1873 //
1874 //  on_ifndef(): handle #ifndef directives
1875 //
1876 ///////////////////////////////////////////////////////////////////////////////
1877 template <typename ContextT>
1878 inline void
1879 pp_iterator_functor<ContextT>::on_ifndef(
1880     result_type const& found_directive,
1881     typename parse_tree_type::const_iterator const &begin,
1882     typename parse_tree_type::const_iterator const &end)
1883 {
1884     get_token_value<result_type, parse_node_type> get_value;
1885     token_sequence_type toexpand;
1886 
1887     std::copy(make_ref_transform_iterator((*begin).children.begin(), get_value),
1888               make_ref_transform_iterator((*begin).children.end(), get_value),
1889               std::inserter(toexpand, toexpand.end()));
1890 
1891     bool is_defined = false;
1892 
1893     do {
1894         is_defined = ctx.is_defined_macro(toexpand.begin(), toexpand.end());
1895     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
1896              found_directive, toexpand, is_defined));
1897     ctx.enter_if_block(!is_defined);
1898 }
1899 
1900 ///////////////////////////////////////////////////////////////////////////////
1901 //
1902 //  on_else(): handle #else directives
1903 //
1904 ///////////////////////////////////////////////////////////////////////////////
1905 template <typename ContextT>
1906 inline void
1907 pp_iterator_functor<ContextT>::on_else()
1908 {
1909     if (!ctx.enter_else_block()) {
1910         // #else without matching #if
1911         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
1912             "#else", act_pos);
1913     }
1914 }
1915 
1916 ///////////////////////////////////////////////////////////////////////////////
1917 //
1918 //  on_endif(): handle #endif directives
1919 //
1920 ///////////////////////////////////////////////////////////////////////////////
1921 template <typename ContextT>
1922 inline void
1923 pp_iterator_functor<ContextT>::on_endif()
1924 {
1925     if (!ctx.exit_if_block()) {
1926         // #endif without matching #if
1927         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
1928             "#endif", act_pos);
1929     }
1930 }
1931 
1932 ///////////////////////////////////////////////////////////////////////////////
1933 //  replace all remaining (== undefined) identifiers with an integer literal '0'
1934 template <typename ContextT>
1935 inline void
1936 pp_iterator_functor<ContextT>::replace_undefined_identifiers(
1937     token_sequence_type &expanded)
1938 {
1939     typename token_sequence_type::iterator exp_end = expanded.end();
1940     for (typename token_sequence_type::iterator exp_it = expanded.begin();
1941          exp_it != exp_end; ++exp_it)
1942     {
1943         using namespace boost::wave;
1944 
1945         token_id id = token_id(*exp_it);
1946         if (IS_CATEGORY(id, IdentifierTokenType) ||
1947             IS_CATEGORY(id, KeywordTokenType))
1948         {
1949             (*exp_it).set_token_id(T_INTLIT);
1950             (*exp_it).set_value("0");
1951         }
1952     }
1953 }
1954 
1955 ///////////////////////////////////////////////////////////////////////////////
1956 //
1957 //  on_if(): handle #if directives
1958 //
1959 ///////////////////////////////////////////////////////////////////////////////
1960 template <typename ContextT>
1961 inline void
1962 pp_iterator_functor<ContextT>::on_if(
1963     result_type const& found_directive,
1964     typename parse_tree_type::const_iterator const &begin,
1965     typename parse_tree_type::const_iterator const &end)
1966 {
1967     // preprocess the given sequence into the provided list
1968     get_token_value<result_type, parse_node_type> get_value;
1969     token_sequence_type toexpand;
1970 
1971     std::copy(make_ref_transform_iterator(begin, get_value),
1972         make_ref_transform_iterator(end, get_value),
1973         std::inserter(toexpand, toexpand.end()));
1974 
1975     impl::remove_leading_whitespace(ctx, toexpand);
1976 
1977     bool if_status = false;
1978     grammars::value_error status = grammars::error_noerror;
1979     token_sequence_type expanded;
1980 
1981     do {
1982         expanded.clear();
1983 
1984         typename token_sequence_type::iterator begin2 = toexpand.begin();
1985         ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded);
1986 
1987         // replace all remaining (== undefined) identifiers with an integer literal '0'
1988         replace_undefined_identifiers(expanded);
1989 
1990 #if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0
1991         {
1992             string_type outstr(boost::wave::util::impl::as_string(toexpand));
1993             outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")";
1994             BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#if " << outstr
1995                 << std::endl;
1996         }
1997 #endif
1998         try {
1999             // parse the expression and enter the #if block
2000             if_status = grammars::expression_grammar_gen<result_type>::
2001                     evaluate(expanded.begin(), expanded.end(), act_pos,
2002                         ctx.get_if_block_status(), status);
2003         }
2004         catch (boost::wave::preprocess_exception const& e) {
2005             // any errors occurred have to be dispatched to the context hooks
2006             ctx.get_hooks().throw_exception(ctx.derived(), e);
2007             break;
2008         }
2009 
2010     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
2011                 found_directive, toexpand, if_status)
2012              && status == grammars::error_noerror);
2013 
2014     ctx.enter_if_block(if_status);
2015     if (grammars::error_noerror != status) {
2016         // division or other error by zero occurred
2017         string_type expression = util::impl::as_string(expanded);
2018         if (0 == expression.size())
2019             expression = "<empty expression>";
2020 
2021         if (grammars::error_division_by_zero & status) {
2022             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, division_by_zero,
2023                 expression.c_str(), act_pos);
2024         }
2025         else if (grammars::error_integer_overflow & status) {
2026             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, integer_overflow,
2027                 expression.c_str(), act_pos);
2028         }
2029         else if (grammars::error_character_overflow & status) {
2030             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2031                 character_literal_out_of_range, expression.c_str(), act_pos);
2032         }
2033     }
2034 }
2035 
2036 ///////////////////////////////////////////////////////////////////////////////
2037 //
2038 //  on_elif(): handle #elif directives
2039 //
2040 ///////////////////////////////////////////////////////////////////////////////
2041 template <typename ContextT>
2042 inline void
2043 pp_iterator_functor<ContextT>::on_elif(
2044     result_type const& found_directive,
2045     typename parse_tree_type::const_iterator const &begin,
2046     typename parse_tree_type::const_iterator const &end)
2047 {
2048     // preprocess the given sequence into the provided list
2049     get_token_value<result_type, parse_node_type> get_value;
2050     token_sequence_type toexpand;
2051 
2052     std::copy(make_ref_transform_iterator(begin, get_value),
2053         make_ref_transform_iterator(end, get_value),
2054         std::inserter(toexpand, toexpand.end()));
2055 
2056     impl::remove_leading_whitespace(ctx, toexpand);
2057 
2058     // check current if block status
2059     if (ctx.get_if_block_some_part_status()) {
2060         if (!ctx.enter_elif_block(false)) {
2061             // #else without matching #if
2062             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2063                 missing_matching_if, "#elif", act_pos);
2064             // fall through...
2065         }
2066 
2067         // skip all the expression and the trailing whitespace
2068         typename token_sequence_type::iterator begin2 = toexpand.begin();
2069 
2070         impl::skip_to_eol(ctx, begin2, toexpand.end());
2071         return;     // one of previous #if/#elif was true, so don't enter this #elif
2072     }
2073 
2074     // preprocess the given sequence into the provided list
2075     bool if_status = false;
2076     grammars::value_error status = grammars::error_noerror;
2077     token_sequence_type expanded;
2078 
2079     do {
2080         expanded.clear();
2081 
2082         typename token_sequence_type::iterator begin2 = toexpand.begin();
2083         ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded);
2084 
2085         // replace all remaining (== undefined) identifiers with an integer literal '0'
2086         replace_undefined_identifiers(expanded);
2087 
2088 #if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0
2089         {
2090             string_type outstr(boost::wave::util::impl::as_string(toexpand));
2091             outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")";
2092             BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#elif " << outstr << std::endl;
2093         }
2094 #endif
2095 
2096         try {
2097             // parse the expression and enter the #elif block
2098             if_status = grammars::expression_grammar_gen<result_type>::
2099                 evaluate(expanded.begin(), expanded.end(), act_pos,
2100                     ctx.get_if_block_status(), status);
2101         }
2102         catch (boost::wave::preprocess_exception const& e) {
2103             // any errors occurred have to be dispatched to the context hooks
2104             ctx.get_hooks().throw_exception(ctx.derived(), e);
2105         }
2106 
2107     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
2108                 found_directive, toexpand, if_status)
2109              && status == grammars::error_noerror);
2110 
2111     if (!ctx.enter_elif_block(if_status)) {
2112         // #elif without matching #if
2113         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
2114             "#elif", act_pos);
2115         return;
2116     }
2117 
2118     if (grammars::error_noerror != status) {
2119         // division or other error by zero occurred
2120         string_type expression = util::impl::as_string(expanded);
2121         if (0 == expression.size())
2122             expression = "<empty expression>";
2123 
2124         if (grammars::error_division_by_zero & status) {
2125             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, division_by_zero,
2126                 expression.c_str(), act_pos);
2127         }
2128         else if (grammars::error_integer_overflow & status) {
2129             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2130                 integer_overflow, expression.c_str(), act_pos);
2131         }
2132         else if (grammars::error_character_overflow & status) {
2133             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2134                 character_literal_out_of_range, expression.c_str(), act_pos);
2135         }
2136     }
2137 }
2138 
2139 ///////////////////////////////////////////////////////////////////////////////
2140 //
2141 //  on_illformed(): handles the illegal directive
2142 //
2143 ///////////////////////////////////////////////////////////////////////////////
2144 template <typename ContextT>
2145 inline void
2146 pp_iterator_functor<ContextT>::on_illformed(
2147     typename result_type::string_type s)
2148 {
2149     BOOST_ASSERT(ctx.get_if_block_status());
2150 
2151     // some messages have more than one newline at the end
2152     typename string_type::size_type p = s.find_last_not_of('\n');
2153     if (string_type::npos != p)
2154         s = s.substr(0, p+1);
2155 
2156     // throw the exception
2157     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_directive,
2158         s.c_str(), act_pos);
2159 }
2160 
2161 ///////////////////////////////////////////////////////////////////////////////
2162 //
2163 //  on_line(): handle #line directives
2164 //
2165 ///////////////////////////////////////////////////////////////////////////////
2166 
2167 namespace impl {
2168 
2169     template <typename IteratorT, typename StringT>
2170     bool retrieve_line_info (IteratorT first, IteratorT const &last,
2171         unsigned int &line, StringT &file,
2172         boost::wave::preprocess_exception::error_code& error)
2173     {
2174         using namespace boost::wave;
2175         token_id id = token_id(*first);
2176         if (T_PP_NUMBER == id || T_INTLIT == id) {
2177         // extract line number
2178             using namespace std;    // some systems have atoi in namespace std
2179             line = (unsigned int)atoi((*first).get_value().c_str());
2180             if (0 == line)
2181                 error = preprocess_exception::bad_line_number;
2182 
2183         // re-extract line number with spirit to diagnose overflow
2184             using namespace boost::spirit::classic;
2185             if (!parse((*first).get_value().c_str(), int_p).full)
2186                 error = preprocess_exception::bad_line_number;
2187 
2188         // extract file name (if it is given)
2189             while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
2190                 /**/;   // skip whitespace
2191 
2192             if (first != last) {
2193                 if (T_STRINGLIT != token_id(*first)) {
2194                     error = preprocess_exception::bad_line_filename;
2195                     return false;
2196                 }
2197 
2198                 StringT const& file_lit = (*first).get_value();
2199 
2200                 if ('L' == file_lit[0]) {
2201                     error = preprocess_exception::bad_line_filename;
2202                     return false;       // shouldn't be a wide character string
2203                 }
2204 
2205                 file = file_lit.substr(1, file_lit.size()-2);
2206 
2207             // test if there is other junk on this line
2208                 while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
2209                     /**/;   // skip whitespace
2210             }
2211             return first == last;
2212         }
2213         error = preprocess_exception::bad_line_statement;
2214         return false;
2215     }
2216 }
2217 
2218 template <typename ContextT>
2219 inline void
2220 pp_iterator_functor<ContextT>::on_line(
2221     typename parse_tree_type::const_iterator const &begin,
2222     typename parse_tree_type::const_iterator const &end)
2223 {
2224     BOOST_ASSERT(ctx.get_if_block_status());
2225 
2226     // Try to extract the line number and file name from the given token list
2227     // directly. If that fails, preprocess the whole token sequence and try again
2228     // to extract this information.
2229     token_sequence_type expanded;
2230     get_token_value<result_type, parse_node_type> get_value;
2231 
2232     typedef typename ref_transform_iterator_generator<
2233             get_token_value<result_type, parse_node_type>,
2234             typename parse_tree_type::const_iterator
2235         >::type const_tree_iterator_t;
2236 
2237     const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value);
2238     const_tree_iterator_t last = make_ref_transform_iterator(end, get_value);
2239 
2240     // try to interpret the #line body as a number followed by an optional
2241     // string literal
2242     unsigned int line = 0;
2243     preprocess_exception::error_code error = preprocess_exception::no_error;
2244     string_type file_name;
2245     token_sequence_type toexpand;
2246 
2247     std::copy(first, last, std::inserter(toexpand, toexpand.end()));
2248     if (!impl::retrieve_line_info(first, last, line, file_name, error)) {
2249         // preprocess the body of this #line message
2250         typename token_sequence_type::iterator begin2 = toexpand.begin();
2251         ctx.expand_whole_tokensequence(begin2, toexpand.end(),
2252                                        expanded, false, false);
2253 
2254         error = preprocess_exception::no_error;
2255         if (!impl::retrieve_line_info(expanded.begin(), expanded.end(),
2256             line, file_name, error))
2257         {
2258             typename ContextT::string_type msg(
2259                 boost::wave::util::impl::as_string(expanded));
2260             BOOST_WAVE_THROW_VAR_CTX(ctx, preprocess_exception, error,
2261                 msg.c_str(), act_pos);
2262             return;
2263         }
2264 
2265         // call the corresponding pp hook function
2266         ctx.get_hooks().found_line_directive(ctx.derived(), expanded, line,
2267             file_name.c_str());
2268     }
2269     else {
2270         // call the corresponding pp hook function
2271         ctx.get_hooks().found_line_directive(ctx.derived(), toexpand, line,
2272             file_name.c_str());
2273     }
2274 
2275     // the queues should be empty at this point
2276     BOOST_ASSERT(unput_queue.empty());
2277     BOOST_ASSERT(pending_queue.empty());
2278 
2279     // make sure error recovery starts on the next line
2280     must_emit_line_directive = true;
2281 
2282     // diagnose possible error in detected line directive
2283     if (error != preprocess_exception::no_error) {
2284         typename ContextT::string_type msg(
2285             boost::wave::util::impl::as_string(expanded));
2286         BOOST_WAVE_THROW_VAR_CTX(ctx, preprocess_exception, error,
2287             msg.c_str(), act_pos);
2288         return;
2289     }
2290 
2291     // set new line number/filename only if ok
2292     if (!file_name.empty()) {    // reuse current file name
2293         using boost::wave::util::impl::unescape_lit;
2294         act_pos.set_file(unescape_lit(file_name).c_str());
2295     }
2296     act_pos.set_line(line);
2297     if (iter_ctx->first != iter_ctx->last)
2298     {
2299       iter_ctx->first.set_position(act_pos);
2300     }
2301 }
2302 
2303 ///////////////////////////////////////////////////////////////////////////////
2304 //
2305 //  on_error(): handle #error directives
2306 //
2307 ///////////////////////////////////////////////////////////////////////////////
2308 template <typename ContextT>
2309 inline void
2310 pp_iterator_functor<ContextT>::on_error(
2311     typename parse_tree_type::const_iterator const &begin,
2312     typename parse_tree_type::const_iterator const &end)
2313 {
2314     BOOST_ASSERT(ctx.get_if_block_status());
2315 
2316     // preprocess the given sequence into the provided list
2317     token_sequence_type expanded;
2318     get_token_value<result_type, parse_node_type> get_value;
2319 
2320     typename ref_transform_iterator_generator<
2321         get_token_value<result_type, parse_node_type>,
2322         typename parse_tree_type::const_iterator
2323     >::type first = make_ref_transform_iterator(begin, get_value);
2324 
2325 #if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0
2326     // preprocess the body of this #error message
2327     token_sequence_type toexpand;
2328 
2329     std::copy(first, make_ref_transform_iterator(end, get_value),
2330         std::inserter(toexpand, toexpand.end()));
2331 
2332     typename token_sequence_type::iterator begin2 = toexpand.begin();
2333     ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
2334                                    false, false);
2335     if (!ctx.get_hooks().found_error_directive(ctx.derived(), toexpand))
2336 #else
2337     // simply copy the body of this #error message to the issued diagnostic
2338     // message
2339     std::copy(first, make_ref_transform_iterator(end, get_value),
2340         std::inserter(expanded, expanded.end()));
2341     if (!ctx.get_hooks().found_error_directive(ctx.derived(), expanded))
2342 #endif
2343     {
2344         // report the corresponding error
2345         BOOST_WAVE_STRINGTYPE msg(boost::wave::util::impl::as_string(expanded));
2346         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, error_directive,
2347             msg.c_str(), act_pos);
2348     }
2349 }
2350 
2351 #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
2352 ///////////////////////////////////////////////////////////////////////////////
2353 //
2354 //  on_warning(): handle #warning directives
2355 //
2356 ///////////////////////////////////////////////////////////////////////////////
2357 template <typename ContextT>
2358 inline void
2359 pp_iterator_functor<ContextT>::on_warning(
2360     typename parse_tree_type::const_iterator const &begin,
2361     typename parse_tree_type::const_iterator const &end)
2362 {
2363     BOOST_ASSERT(ctx.get_if_block_status());
2364 
2365     // preprocess the given sequence into the provided list
2366     token_sequence_type expanded;
2367     get_token_value<result_type, parse_node_type> get_value;
2368 
2369     typename ref_transform_iterator_generator<
2370         get_token_value<result_type, parse_node_type>,
2371         typename parse_tree_type::const_iterator
2372     >::type first = make_ref_transform_iterator(begin, get_value);
2373 
2374 #if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0
2375     // preprocess the body of this #warning message
2376     token_sequence_type toexpand;
2377 
2378     std::copy(first, make_ref_transform_iterator(end, get_value),
2379         std::inserter(toexpand, toexpand.end()));
2380 
2381     typename token_sequence_type::iterator begin2 = toexpand.begin();
2382     ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
2383                                    false, false);
2384     if (!ctx.get_hooks().found_warning_directive(ctx.derived(), toexpand))
2385 #else
2386     // simply copy the body of this #warning message to the issued diagnostic
2387     // message
2388     std::copy(first, make_ref_transform_iterator(end, get_value),
2389         std::inserter(expanded, expanded.end()));
2390     if (!ctx.get_hooks().found_warning_directive(ctx.derived(), expanded))
2391 #endif
2392     {
2393         // report the corresponding error
2394         BOOST_WAVE_STRINGTYPE msg(boost::wave::util::impl::as_string(expanded));
2395         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, warning_directive,
2396             msg.c_str(), act_pos);
2397     }
2398 }
2399 #endif // BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
2400 
2401 ///////////////////////////////////////////////////////////////////////////////
2402 //
2403 //  on_pragma(): handle #pragma directives
2404 //
2405 ///////////////////////////////////////////////////////////////////////////////
2406 template <typename ContextT>
2407 inline bool
2408 pp_iterator_functor<ContextT>::on_pragma(
2409     typename parse_tree_type::const_iterator const &begin,
2410     typename parse_tree_type::const_iterator const &end)
2411 {
2412     using namespace boost::wave;
2413 
2414     BOOST_ASSERT(ctx.get_if_block_status());
2415 
2416     // Look at the pragma token sequence and decide, if the first token is STDC
2417     // (see C99 standard [6.10.6.2]), if it is, the sequence must _not_ be
2418     // preprocessed.
2419     token_sequence_type expanded;
2420     get_token_value<result_type, parse_node_type> get_value;
2421 
2422     typedef typename ref_transform_iterator_generator<
2423             get_token_value<result_type, parse_node_type>,
2424             typename parse_tree_type::const_iterator
2425         >::type const_tree_iterator_t;
2426 
2427     const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value);
2428     const_tree_iterator_t last = make_ref_transform_iterator(end, get_value);
2429 
2430     expanded.push_back(result_type(T_PP_PRAGMA, "#pragma", act_token.get_position()));
2431 
2432     while (first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
2433         expanded.push_back(*first++);   // skip whitespace
2434 
2435     if (first != last) {
2436         if (T_IDENTIFIER == token_id(*first) &&
2437             boost::wave::need_c99(ctx.get_language()) &&
2438             (*first).get_value() == "STDC")
2439         {
2440         // do _not_ preprocess the token sequence
2441             std::copy(first, last, std::inserter(expanded, expanded.end()));
2442         }
2443         else {
2444 #if BOOST_WAVE_PREPROCESS_PRAGMA_BODY != 0
2445             // preprocess the given tokensequence
2446             token_sequence_type toexpand;
2447 
2448             std::copy(first, last, std::inserter(toexpand, toexpand.end()));
2449 
2450             typename token_sequence_type::iterator begin2 = toexpand.begin();
2451             ctx.expand_whole_tokensequence(begin2, toexpand.end(),
2452                                            expanded, false, false);
2453 #else
2454             // do _not_ preprocess the token sequence
2455             std::copy(first, last, std::inserter(expanded, expanded.end()));
2456 #endif
2457         }
2458     }
2459     expanded.push_back(result_type(T_NEWLINE, "\n", act_token.get_position()));
2460 
2461     // the queues should be empty at this point
2462     BOOST_ASSERT(unput_queue.empty());
2463     BOOST_ASSERT(pending_queue.empty());
2464 
2465     // try to interpret the expanded #pragma body
2466     token_sequence_type pending;
2467     if (interpret_pragma(expanded, pending)) {
2468         // if there is some replacement text, insert it into the pending queue
2469         if (!pending.empty())
2470             pending_queue.splice(pending_queue.begin(), pending);
2471         return true;        // this #pragma was successfully recognized
2472     }
2473 
2474 #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
2475     // Move the resulting token sequence into the pending_queue, so it will be
2476     // returned to the caller.
2477     if (boost::wave::need_emit_pragma_directives(ctx.get_language())) {
2478         pending_queue.splice(pending_queue.begin(), expanded);
2479         return false;       // return the whole #pragma directive
2480     }
2481 #endif
2482     return true;            // skip the #pragma at all
2483 }
2484 
2485 template <typename ContextT>
2486 inline bool
2487 pp_iterator_functor<ContextT>::interpret_pragma(
2488     token_sequence_type const &pragma_body, token_sequence_type &result)
2489 {
2490     using namespace cpplexer;
2491 
2492     typename token_sequence_type::const_iterator end = pragma_body.end();
2493     typename token_sequence_type::const_iterator it = pragma_body.begin();
2494     for (++it; it != end && IS_CATEGORY(*it, WhiteSpaceTokenType); ++it)
2495         /**/;   // skip whitespace
2496 
2497     if (it == end)      // eof reached
2498         return false;
2499 
2500     return boost::wave::util::interpret_pragma(
2501         ctx.derived(), act_token, it, end, result);
2502 }
2503 
2504 ///////////////////////////////////////////////////////////////////////////////
2505 }   // namespace impl
2506 
2507 ///////////////////////////////////////////////////////////////////////////////
2508 //
2509 //  pp_iterator
2510 //
2511 //      The boost::wave::pp_iterator template is the iterator, through which
2512 //      the resulting preprocessed input stream is accessible.
2513 //
2514 ///////////////////////////////////////////////////////////////////////////////
2515 
2516 template <typename ContextT>
2517 class pp_iterator
2518 :   public boost::spirit::classic::multi_pass<
2519         boost::wave::impl::pp_iterator_functor<ContextT>,
2520         boost::wave::util::functor_input
2521     >
2522 {
2523 public:
2524     typedef boost::wave::impl::pp_iterator_functor<ContextT> input_policy_type;
2525 
2526 private:
2527     typedef
2528         boost::spirit::classic::multi_pass<input_policy_type, boost::wave::util::functor_input>
2529         base_type;
2530     typedef pp_iterator<ContextT> self_type;
2531     typedef boost::wave::util::functor_input functor_input_type;
2532 
2533 public:
2534     pp_iterator()
2535     {}
2536 
2537     template <typename IteratorT>
2538     pp_iterator(ContextT &ctx, IteratorT const &first, IteratorT const &last,
2539         typename ContextT::position_type const &pos)
2540     :   base_type(input_policy_type(ctx, first, last, pos))
2541     {}
2542 
2543     bool force_include(char const *path_, bool is_last)
2544     {
2545         bool result = this->get_functor().on_include_helper(path_, path_,
2546             false, false);
2547         if (is_last) {
2548             this->functor_input_type::
2549                 template inner<input_policy_type>::advance_input();
2550         }
2551         return result;
2552     }
2553 };
2554 
2555 ///////////////////////////////////////////////////////////////////////////////
2556 }   // namespace wave
2557 }   // namespace boost
2558 
2559 // the suffix header occurs after all of the code
2560 #ifdef BOOST_HAS_ABI_HEADERS
2561 #include BOOST_ABI_SUFFIX
2562 #endif
2563 
2564 #endif // !defined(BOOST_CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED)