LCOV - code coverage report
Current view: top level - usr/include/boost/wave/util - cpp_iterator.hpp (source / functions) Hit Total Coverage
Test: ROSE Lines: 0 834 0.0 %
Date: 2022-12-08 13:48:47 Functions: 0 42 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*=============================================================================
       2             :     Boost.Wave: A Standard compliant C++ preprocessor library
       3             : 
       4             :     Definition of the preprocessor iterator
       5             : 
       6             :     http://www.boost.org/
       7             : 
       8             :     Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
       9             :     Software License, Version 1.0. (See accompanying file
      10             :     LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      11             : =============================================================================*/
      12             : 
      13             : #if !defined(CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED)
      14             : #define CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED
      15             : 
      16             : #include <string>
      17             : #include <vector>
      18             : #include <list>
      19             : #include <cstdlib>
      20             : #include <cctype>
      21             : 
      22             : #include <boost/assert.hpp>
      23             : #include <boost/shared_ptr.hpp>
      24             : #include <boost/filesystem/path.hpp>
      25             : #include <boost/filesystem/operations.hpp>
      26             : #include <boost/lexical_cast.hpp>
      27             : #include <boost/spirit/include/classic_multi_pass.hpp>
      28             : #include <boost/spirit/include/classic_parse_tree_utils.hpp>
      29             : 
      30             : #include <boost/wave/wave_config.hpp>
      31             : #include <boost/pool/pool_alloc.hpp>
      32             : 
      33             : #include <boost/wave/util/insert_whitespace_detection.hpp>
      34             : #include <boost/wave/util/macro_helpers.hpp>
      35             : #include <boost/wave/util/cpp_macromap_utils.hpp>
      36             : #include <boost/wave/util/interpret_pragma.hpp>
      37             : #include <boost/wave/util/transform_iterator.hpp>
      38             : #include <boost/wave/util/functor_input.hpp>
      39             : #include <boost/wave/util/filesystem_compatibility.hpp>
      40             : 
      41             : #include <boost/wave/grammars/cpp_grammar_gen.hpp>
      42             : #include <boost/wave/grammars/cpp_expression_grammar_gen.hpp>
      43             : #if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0
      44             : #include <boost/wave/grammars/cpp_predef_macros_gen.hpp>
      45             : #endif
      46             : 
      47             : #include <boost/wave/whitespace_handling.hpp>
      48             : #include <boost/wave/cpp_iteration_context.hpp>
      49             : #include <boost/wave/cpp_exceptions.hpp>
      50             : #include <boost/wave/language_support.hpp>
      51             : 
      52             : // this must occur after all of the includes and before any code appears
      53             : #ifdef BOOST_HAS_ABI_HEADERS
      54             : #include BOOST_ABI_PREFIX
      55             : #endif
      56             : 
      57             : ///////////////////////////////////////////////////////////////////////////////
      58             : namespace boost {
      59             : namespace wave {
      60             : namespace util {
      61             : 
      62             : ///////////////////////////////////////////////////////////////////////////////
      63             : // retrieve the macro name from the parse tree
      64             : template <
      65             :     typename ContextT, typename ParseNodeT, typename TokenT,
      66             :     typename PositionT
      67             : >
      68             : inline bool
      69           0 : retrieve_macroname(ContextT& ctx, ParseNodeT const &node,
      70             :     boost::spirit::classic::parser_id id, TokenT &macroname, PositionT& act_pos,
      71             :     bool update_position)
      72             : {
      73           0 : ParseNodeT const *name_node = 0;
      74             : 
      75             :     using boost::spirit::classic::find_node;
      76           0 :     if (!find_node(node, id, &name_node))
      77             :     {
      78             :         // ill formed define statement (unexpected, should not happen)
      79           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_define_statement,
      80             :             "bad parse tree (unexpected)", act_pos);
      81           0 :         return false;
      82             :     }
      83             : 
      84           0 : typename ParseNodeT::children_t const &children = name_node->children;
      85             : 
      86           0 :     if (0 == children.size() ||
      87           0 :         children.front().value.begin() == children.front().value.end())
      88             :     {
      89             :         // ill formed define statement (unexpected, should not happen)
      90           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_define_statement,
      91             :             "bad parse tree (unexpected)", act_pos);
      92           0 :         return false;
      93             :     }
      94             : 
      95             : // retrieve the macro name
      96           0 :     macroname = *children.front().value.begin();
      97           0 :     if (update_position) {
      98           0 :         macroname.set_position(act_pos);
      99           0 :         act_pos.set_column(act_pos.get_column() + macroname.get_value().size());
     100             :     }
     101             :     return true;
     102             : }
     103             : 
     104             : ///////////////////////////////////////////////////////////////////////////////
     105             : // retrieve the macro parameters or the macro definition from the parse tree
     106             : template <typename ParseNodeT, typename ContainerT, typename PositionT>
     107             : inline bool
     108           0 : retrieve_macrodefinition(
     109             :     ParseNodeT const &node, boost::spirit::classic::parser_id id,
     110             :     ContainerT &macrodefinition, PositionT& act_pos, bool update_position)
     111             : {
     112             :     using namespace boost::wave;
     113             :     typedef typename ParseNodeT::const_tree_iterator const_tree_iterator;
     114             : 
     115             : // find macro parameters/macro definition inside the parse tree
     116           0 : std::pair<const_tree_iterator, const_tree_iterator> nodes;
     117             : 
     118             :     using boost::spirit::classic::get_node_range;
     119           0 :     if (get_node_range(node, id, nodes)) {
     120             :     // copy all parameters to the supplied container
     121           0 :         typename ContainerT::iterator last_nonwhite = macrodefinition.end();
     122           0 :         const_tree_iterator end = nodes.second;
     123             : 
     124           0 :         for (const_tree_iterator cit = nodes.first; cit != end; ++cit) {
     125           0 :             if ((*cit).value.begin() != (*cit).value.end()) {
     126           0 :             typename ContainerT::iterator inserted = macrodefinition.insert(
     127           0 :                 macrodefinition.end(), *(*cit).value.begin());
     128             : 
     129           0 :                 if (!IS_CATEGORY(macrodefinition.back(), WhiteSpaceTokenType) &&
     130           0 :                     T_NEWLINE != token_id(macrodefinition.back()) &&
     131           0 :                     T_EOF != token_id(macrodefinition.back()))
     132             :                 {
     133             :                     last_nonwhite = inserted;
     134             :                 }
     135             : 
     136           0 :                 if (update_position) {
     137           0 :                     (*inserted).set_position(act_pos);
     138           0 :                     act_pos.set_column(
     139           0 :                         act_pos.get_column() + (*inserted).get_value().size());
     140             :                 }
     141             :             }
     142             :         }
     143             : 
     144             :     // trim trailing whitespace (leading whitespace is trimmed by the grammar)
     145           0 :         if (last_nonwhite != macrodefinition.end()) {
     146           0 :             if (update_position) {
     147           0 :                 act_pos.set_column((*last_nonwhite).get_position().get_column() +
     148           0 :                     (*last_nonwhite).get_value().size());
     149             :             }
     150           0 :             macrodefinition.erase(++last_nonwhite, macrodefinition.end());
     151             :         }
     152             :         return true;
     153             :     }
     154             :     return false;
     155             : }
     156             : 
     157             : #if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0
     158             : ///////////////////////////////////////////////////////////////////////////////
     159             : //  add an additional predefined macro given by a string (MACRO(x)=definition)
     160             : template <typename ContextT>
     161           0 : bool add_macro_definition(ContextT &ctx, std::string macrostring,
     162             :     bool is_predefined, boost::wave::language_support language)
     163             : {
     164             :     typedef typename ContextT::token_type token_type;
     165             :     typedef typename ContextT::lexer_type lexer_type;
     166             :     typedef typename token_type::position_type position_type;
     167             :     typedef boost::wave::grammars::predefined_macros_grammar_gen<lexer_type>
     168             :         predef_macros_type;
     169             : 
     170             :     using namespace boost::wave;
     171             :     using namespace std;    // isspace is in std namespace for some systems
     172             : 
     173             : // skip leading whitespace
     174           0 : std::string::iterator begin = macrostring.begin();
     175           0 : std::string::iterator end = macrostring.end();
     176             : 
     177           0 :     while(begin != end && isspace(*begin))
     178           0 :         ++begin;
     179             : 
     180             : // parse the macro definition
     181           0 : position_type act_pos("<command line>");
     182           0 : boost::spirit::classic::tree_parse_info<lexer_type> hit =
     183             :     predef_macros_type::parse_predefined_macro(
     184             :         lexer_type(begin, end, position_type(), language), lexer_type());
     185             : 
     186           0 :     if (!hit.match || (!hit.full && T_EOF != token_id(*hit.stop))) {
     187           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_macro_definition,
     188             :             macrostring.c_str(), act_pos);
     189             :         return false;
     190             :     }
     191             : 
     192             : // retrieve the macro definition from the parse tree
     193           0 : token_type macroname;
     194           0 : std::vector<token_type> macroparameters;
     195           0 : typename ContextT::token_sequence_type macrodefinition;
     196           0 : bool has_parameters = false;
     197             : 
     198           0 :     if (!boost::wave::util::retrieve_macroname(ctx, *hit.trees.begin(),
     199             :             BOOST_WAVE_PLAIN_DEFINE_ID, macroname, act_pos, true))
     200             :         return false;
     201           0 :     has_parameters = boost::wave::util::retrieve_macrodefinition(*hit.trees.begin(),
     202             :         BOOST_WAVE_MACRO_PARAMETERS_ID, macroparameters, act_pos, true);
     203           0 :     boost::wave::util::retrieve_macrodefinition(*hit.trees.begin(),
     204             :         BOOST_WAVE_MACRO_DEFINITION_ID, macrodefinition, act_pos, true);
     205             : 
     206             :     // get rid of trailing T_EOF
     207           0 :     if (!macrodefinition.empty() && token_id(macrodefinition.back()) == T_EOF)
     208           0 :         macrodefinition.pop_back();
     209             : 
     210             : //  If no macrodefinition is given, and the macro string does not end with a
     211             : //  '=', then the macro should be defined with the value '1'
     212           0 :     if (macrodefinition.empty() && '=' != macrostring[macrostring.size()-1])
     213           0 :         macrodefinition.push_back(token_type(T_INTLIT, "1", act_pos));
     214             : 
     215             : // add the new macro to the macromap
     216             :     return ctx.add_macro_definition(macroname, has_parameters, macroparameters,
     217           0 :         macrodefinition, is_predefined);
     218             : }
     219             : #endif // BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0
     220             : 
     221             : ///////////////////////////////////////////////////////////////////////////////
     222             : }   // namespace util
     223             : 
     224             : ///////////////////////////////////////////////////////////////////////////////
     225             : //  forward declaration
     226             : template <typename ContextT> class pp_iterator;
     227             : 
     228             : namespace impl {
     229             : 
     230             : ///////////////////////////////////////////////////////////////////////////////
     231             : //
     232             : //  pp_iterator_functor
     233             : //
     234             : ///////////////////////////////////////////////////////////////////////////////
     235             : template <typename ContextT>
     236             : class pp_iterator_functor {
     237             : 
     238             : public:
     239             : // interface to the boost::spirit::classic::iterator_policies::functor_input policy
     240             :     typedef typename ContextT::token_type               result_type;
     241             : 
     242             : //  eof token
     243             :     static result_type const eof;
     244             : 
     245             : private:
     246             : // type of a token sequence
     247             :     typedef typename ContextT::token_sequence_type      token_sequence_type;
     248             : 
     249             :     typedef typename ContextT::lexer_type               lexer_type;
     250             :     typedef typename result_type::string_type           string_type;
     251             :     typedef typename result_type::position_type         position_type;
     252             :     typedef boost::wave::grammars::cpp_grammar_gen<lexer_type, token_sequence_type>
     253             :         cpp_grammar_type;
     254             : 
     255             : //  iteration context related types (an iteration context represents a current
     256             : //  position in an included file)
     257             :     typedef base_iteration_context<ContextT, lexer_type>
     258             :         base_iteration_context_type;
     259             :     typedef iteration_context<ContextT, lexer_type> iteration_context_type;
     260             : 
     261             : // parse tree related types
     262             :     typedef typename cpp_grammar_type::node_factory_type node_factory_type;
     263             :     typedef boost::spirit::classic::tree_parse_info<lexer_type, node_factory_type>
     264             :         tree_parse_info_type;
     265             :     typedef boost::spirit::classic::tree_match<lexer_type, node_factory_type>
     266             :         parse_tree_match_type;
     267             :     typedef typename parse_tree_match_type::node_t       parse_node_type;       // tree_node<node_val_data<> >
     268             :     typedef typename parse_tree_match_type::parse_node_t parse_node_value_type; // node_val_data<>
     269             :     typedef typename parse_tree_match_type::container_t  parse_tree_type;       // parse_node_type::children_t
     270             : 
     271             : public:
     272             :     template <typename IteratorT>
     273           0 :     pp_iterator_functor(ContextT &ctx_, IteratorT const &first_,
     274             :             IteratorT const &last_, typename ContextT::position_type const &pos_)
     275             :     :   ctx(ctx_),
     276           0 :         iter_ctx(new base_iteration_context_type(ctx,
     277             :                 lexer_type(first_, last_, pos_,
     278             :                     boost::wave::enable_prefer_pp_numbers(ctx.get_language())),
     279             :                 lexer_type(),
     280           0 :                 pos_.get_file().c_str()
     281             :             )),
     282             :         seen_newline(true), skipped_newline(false),
     283             :         must_emit_line_directive(false), act_pos(ctx_.get_main_pos()),
     284           0 :         whitespace(boost::wave::need_insert_whitespace(ctx.get_language()))
     285             :     {
     286           0 :         act_pos.set_file(pos_.get_file());
     287             : #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
     288           0 :         ctx_.set_current_filename(pos_.get_file().c_str());
     289             : #endif
     290           0 :         iter_ctx->emitted_lines = (unsigned int)(-1);   // force #line directive
     291           0 :     }
     292             : 
     293             : // get the next preprocessed token
     294             :     result_type const &operator()();
     295             : 
     296             : // get the last recognized token (for error processing etc.)
     297             :     result_type const &current_token() const { return act_token; }
     298             : 
     299             : protected:
     300             :     friend class pp_iterator<ContextT>;
     301             :     bool on_include_helper(char const *t, char const *s, bool is_system,
     302             :         bool include_next);
     303             : 
     304             : protected:
     305             :     result_type const &get_next_token();
     306             :     result_type const &pp_token();
     307             : 
     308             :     template <typename IteratorT>
     309             :     bool extract_identifier(IteratorT &it);
     310             :     template <typename IteratorT>
     311             :     bool ensure_is_last_on_line(IteratorT& it, bool call_hook = true);
     312             :     template <typename IteratorT>
     313             :     bool skip_to_eol_with_check(IteratorT &it, bool call_hook = true);
     314             : 
     315             :     bool pp_directive();
     316             :     template <typename IteratorT>
     317             :     bool handle_pp_directive(IteratorT &it);
     318             :     bool dispatch_directive(tree_parse_info_type const &hit,
     319             :         result_type const& found_directive,
     320             :         token_sequence_type const& found_eoltokens);
     321             :     void replace_undefined_identifiers(token_sequence_type &expanded);
     322             : 
     323             :     void on_include(string_type const &s, bool is_system, bool include_next);
     324             :     void on_include(typename parse_tree_type::const_iterator const &begin,
     325             :         typename parse_tree_type::const_iterator const &end, bool include_next);
     326             : 
     327             :     void on_define(parse_node_type const &node);
     328             :     void on_undefine(lexer_type const &it);
     329             : 
     330             :     void on_ifdef(result_type const& found_directive, lexer_type const &it);
     331             : //         typename parse_tree_type::const_iterator const &end);
     332             :     void on_ifndef(result_type const& found_directive, lexer_type const& it);
     333             : //         typename parse_tree_type::const_iterator const &end);
     334             :     void on_else();
     335             :     void on_endif();
     336             :     void on_illformed(typename result_type::string_type s);
     337             : 
     338             :     void on_line(typename parse_tree_type::const_iterator const &begin,
     339             :         typename parse_tree_type::const_iterator const &end);
     340             :     void on_if(result_type const& found_directive,
     341             :         typename parse_tree_type::const_iterator const &begin,
     342             :         typename parse_tree_type::const_iterator const &end);
     343             :     void on_elif(result_type const& found_directive,
     344             :         typename parse_tree_type::const_iterator const &begin,
     345             :         typename parse_tree_type::const_iterator const &end);
     346             :     void on_error(typename parse_tree_type::const_iterator const &begin,
     347             :         typename parse_tree_type::const_iterator const &end);
     348             : #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
     349             :     void on_warning(typename parse_tree_type::const_iterator const &begin,
     350             :         typename parse_tree_type::const_iterator const &end);
     351             : #endif
     352             :     bool on_pragma(typename parse_tree_type::const_iterator const &begin,
     353             :         typename parse_tree_type::const_iterator const &end);
     354             : 
     355             :     bool emit_line_directive();
     356             :     bool returned_from_include();
     357             : 
     358             :     bool interpret_pragma(token_sequence_type const &pragma_body,
     359             :         token_sequence_type &result);
     360             : 
     361             : private:
     362             :     ContextT &ctx;              // context, this iterator is associated with
     363             :     boost::shared_ptr<base_iteration_context_type> iter_ctx;
     364             : 
     365             :     bool seen_newline;              // needed for recognizing begin of line
     366             :     bool skipped_newline;           // a newline has been skipped since last one
     367             :     bool must_emit_line_directive;  // must emit a line directive
     368             :     result_type act_token;          // current token
     369             :     typename result_type::position_type &act_pos;   // current fileposition (references the macromap)
     370             : 
     371             :     token_sequence_type unput_queue;     // tokens to be preprocessed again
     372             :     token_sequence_type pending_queue;   // tokens already preprocessed
     373             : 
     374             :     // detect whether to insert additional whitespace in between two adjacent
     375             :     // tokens, which otherwise would form a different token type, if
     376             :     // re-tokenized
     377             :     boost::wave::util::insert_whitespace_detection whitespace;
     378             : };
     379             : 
     380             : ///////////////////////////////////////////////////////////////////////////////
     381             : //  eof token
     382             : template <typename ContextT>
     383             : typename pp_iterator_functor<ContextT>::result_type const
     384             :     pp_iterator_functor<ContextT>::eof;
     385             : 
     386             : ///////////////////////////////////////////////////////////////////////////////
     387             : //
     388             : //  returned_from_include()
     389             : //
     390             : //      Tests if it is necessary to pop the include file context (eof inside
     391             : //      a file was reached). If yes, it pops this context. Preprocessing will
     392             : //      continue with the next outer file scope.
     393             : //
     394             : ///////////////////////////////////////////////////////////////////////////////
     395             : template <typename ContextT>
     396             : inline bool
     397           0 : pp_iterator_functor<ContextT>::returned_from_include()
     398             : {
     399           0 :     if (iter_ctx->first == iter_ctx->last && ctx.get_iteration_depth() > 0) {
     400             :     // call the include policy trace function
     401             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
     402             :         ctx.get_hooks().returning_from_include_file();
     403             : #else
     404           0 :         ctx.get_hooks().returning_from_include_file(ctx.derived());
     405             : #endif
     406             : 
     407             :     // restore the previous iteration context after finishing the preprocessing
     408             :     // of the included file
     409           0 :         BOOST_WAVE_STRINGTYPE oldfile = iter_ctx->real_filename;
     410           0 :         position_type old_pos (act_pos);
     411             : 
     412             :     // if this file has include guards handle it as if it had a #pragma once
     413             : #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
     414           0 :         if (need_include_guard_detection(ctx.get_language())) {
     415           0 :             std::string guard_name;
     416           0 :             if (iter_ctx->first.has_include_guards(guard_name))
     417           0 :                 ctx.add_pragma_once_header(ctx.get_current_filename(), guard_name);
     418             :         }
     419             : #endif
     420           0 :         iter_ctx = ctx.pop_iteration_context();
     421             : 
     422           0 :         must_emit_line_directive = true;
     423           0 :         iter_ctx->emitted_lines = (unsigned int)(-1);   // force #line directive
     424           0 :         seen_newline = true;
     425             : 
     426             :     // restore current file position
     427           0 :         act_pos.set_file(iter_ctx->filename);
     428           0 :         act_pos.set_line(iter_ctx->line);
     429           0 :         act_pos.set_column(0);
     430             : 
     431             :     // restore the actual current file and directory
     432             : #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
     433             :         namespace fs = boost::filesystem;
     434           0 :         fs::path rfp(wave::util::create_path(iter_ctx->real_filename.c_str()));
     435           0 :         std::string real_filename(rfp.string());
     436           0 :         ctx.set_current_filename(real_filename.c_str());
     437             : #endif
     438           0 :         ctx.set_current_directory(iter_ctx->real_filename.c_str());
     439           0 :         ctx.set_current_relative_filename(iter_ctx->real_relative_filename.c_str());
     440             : 
     441             :     // ensure the integrity of the #if/#endif stack
     442             :     // report unbalanced #if/#endif now to make it possible to recover properly
     443           0 :         if (iter_ctx->if_block_depth != ctx.get_if_block_depth()) {
     444             :             using boost::wave::util::impl::escape_lit;
     445           0 :             BOOST_WAVE_STRINGTYPE msg(escape_lit(oldfile));
     446           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, unbalanced_if_endif,
     447             :                 msg.c_str(), old_pos);
     448             :         }
     449           0 :         return true;
     450             :     }
     451             :     return false;
     452             : }
     453             : 
     454             : ///////////////////////////////////////////////////////////////////////////////
     455             : //
     456             : //  operator()(): get the next preprocessed token
     457             : //
     458             : //      throws a preprocess_exception, if appropriate
     459             : //
     460             : ///////////////////////////////////////////////////////////////////////////////
     461             : namespace impl {
     462             : 
     463             :     //  It may be necessary to emit a #line directive either
     464             :     //  - when comments need to be preserved: if the current token is not a
     465             :     //    whitespace, except comments
     466             :     //  - when comments are to be skipped: if the current token is not a
     467             :     //    whitespace token.
     468             :     template <typename ContextT>
     469           0 :     bool consider_emitting_line_directive(ContextT const& ctx, token_id id)
     470             :     {
     471           0 :         if (need_preserve_comments(ctx.get_language()))
     472             :         {
     473           0 :             if (!IS_CATEGORY(id, EOLTokenType) && !IS_CATEGORY(id, EOFTokenType))
     474             :             {
     475             :                 return true;
     476             :             }
     477             :         }
     478           0 :         if (!IS_CATEGORY(id, WhiteSpaceTokenType) &&
     479           0 :             !IS_CATEGORY(id, EOLTokenType) && !IS_CATEGORY(id, EOFTokenType))
     480             :         {
     481             :             return true;
     482             :         }
     483             :         return false;
     484             :     }
     485             : }
     486             : 
     487             : template <typename ContextT>
     488             : inline typename pp_iterator_functor<ContextT>::result_type const &
     489           0 : pp_iterator_functor<ContextT>::operator()()
     490             : {
     491             :     using namespace boost::wave;
     492             : 
     493             :     // make sure the cwd has been initialized
     494           0 :     ctx.init_context();
     495             : 
     496             :     // loop over skip able whitespace until something significant is found
     497           0 :     bool was_seen_newline = seen_newline;
     498           0 :     bool was_skipped_newline = skipped_newline;
     499           0 :     token_id id = T_UNKNOWN;
     500             : 
     501             :     try {   // catch lexer exceptions
     502           0 :         do {
     503           0 :             if (skipped_newline) {
     504           0 :                 was_skipped_newline = true;
     505           0 :                 skipped_newline = false;
     506             :             }
     507             : 
     508             :         // get_next_token assigns result to act_token member
     509           0 :             get_next_token();
     510             : 
     511             :         // if comments shouldn't be preserved replace them with newlines
     512           0 :             id = token_id(act_token);
     513           0 :             if (!need_preserve_comments(ctx.get_language()) &&
     514           0 :                 (T_CPPCOMMENT == id || context_policies::util::ccomment_has_newline(act_token)))
     515             :             {
     516           0 :                 act_token.set_token_id(id = T_NEWLINE);
     517           0 :                 act_token.set_value("\n");
     518             :             }
     519             : 
     520           0 :             if (IS_CATEGORY(id, EOLTokenType))
     521           0 :                 seen_newline = true;
     522             : 
     523           0 :         } while (ctx.get_hooks().may_skip_whitespace(ctx.derived(), act_token, skipped_newline));
     524             :     }
     525           0 :     catch (boost::wave::cpplexer::lexing_exception const& e) {
     526             :     // dispatch any lexer exceptions to the context hook function
     527           0 :         ctx.get_hooks().throw_exception(ctx.derived(), e);
     528           0 :         return act_token;
     529             :     }
     530             : 
     531             : // restore the accumulated skipped_newline state for next invocation
     532           0 :     if (was_skipped_newline)
     533           0 :         skipped_newline = true;
     534             : 
     535             : // if there were skipped any newlines, we must emit a #line directive
     536           0 :     if ((must_emit_line_directive || (was_seen_newline && skipped_newline)) &&
     537           0 :         impl::consider_emitting_line_directive(ctx, id))
     538             :     {
     539             :     // must emit a #line directive
     540           0 :         if (need_emit_line_directives(ctx.get_language()) && emit_line_directive())
     541             :         {
     542           0 :             skipped_newline = false;
     543           0 :             ctx.get_hooks().may_skip_whitespace(ctx.derived(), act_token, skipped_newline);     // feed ws eater FSM
     544           0 :             id = token_id(act_token);
     545             :         }
     546             :     }
     547             : 
     548             : // cleanup of certain tokens required
     549           0 :     seen_newline = false;
     550           0 :     switch (id) {
     551           0 :     case T_NONREPLACABLE_IDENTIFIER:
     552           0 :         act_token.set_token_id(id = T_IDENTIFIER);
     553             :         break;
     554             : 
     555           0 :     case T_GENERATEDNEWLINE:  // was generated by emit_line_directive()
     556           0 :         act_token.set_token_id(id = T_NEWLINE);
     557           0 :         ++iter_ctx->emitted_lines;
     558           0 :         seen_newline = true;
     559           0 :         break;
     560             : 
     561           0 :     case T_NEWLINE:
     562             :     case T_CPPCOMMENT:
     563           0 :         seen_newline = true;
     564           0 :         ++iter_ctx->emitted_lines;
     565           0 :         break;
     566             : 
     567             : #if BOOST_WAVE_SUPPORT_CPP0X != 0
     568           0 :     case T_RAWSTRINGLIT:
     569           0 :         iter_ctx->emitted_lines +=
     570           0 :             context_policies::util::rawstring_count_newlines(act_token);
     571           0 :         break;
     572             : #endif
     573             : 
     574           0 :     case T_CCOMMENT:          // will come here only if whitespace is preserved
     575           0 :         iter_ctx->emitted_lines +=
     576           0 :             context_policies::util::ccomment_count_newlines(act_token);
     577           0 :         break;
     578             : 
     579           0 :     case T_PP_NUMBER:        // re-tokenize the pp-number
     580             :         {
     581           0 :             token_sequence_type rescanned;
     582             : 
     583           0 :             std::string pp_number(
     584           0 :                 util::to_string<std::string>(act_token.get_value()));
     585             : 
     586           0 :             lexer_type it = lexer_type(pp_number.begin(),
     587           0 :                 pp_number.end(), act_token.get_position(),
     588           0 :                 ctx.get_language());
     589           0 :             lexer_type end = lexer_type();
     590             : 
     591           0 :             for (/**/; it != end && T_EOF != token_id(*it); ++it)
     592           0 :                 rescanned.push_back(*it);
     593             : 
     594           0 :             pending_queue.splice(pending_queue.begin(), rescanned);
     595           0 :             act_token = pending_queue.front();
     596           0 :             id = token_id(act_token);
     597           0 :             pending_queue.pop_front();
     598             :         }
     599           0 :         break;
     600             : 
     601           0 :     case T_EOF:
     602           0 :         seen_newline = true;
     603           0 :         break;
     604             : 
     605           0 :     default:    // make sure whitespace at line begin keeps seen_newline status
     606           0 :         if (IS_CATEGORY(id, WhiteSpaceTokenType))
     607           0 :             seen_newline = was_seen_newline;
     608             :         break;
     609             :     }
     610             : 
     611           0 :     if (token_is_valid(act_token) && whitespace.must_insert(id, act_token.get_value())) {
     612             :     // must insert some whitespace into the output stream to avoid adjacent
     613             :     // tokens, which would form different (and wrong) tokens
     614           0 :         whitespace.shift_tokens(T_SPACE);
     615           0 :         pending_queue.push_front(act_token);        // push this token back
     616           0 :         return act_token = result_type(T_SPACE,
     617             :             typename result_type::string_type(" "),
     618             :             act_token.get_position());
     619             :     }
     620           0 :     whitespace.shift_tokens(id);
     621           0 :     return ctx.get_hooks().generated_token(ctx.derived(), act_token);
     622             : }
     623             : 
     624             : ///////////////////////////////////////////////////////////////////////////////
     625             : template <typename ContextT>
     626             : inline typename pp_iterator_functor<ContextT>::result_type const &
     627           0 : pp_iterator_functor<ContextT>::get_next_token()
     628             : {
     629             :     using namespace boost::wave;
     630             : 
     631             : // if there is something in the unput_queue, then return the next token from
     632             : // there (all tokens in the queue are preprocessed already)
     633           0 :     if (!pending_queue.empty() || !unput_queue.empty())
     634           0 :         return pp_token();      // return next token
     635             : 
     636             : // test for EOF, if there is a pending input context, pop it back and continue
     637             : // parsing with it
     638           0 : bool returned_from_include_file = returned_from_include();
     639             : 
     640             : // try to generate the next token
     641           0 :     if (iter_ctx->first != iter_ctx->last) {
     642             :         do {
     643             :         // If there are pending tokens in the queue, we'll have to return
     644             :         // these. This may happen from a #pragma directive, which got replaced
     645             :         // by some token sequence.
     646           0 :             if (!pending_queue.empty()) {
     647             :             util::on_exit::pop_front<token_sequence_type>
     648           0 :                 pop_front_token(pending_queue);
     649             : 
     650           0 :                 return act_token = pending_queue.front();
     651             :             }
     652             : 
     653             :         // adjust the current position (line and column)
     654           0 :         bool was_seen_newline = seen_newline || returned_from_include_file;
     655             : 
     656             :         // fetch the current token
     657           0 :             act_token = *iter_ctx->first;
     658           0 :             act_pos = act_token.get_position();
     659             : 
     660             :         // act accordingly on the current token
     661           0 :         token_id id = token_id(act_token);
     662             : 
     663           0 :             if (T_EOF == id) {
     664             :             // returned from an include file, continue with the next token
     665           0 :                 whitespace.shift_tokens(T_EOF);
     666           0 :                 ++iter_ctx->first;
     667             : 
     668             :             // now make sure this line has a newline
     669           0 :                 if ((!seen_newline || act_pos.get_column() > 1) &&
     670           0 :                     !need_single_line(ctx.get_language()))
     671             :                 {
     672           0 :                     if (need_no_newline_at_end_of_file(ctx.get_language()))
     673             :                     {
     674           0 :                         seen_newline = true;
     675           0 :                         pending_queue.push_back(
     676           0 :                             result_type(T_NEWLINE, "\n", act_pos)
     677             :                         );
     678             :                     }
     679             :                     else
     680             :                     {
     681             :                     // warn, if this file does not end with a newline
     682           0 :                         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
     683             :                             last_line_not_terminated, "", act_pos);
     684             :                     }
     685             :                 }
     686           0 :                 continue;   // if this is the main file, the while loop breaks
     687             :             }
     688           0 :             else if (T_NEWLINE == id || T_CPPCOMMENT == id) {
     689             :             // a newline is to be returned ASAP, a C++ comment too
     690             :             // (the C++ comment token includes the trailing newline)
     691           0 :                 seen_newline = true;
     692           0 :                 ++iter_ctx->first;
     693             : 
     694           0 :                 if (!ctx.get_if_block_status()) {
     695             :                 // skip this token because of the disabled #if block
     696           0 :                     whitespace.shift_tokens(id);  // whitespace controller
     697           0 :                     util::impl::call_skipped_token_hook(ctx, act_token);
     698           0 :                     continue;
     699             :                 }
     700           0 :                 return act_token;
     701             :             }
     702           0 :             seen_newline = false;
     703             : 
     704           0 :             if (was_seen_newline && pp_directive()) {
     705             :             // a pp directive was found
     706             : //                 pending_queue.push_back(result_type(T_NEWLINE, "\n", act_pos));
     707             : //                 seen_newline = true;
     708             : //                 must_emit_line_directive = true;
     709           0 :                 if (iter_ctx->first == iter_ctx->last)
     710             :                 {
     711           0 :                     seen_newline = true;
     712           0 :                     act_token = result_type(T_NEWLINE, "\n", act_pos);
     713             :                 }
     714             : 
     715             :             // loop to the next token to analyze
     716             :             // simply fall through, since the iterator was already adjusted
     717             :             // correctly
     718             :             }
     719           0 :             else if (ctx.get_if_block_status()) {
     720             :             // preprocess this token, eat up more, if appropriate, return
     721             :             // the next preprocessed token
     722           0 :                 return pp_token();
     723             :             }
     724             :             else {
     725             :             // compilation condition is false: if the current token is a
     726             :             // newline, account for it, otherwise discard the actual token and
     727             :             // try the next one
     728           0 :                 if (T_NEWLINE == token_id(act_token)) {
     729           0 :                     seen_newline = true;
     730           0 :                     must_emit_line_directive = true;
     731             :                 }
     732             : 
     733             :             // next token
     734           0 :                 util::impl::call_skipped_token_hook(ctx, act_token);
     735           0 :                 ++iter_ctx->first;
     736             :             }
     737             : 
     738           0 :         } while ((iter_ctx->first != iter_ctx->last) ||
     739           0 :                  (returned_from_include_file = returned_from_include()));
     740             : 
     741             :     // overall eof reached
     742           0 :         if (ctx.get_if_block_depth() > 0 && !need_single_line(ctx.get_language()))
     743             :         {
     744             :         // missing endif directive(s)
     745           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
     746             :                 missing_matching_endif, "", act_pos);
     747             :         }
     748             :     }
     749             :     else {
     750           0 :         act_token = eof;            // this is the last token
     751             :     }
     752             : 
     753             : //  whitespace.shift_tokens(T_EOF);     // whitespace controller
     754           0 :     return act_token;                   // return eof token
     755             : }
     756             : 
     757             : ///////////////////////////////////////////////////////////////////////////////
     758             : //
     759             : //  emit_line_directive(): emits a line directive from the act_token data
     760             : //
     761             : ///////////////////////////////////////////////////////////////////////////////
     762             : template <typename ContextT>
     763             : inline bool
     764           0 : pp_iterator_functor<ContextT>::emit_line_directive()
     765             : {
     766             :     using namespace boost::wave;
     767             : 
     768           0 : typename ContextT::position_type pos = act_token.get_position();
     769             : 
     770             : //     if (must_emit_line_directive &&
     771             : //         iter_ctx->emitted_lines+1 == act_pos.get_line() &&
     772             : //         iter_ctx->filename == act_pos.get_file())
     773             : //     {
     774             : //         must_emit_line_directive = false;
     775             : //         return false;
     776             : //     }
     777             : 
     778           0 :     if (must_emit_line_directive ||
     779           0 :         iter_ctx->emitted_lines+1 != act_pos.get_line())
     780             :     {
     781             :     // unput the current token
     782           0 :         pending_queue.push_front(act_token);
     783           0 :         pos.set_line(act_pos.get_line());
     784             : 
     785           0 :         if (iter_ctx->emitted_lines+2 == act_pos.get_line() && act_pos.get_line() != 1) {
     786             :         // prefer to output a single newline instead of the #line directive
     787             : //             whitespace.shift_tokens(T_NEWLINE);
     788           0 :             act_token = result_type(T_NEWLINE, "\n", pos);
     789             :         }
     790             :         else {
     791             :         // account for the newline emitted here
     792           0 :             act_pos.set_line(act_pos.get_line()-1);
     793           0 :             iter_ctx->emitted_lines = act_pos.get_line()-1;
     794             : 
     795           0 :         token_sequence_type pending;
     796             : 
     797           0 :             if (!ctx.get_hooks().emit_line_directive(ctx, pending, act_token))
     798             :             {
     799           0 :                 unsigned int column = 6;
     800             : 
     801             :                 // the hook did not generate anything, emit default #line
     802           0 :                 pos.set_column(1);
     803           0 :                 pending.push_back(result_type(T_PP_LINE, "#line", pos));
     804             : 
     805           0 :                 pos.set_column(column);      // account for '#line'
     806           0 :                 pending.push_back(result_type(T_SPACE, " ", pos));
     807             : 
     808             :                 // 21 is the max required size for a 64 bit integer represented as a
     809             :                 // string
     810             : 
     811           0 :                 std::string buffer = lexical_cast<std::string>(pos.get_line());
     812             : 
     813           0 :                 pos.set_column(++column);                 // account for ' '
     814           0 :                 pending.push_back(result_type(T_INTLIT, buffer.c_str(), pos));
     815           0 :                 pos.set_column(column += (unsigned int)buffer.size()); // account for <number>
     816           0 :                 pending.push_back(result_type(T_SPACE, " ", pos));
     817           0 :                 pos.set_column(++column);                 // account for ' '
     818             : 
     819           0 :                 std::string file("\"");
     820           0 :                 boost::filesystem::path filename(
     821           0 :                     wave::util::create_path(act_pos.get_file().c_str()));
     822             : 
     823             :                 using wave::util::impl::escape_lit;
     824           0 :                 file += escape_lit(wave::util::native_file_string(filename)) + "\"";
     825             : 
     826           0 :                 pending.push_back(result_type(T_STRINGLIT, file.c_str(), pos));
     827           0 :                 pos.set_column(column += (unsigned int)file.size());    // account for filename
     828           0 :                 pending.push_back(result_type(T_GENERATEDNEWLINE, "\n", pos));
     829             :             }
     830             : 
     831             :         // if there is some replacement text, insert it into the pending queue
     832           0 :             if (!pending.empty()) {
     833           0 :                 pending_queue.splice(pending_queue.begin(), pending);
     834           0 :                 act_token = pending_queue.front();
     835           0 :                 pending_queue.pop_front();
     836             :             }
     837             :         }
     838             : 
     839           0 :         must_emit_line_directive = false;     // we are now in sync
     840           0 :         return true;
     841             :     }
     842             : 
     843           0 :     must_emit_line_directive = false;         // we are now in sync
     844           0 :     return false;
     845             : }
     846             : 
     847             : ///////////////////////////////////////////////////////////////////////////////
     848             : //
     849             : //  pptoken(): return the next preprocessed token
     850             : //
     851             : ///////////////////////////////////////////////////////////////////////////////
     852             : template <typename ContextT>
     853             : inline typename pp_iterator_functor<ContextT>::result_type const &
     854           0 : pp_iterator_functor<ContextT>::pp_token()
     855             : {
     856             :     using namespace boost::wave;
     857             : 
     858           0 : token_id id = token_id(*iter_ctx->first);
     859             : 
     860             :     // eat all T_PLACEHOLDER tokens, eventually slipped through out of the
     861             :     // macro engine
     862             :     do {
     863           0 :         if (!pending_queue.empty()) {
     864             :         // if there are pending tokens in the queue, return the first one
     865           0 :             act_token = pending_queue.front();
     866           0 :             pending_queue.pop_front();
     867           0 :             act_pos = act_token.get_position();
     868             :         }
     869           0 :         else if (!unput_queue.empty()
     870           0 :               || T_IDENTIFIER == id
     871           0 :               || IS_CATEGORY(id, KeywordTokenType)
     872           0 :               || IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType)
     873           0 :               || IS_CATEGORY(id, BoolLiteralTokenType))
     874             :         {
     875             :         //  call the lexer, preprocess the required number of tokens, put them
     876             :         //  into the unput queue
     877           0 :             act_token = ctx.expand_tokensequence(iter_ctx->first,
     878           0 :                 iter_ctx->last, pending_queue, unput_queue, skipped_newline);
     879             :         }
     880             :         else {
     881             :         // simply return the next token
     882           0 :             act_token = *iter_ctx->first;
     883           0 :             ++iter_ctx->first;
     884             :         }
     885           0 :         id = token_id(act_token);
     886             : 
     887           0 :     } while (T_PLACEHOLDER == id);
     888           0 :     return act_token;
     889             : }
     890             : 
     891             : ///////////////////////////////////////////////////////////////////////////////
     892             : //
     893             : //  pp_directive(): recognize a preprocessor directive
     894             : //
     895             : ///////////////////////////////////////////////////////////////////////////////
     896             : namespace impl {
     897             : 
     898             :     // call 'found_directive' preprocessing hook
     899             :     template <typename ContextT>
     900           0 :     bool call_found_directive_hook(ContextT& ctx,
     901             :         typename ContextT::token_type const& found_directive)
     902             :     {
     903             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
     904             :         ctx.get_hooks().found_directive(found_directive);
     905             : #else
     906           0 :         if (ctx.get_hooks().found_directive(ctx.derived(), found_directive))
     907             :             return true;    // skip this directive and return newline only
     908             : #endif
     909             :         return false;
     910             :     }
     911             : 
     912             : //     // call 'skipped_token' preprocessing hook
     913             : //     template <typename ContextT>
     914             : //     void call_skipped_token_hook(ContextT& ctx,
     915             : //         typename ContextT::token_type const& skipped)
     916             : //     {
     917             : // #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
     918             : //         ctx.get_hooks().skipped_token(skipped);
     919             : // #else
     920             : //         ctx.get_hooks().skipped_token(ctx.derived(), skipped);
     921             : // #endif
     922             : //     }
     923             : 
     924             :     template <typename ContextT, typename IteratorT>
     925           0 :     bool next_token_is_pp_directive(ContextT &ctx, IteratorT &it, IteratorT const &end)
     926             :     {
     927             :         using namespace boost::wave;
     928             : 
     929           0 :         token_id id = T_UNKNOWN;
     930           0 :         for (/**/; it != end; ++it) {
     931           0 :             id = token_id(*it);
     932           0 :             if (!IS_CATEGORY(id, WhiteSpaceTokenType))
     933             :                 break;          // skip leading whitespace
     934             :             if (IS_CATEGORY(id, EOLTokenType) || IS_CATEGORY(id, EOFTokenType))
     935             :                 break;          // do not enter a new line
     936           0 :             if (T_CPPCOMMENT == id ||
     937           0 :                 context_policies::util::ccomment_has_newline(*it))
     938             :             {
     939             :                 break;
     940             :             }
     941             : 
     942             :             // this token gets skipped
     943           0 :             util::impl::call_skipped_token_hook(ctx, *it);
     944             :         }
     945           0 :         BOOST_ASSERT(it == end || id != T_UNKNOWN);
     946           0 :         return it != end && IS_CATEGORY(id, PPTokenType);
     947             :     }
     948             : 
     949             :     // verify that there isn't anything significant left on the line
     950             :     template <typename ContextT, typename IteratorT>
     951           0 :     bool pp_is_last_on_line(ContextT &ctx, IteratorT &it, IteratorT const &end,
     952             :         bool call_hook = true)
     953             :     {
     954             :         using namespace boost::wave;
     955             : 
     956             :         // this token gets skipped
     957           0 :         if (call_hook)
     958           0 :             util::impl::call_skipped_token_hook(ctx, *it);
     959             : 
     960           0 :         for (++it; it != end; ++it) {
     961           0 :         token_id id = token_id(*it);
     962             : 
     963           0 :             if (T_CPPCOMMENT == id || T_NEWLINE == id ||
     964           0 :                 context_policies::util::ccomment_has_newline(*it))
     965             :             {
     966           0 :                 if (call_hook)
     967           0 :                     util::impl::call_skipped_token_hook(ctx, *it);
     968           0 :                 ++it;           // skip eol/C/C++ comment
     969           0 :                 return true;    // no more significant tokens on this line
     970             :             }
     971             : 
     972           0 :             if (!IS_CATEGORY(id, WhiteSpaceTokenType))
     973             :                 break;
     974             : 
     975             :             // this token gets skipped
     976           0 :             if (call_hook)
     977           0 :                 util::impl::call_skipped_token_hook(ctx, *it);
     978             :         }
     979           0 :         return need_no_newline_at_end_of_file(ctx.get_language());
     980             :     }
     981             : 
     982             :     ///////////////////////////////////////////////////////////////////////////
     983             :     template <typename ContextT, typename IteratorT>
     984           0 :     bool skip_to_eol(ContextT &ctx, IteratorT &it, IteratorT const &end,
     985             :         bool call_hook = true)
     986             :     {
     987             :         using namespace boost::wave;
     988             : 
     989           0 :         for (/**/; it != end; ++it) {
     990           0 :         token_id id = token_id(*it);
     991             : 
     992           0 :             if (T_CPPCOMMENT == id || T_NEWLINE == id ||
     993           0 :                 context_policies::util::ccomment_has_newline(*it))
     994             :             {
     995             :                 // always call hook for eol
     996           0 :                 util::impl::call_skipped_token_hook(ctx, *it);
     997           0 :                 ++it;           // skip eol/C/C++ comment
     998           0 :                 return true;    // found eol
     999             :             }
    1000             : 
    1001           0 :             if (call_hook)
    1002           0 :                 util::impl::call_skipped_token_hook(ctx, *it);
    1003             :         }
    1004             :         return false;
    1005             :     }
    1006             : 
    1007             :     ///////////////////////////////////////////////////////////////////////////
    1008             :     template <typename ContextT, typename ContainerT>
    1009             :     inline void
    1010           0 :     remove_leading_whitespace(ContextT &ctx, ContainerT& c, bool call_hook = true)
    1011             :     {
    1012           0 :         typename ContainerT::iterator it = c.begin();
    1013           0 :         while (IS_CATEGORY(*it, WhiteSpaceTokenType)) {
    1014           0 :             typename ContainerT::iterator save = it++;
    1015           0 :             if (call_hook)
    1016           0 :                 util::impl::call_skipped_token_hook(ctx, *save);
    1017           0 :             c.erase(save);
    1018             :         }
    1019           0 :     }
    1020             : }
    1021             : 
    1022             : ///////////////////////////////////////////////////////////////////////////////
    1023             : template <typename ContextT>
    1024             : template <typename IteratorT>
    1025             : inline bool
    1026           0 : pp_iterator_functor<ContextT>::extract_identifier(IteratorT &it)
    1027             : {
    1028           0 :     token_id id = util::impl::skip_whitespace(it, iter_ctx->last);
    1029           0 :     if (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType) ||
    1030           0 :         IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
    1031             :         IS_CATEGORY(id, BoolLiteralTokenType))
    1032             :     {
    1033           0 :         IteratorT save = it;
    1034           0 :         if (impl::pp_is_last_on_line(ctx, save, iter_ctx->last, false))
    1035           0 :             return true;
    1036             :     }
    1037             : 
    1038             :     // report the ill formed directive
    1039           0 :     impl::skip_to_eol(ctx, it, iter_ctx->last);
    1040             : 
    1041           0 : string_type str(util::impl::as_string<string_type>(iter_ctx->first, it));
    1042             : 
    1043           0 :     seen_newline = true;
    1044           0 :     iter_ctx->first = it;
    1045           0 :     on_illformed(str);
    1046           0 :     return false;
    1047             : }
    1048             : 
    1049             : ///////////////////////////////////////////////////////////////////////////////
    1050             : template <typename ContextT>
    1051             : template <typename IteratorT>
    1052             : inline bool
    1053           0 : pp_iterator_functor<ContextT>::ensure_is_last_on_line(IteratorT& it, bool call_hook)
    1054             : {
    1055           0 :     if (!impl::pp_is_last_on_line(ctx, it, iter_ctx->last, call_hook))
    1056             :     {
    1057             :     // enable error recovery (start over with the next line)
    1058           0 :         impl::skip_to_eol(ctx, it, iter_ctx->last);
    1059             : 
    1060           0 :     string_type str(util::impl::as_string<string_type>(
    1061           0 :         iter_ctx->first, it));
    1062             : 
    1063           0 :         seen_newline = true;
    1064           0 :         iter_ctx->first = it;
    1065             : 
    1066             :     // report an invalid directive
    1067           0 :         on_illformed(str);
    1068           0 :         return false;
    1069             :     }
    1070             : 
    1071           0 :     if (it == iter_ctx->last && !need_single_line(ctx.get_language()))
    1072             :     {
    1073             :     // The line doesn't end with an eol but eof token.
    1074           0 :         seen_newline = true;    // allow to resume after warning
    1075           0 :         iter_ctx->first = it;
    1076             : 
    1077           0 :         if (!need_no_newline_at_end_of_file(ctx.get_language()))
    1078             :         {
    1079             :         // Trigger a warning that the last line was not terminated with a
    1080             :         // newline.
    1081           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1082             :                 last_line_not_terminated, "", act_pos);
    1083             :         }
    1084             : 
    1085           0 :         return false;
    1086             :     }
    1087             :     return true;
    1088             : }
    1089             : 
    1090             : template <typename ContextT>
    1091             : template <typename IteratorT>
    1092             : inline bool
    1093           0 : pp_iterator_functor<ContextT>::skip_to_eol_with_check(IteratorT &it, bool call_hook)
    1094             : {
    1095           0 :     typename ContextT::string_type value ((*it).get_value());
    1096           0 :     if (!impl::skip_to_eol(ctx, it, iter_ctx->last, call_hook) &&
    1097           0 :         !need_single_line(ctx.get_language()))
    1098             :     {
    1099             :     // The line doesn't end with an eol but eof token.
    1100           0 :         seen_newline = true;    // allow to resume after warning
    1101           0 :         iter_ctx->first = it;
    1102             : 
    1103           0 :         if (!need_no_newline_at_end_of_file(ctx.get_language()))
    1104             :         {
    1105             :         // Trigger a warning, that the last line was not terminated with a
    1106             :         // newline.
    1107           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1108             :                 last_line_not_terminated, "", act_pos);
    1109             :         }
    1110           0 :         return false;
    1111             :     }
    1112             : 
    1113             : // normal line ending reached, adjust iterator and flag
    1114           0 :     seen_newline = true;
    1115           0 :     iter_ctx->first = it;
    1116           0 :     return true;
    1117             : }
    1118             : 
    1119             : ///////////////////////////////////////////////////////////////////////////////
    1120             : //  handle_pp_directive: handle certain pp_directives
    1121             : template <typename ContextT>
    1122             : template <typename IteratorT>
    1123             : inline bool
    1124           0 : pp_iterator_functor<ContextT>::handle_pp_directive(IteratorT &it)
    1125             : {
    1126           0 :     token_id id = token_id(*it);
    1127           0 :     bool can_exit = true;
    1128           0 :     bool call_hook_in_skip = true;
    1129           0 :     if (!ctx.get_if_block_status()) {
    1130           0 :         if (IS_EXTCATEGORY(*it, PPConditionalTokenType)) {
    1131             :         // simulate the if block hierarchy
    1132           0 :             switch (id) {
    1133           0 :             case T_PP_IFDEF:        // #ifdef
    1134             :             case T_PP_IFNDEF:       // #ifndef
    1135             :             case T_PP_IF:           // #if
    1136           0 :                 ctx.enter_if_block(false);
    1137             :                 break;
    1138             : 
    1139           0 :             case T_PP_ELIF:         // #elif
    1140           0 :                 if (!ctx.get_enclosing_if_block_status()) {
    1141           0 :                     if (!ctx.enter_elif_block(false)) {
    1142             :                     // #else without matching #if
    1143           0 :                         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1144             :                             missing_matching_if, "#elif", act_pos);
    1145           0 :                         return true;  // do not analyze this directive any further
    1146             :                     }
    1147             :                 }
    1148             :                 else {
    1149             :                     can_exit = false;   // #elif is not always safe to skip
    1150             :                 }
    1151             :                 break;
    1152             : 
    1153           0 :             case T_PP_ELSE:         // #else
    1154             :             case T_PP_ENDIF:        // #endif
    1155             :                 {
    1156             :                 // handle this directive
    1157           0 :                     if (T_PP_ELSE == token_id(*it))
    1158           0 :                         on_else();
    1159             :                     else
    1160           0 :                         on_endif();
    1161             : 
    1162             :                 // make sure, there are no (non-whitespace) tokens left on
    1163             :                 // this line
    1164           0 :                     ensure_is_last_on_line(it);
    1165             : 
    1166             :                 // we skipped to the end of this line already
    1167           0 :                     seen_newline = true;
    1168           0 :                     iter_ctx->first = it;
    1169             :                 }
    1170           0 :                 return true;
    1171             : 
    1172           0 :             default:                // #something else
    1173           0 :                 on_illformed((*it).get_value());
    1174             :                 break;
    1175             :             }
    1176             :         }
    1177             :         else {
    1178           0 :             util::impl::call_skipped_token_hook(ctx, *it);
    1179           0 :             ++it;
    1180             :         }
    1181             :     }
    1182             :     else {
    1183             :     // try to handle the simple pp directives without parsing
    1184           0 :         result_type directive = *it;
    1185           0 :         bool include_next = false;
    1186           0 :         switch (id) {
    1187           0 :         case T_PP_QHEADER:        // #include "..."
    1188             : #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
    1189             :         case T_PP_QHEADER_NEXT:
    1190             : #endif
    1191           0 :             include_next = (T_PP_QHEADER_NEXT == id) ? true : false;
    1192           0 :             if (!impl::call_found_directive_hook(ctx, *it))
    1193             :             {
    1194           0 :                 string_type dir((*it).get_value());
    1195             : 
    1196             :             // make sure, there are no (non-whitespace) tokens left on
    1197             :             // this line
    1198           0 :                 if (ensure_is_last_on_line(it))
    1199             :                 {
    1200           0 :                     seen_newline = true;
    1201           0 :                     iter_ctx->first = it;
    1202           0 :                     on_include (dir, false, include_next);
    1203             :                 }
    1204           0 :                 return true;
    1205             :             }
    1206             :             break;
    1207             : 
    1208           0 :         case T_PP_HHEADER:        // #include <...>
    1209             : #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
    1210             :         case T_PP_HHEADER_NEXT:
    1211             : #endif
    1212           0 :             include_next = (T_PP_HHEADER_NEXT == id) ? true : false;
    1213           0 :             if (!impl::call_found_directive_hook(ctx, *it))
    1214             :             {
    1215           0 :                 string_type dir((*it).get_value());
    1216             : 
    1217             :             // make sure, there are no (non-whitespace) tokens left on
    1218             :             // this line
    1219           0 :                 if (ensure_is_last_on_line(it))
    1220             :                 {
    1221           0 :                     seen_newline = true;
    1222           0 :                     iter_ctx->first = it;
    1223           0 :                     on_include (dir, true, include_next);
    1224             :                 }
    1225           0 :                 return true;
    1226             :             }
    1227             :             break;
    1228             : 
    1229           0 :         case T_PP_ELSE:         // #else
    1230             :         case T_PP_ENDIF:        // #endif
    1231           0 :             if (!impl::call_found_directive_hook(ctx, *it))
    1232             :             {
    1233             :                 // handle this directive
    1234           0 :                 if (T_PP_ELSE == token_id(*it))
    1235           0 :                     on_else();
    1236             :                 else
    1237           0 :                     on_endif();
    1238             : 
    1239             :             // make sure, there are no (non-whitespace) tokens left on
    1240             :             // this line
    1241           0 :                 ensure_is_last_on_line(it);
    1242             : 
    1243             :             // we skipped to the end of this line already
    1244           0 :                 seen_newline = true;
    1245           0 :                 iter_ctx->first = it;
    1246           0 :                 return true;
    1247             :             }
    1248             :             break;
    1249             : 
    1250             :         // extract everything on this line as arguments
    1251             : //         case T_PP_IF:                   // #if
    1252             : //         case T_PP_ELIF:                 // #elif
    1253             : //         case T_PP_ERROR:                // #error
    1254             : //         case T_PP_WARNING:              // #warning
    1255             : //         case T_PP_PRAGMA:               // #pragma
    1256             : //         case T_PP_LINE:                 // #line
    1257             : //             break;
    1258             : 
    1259             :         // extract first non-whitespace token as argument
    1260           0 :         case T_PP_UNDEF:                // #undef
    1261           0 :             if (!impl::call_found_directive_hook(ctx, *it) &&
    1262             :                 extract_identifier(it))
    1263             :             {
    1264           0 :                 on_undefine(it);
    1265             :             }
    1266             :             call_hook_in_skip = false;
    1267             :             break;
    1268             : 
    1269           0 :         case T_PP_IFDEF:                // #ifdef
    1270           0 :             if (!impl::call_found_directive_hook(ctx, *it) &&
    1271             :                 extract_identifier(it))
    1272             :             {
    1273           0 :                 on_ifdef(directive, it);
    1274             :             }
    1275             :             call_hook_in_skip = false;
    1276             :             break;
    1277             : 
    1278           0 :         case T_PP_IFNDEF:               // #ifndef
    1279           0 :             if (!impl::call_found_directive_hook(ctx, *it) &&
    1280             :                 extract_identifier(it))
    1281             :             {
    1282           0 :                 on_ifndef(directive, it);
    1283             :             }
    1284             :             call_hook_in_skip = false;
    1285             :             break;
    1286             : 
    1287             : #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
    1288             : //         case T_MSEXT_PP_REGION:         // #region ...
    1289             : //             break;
    1290             : //
    1291             : //         case T_MSEXT_PP_ENDREGION:      // #endregion
    1292             : //             break;
    1293             : #endif
    1294             : 
    1295             :         default:
    1296             :             can_exit = false;
    1297             :             break;
    1298             :         }
    1299             :     }
    1300             : 
    1301             : // start over with the next line, if only possible
    1302           0 :     if (can_exit) {
    1303           0 :         skip_to_eol_with_check(it, call_hook_in_skip);
    1304           0 :         return true;    // may be safely ignored
    1305             :     }
    1306             :     return false;   // do not ignore this pp directive
    1307             : }
    1308             : 
    1309             : ///////////////////////////////////////////////////////////////////////////////
    1310             : //  pp_directive(): recognize a preprocessor directive
    1311             : template <typename ContextT>
    1312             : inline bool
    1313           0 : pp_iterator_functor<ContextT>::pp_directive()
    1314             : {
    1315             :     using namespace cpplexer;
    1316             : 
    1317             : // test, if the next non-whitespace token is a pp directive
    1318           0 : lexer_type it = iter_ctx->first;
    1319             : 
    1320           0 :     if (!impl::next_token_is_pp_directive(ctx, it, iter_ctx->last)) {
    1321             :     // skip null pp directive (no need to do it via the parser)
    1322           0 :         if (it != iter_ctx->last && T_POUND == BASE_TOKEN(token_id(*it))) {
    1323           0 :             if (impl::pp_is_last_on_line(ctx, it, iter_ctx->last)) {
    1324             :             // start over with the next line
    1325           0 :                 seen_newline = true;
    1326           0 :                 iter_ctx->first = it;
    1327           0 :                 return true;
    1328             :             }
    1329           0 :             else if (ctx.get_if_block_status()) {
    1330             :             // report invalid pp directive
    1331           0 :                 impl::skip_to_eol(ctx, it, iter_ctx->last);
    1332           0 :                 seen_newline = true;
    1333             : 
    1334           0 :                 string_type str(boost::wave::util::impl::as_string<string_type>(
    1335           0 :                     iter_ctx->first, it));
    1336             : 
    1337           0 :             token_sequence_type faulty_line;
    1338             : 
    1339           0 :                 for (/**/; iter_ctx->first != it; ++iter_ctx->first)
    1340           0 :                     faulty_line.push_back(*iter_ctx->first);
    1341             : 
    1342           0 :                 token_sequence_type pending;
    1343           0 :                 if (ctx.get_hooks().found_unknown_directive(ctx, faulty_line, pending))
    1344             :                 {
    1345             :                 // if there is some replacement text, insert it into the pending queue
    1346             :                     if (!pending.empty())
    1347             :                         pending_queue.splice(pending_queue.begin(), pending);
    1348             :                     return true;
    1349             :                 }
    1350             : 
    1351             :                 // default behavior is to throw an exception
    1352           0 :                 on_illformed(str);
    1353             :             }
    1354             :         }
    1355             : 
    1356             :     // this line does not contain a pp directive, so simply return
    1357           0 :         return false;
    1358             :     }
    1359             : 
    1360             : // found eof
    1361           0 :     if (it == iter_ctx->last)
    1362             :         return false;
    1363             : 
    1364             : // ignore/handle all pp directives not related to conditional compilation while
    1365             : // if block status is false
    1366           0 :     if (handle_pp_directive(it)) {
    1367             :         // we may skip pp directives only if the current if block status is
    1368             :         // false or if it was a #include directive we could handle directly
    1369             :         return true;    //  the pp directive has been handled/skipped
    1370             :     }
    1371             : 
    1372             : // found a pp directive, so try to identify it, start with the pp_token
    1373           0 : bool found_eof = false;
    1374           0 : result_type found_directive;
    1375           0 : token_sequence_type found_eoltokens;
    1376             : 
    1377           0 : tree_parse_info_type hit = cpp_grammar_type::parse_cpp_grammar(
    1378           0 :     it, iter_ctx->last, act_pos, found_eof, found_directive, found_eoltokens);
    1379             : 
    1380           0 :     if (hit.match) {
    1381             :     // position the iterator past the matched sequence to allow
    1382             :     // resynchronization, if an error occurs
    1383           0 :         iter_ctx->first = hit.stop;
    1384           0 :         seen_newline = true;
    1385           0 :         must_emit_line_directive = true;
    1386             : 
    1387             :     // found a valid pp directive, dispatch to the correct function to handle
    1388             :     // the found pp directive
    1389           0 :     bool result = dispatch_directive (hit, found_directive, found_eoltokens);
    1390             : 
    1391           0 :         if (found_eof && !need_single_line(ctx.get_language()) &&
    1392           0 :             !need_no_newline_at_end_of_file(ctx.get_language()))
    1393             :         {
    1394             :         // The line was terminated with an end of file token.
    1395             :         // So trigger a warning, that the last line was not terminated with a
    1396             :         // newline.
    1397           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1398             :                 last_line_not_terminated, "", act_pos);
    1399             :         }
    1400           0 :         return result;
    1401             :     }
    1402           0 :     else if (token_id(found_directive) != T_EOF) {
    1403             :     // recognized invalid directive
    1404           0 :         impl::skip_to_eol(ctx, it, iter_ctx->last);
    1405           0 :         seen_newline = true;
    1406             : 
    1407           0 :         string_type str(boost::wave::util::impl::as_string<string_type>(
    1408           0 :             iter_ctx->first, it));
    1409           0 :         iter_ctx->first = it;
    1410             : 
    1411             :     // report the ill formed directive
    1412           0 :         on_illformed(str);
    1413             :     }
    1414             :     return false;
    1415             : }
    1416             : 
    1417             : ///////////////////////////////////////////////////////////////////////////////
    1418             : //
    1419             : //  dispatch_directive(): dispatch a recognized preprocessor directive
    1420             : //
    1421             : ///////////////////////////////////////////////////////////////////////////////
    1422             : template <typename ContextT>
    1423             : inline bool
    1424           0 : pp_iterator_functor<ContextT>::dispatch_directive(
    1425             :     tree_parse_info_type const &hit, result_type const& found_directive,
    1426             :     token_sequence_type const& found_eoltokens)
    1427             : {
    1428             :     using namespace cpplexer;
    1429             : 
    1430             :     typedef typename parse_tree_type::const_iterator const_child_iterator_t;
    1431             : 
    1432             : // this iterator points to the root node of the parse tree
    1433           0 : const_child_iterator_t begin = hit.trees.begin();
    1434             : 
    1435             : // decide, which preprocessor directive was found
    1436           0 : parse_tree_type const &root = (*begin).children;
    1437           0 : parse_node_value_type const &nodeval = get_first_leaf(*root.begin()).value;
    1438             : //long node_id = nodeval.id().to_long();
    1439             : 
    1440           0 : const_child_iterator_t begin_child_it = (*root.begin()).children.begin();
    1441           0 : const_child_iterator_t end_child_it = (*root.begin()).children.end();
    1442             : 
    1443           0 : token_id id = token_id(found_directive);
    1444             : 
    1445             :     // call preprocessing hook
    1446           0 :     if (impl::call_found_directive_hook(ctx, found_directive))
    1447             :         return true;    // skip this directive and return newline only
    1448             : 
    1449           0 :     switch (id) {
    1450             : //     case T_PP_QHEADER:      // #include "..."
    1451             : // #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
    1452             : //     case T_PP_QHEADER_NEXT: // #include_next "..."
    1453             : // #endif
    1454             : //         on_include ((*nodeval.begin()).get_value(), false,
    1455             : //             T_PP_QHEADER_NEXT == id);
    1456             : //         break;
    1457             : 
    1458             : //     case T_PP_HHEADER:      // #include <...>
    1459             : // #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
    1460             : //     case T_PP_HHEADER_NEXT: // #include_next <...>
    1461             : // #endif
    1462             : //         on_include ((*nodeval.begin()).get_value(), true,
    1463             : //             T_PP_HHEADER_NEXT == id);
    1464             : //         break;
    1465             : 
    1466           0 :     case T_PP_INCLUDE:      // #include ...
    1467             : #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
    1468             :     case T_PP_INCLUDE_NEXT: // #include_next ...
    1469             : #endif
    1470           0 :         on_include (begin_child_it, end_child_it, T_PP_INCLUDE_NEXT == id);
    1471             :         break;
    1472             : 
    1473           0 :     case T_PP_DEFINE:       // #define
    1474           0 :         on_define (*begin);
    1475             :         break;
    1476             : 
    1477             : //     case T_PP_UNDEF:        // #undef
    1478             : //         on_undefine(*nodeval.begin());
    1479             : //         break;
    1480             : //
    1481             : //     case T_PP_IFDEF:        // #ifdef
    1482             : //         on_ifdef(found_directive, begin_child_it, end_child_it);
    1483             : //         break;
    1484             : //
    1485             : //     case T_PP_IFNDEF:       // #ifndef
    1486             : //         on_ifndef(found_directive, begin_child_it, end_child_it);
    1487             : //         break;
    1488             : 
    1489           0 :     case T_PP_IF:           // #if
    1490           0 :         on_if(found_directive, begin_child_it, end_child_it);
    1491             :         break;
    1492             : 
    1493           0 :     case T_PP_ELIF:         // #elif
    1494           0 :         on_elif(found_directive, begin_child_it, end_child_it);
    1495             :         break;
    1496             : 
    1497             : //     case T_PP_ELSE:         // #else
    1498             : //         on_else();
    1499             : //         break;
    1500             : 
    1501             : //     case T_PP_ENDIF:        // #endif
    1502             : //         on_endif();
    1503             : //         break;
    1504             : 
    1505           0 :     case T_PP_LINE:         // #line
    1506           0 :         on_line(begin_child_it, end_child_it);
    1507             :         break;
    1508             : 
    1509           0 :     case T_PP_ERROR:        // #error
    1510           0 :         on_error(begin_child_it, end_child_it);
    1511             :         break;
    1512             : 
    1513             : #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
    1514           0 :     case T_PP_WARNING:      // #warning
    1515           0 :         on_warning(begin_child_it, end_child_it);
    1516             :         break;
    1517             : #endif
    1518             : 
    1519           0 :     case T_PP_PRAGMA:       // #pragma
    1520           0 :         return on_pragma(begin_child_it, end_child_it);
    1521             : 
    1522             : #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
    1523             :     case T_MSEXT_PP_REGION:
    1524             :     case T_MSEXT_PP_ENDREGION:
    1525             :         break;              // ignore these
    1526             : #endif
    1527             : 
    1528           0 :     default:                // #something else
    1529           0 :         on_illformed((*nodeval.begin()).get_value());
    1530             : 
    1531             :         // if we end up here, we have been instructed to ignore the error, so
    1532             :         // we simply copy the whole construct to the output
    1533             :         {
    1534           0 :             token_sequence_type expanded;
    1535             :             get_token_value<result_type, parse_node_type> get_value;
    1536             : 
    1537           0 :             std::copy(make_ref_transform_iterator(begin_child_it, get_value),
    1538             :                 make_ref_transform_iterator(end_child_it, get_value),
    1539             :                 std::inserter(expanded, expanded.end()));
    1540           0 :             pending_queue.splice(pending_queue.begin(), expanded);
    1541             :         }
    1542           0 :         break;
    1543             :     }
    1544             : 
    1545             :     // properly skip trailing newline for all directives
    1546           0 :     typename token_sequence_type::const_iterator eol = found_eoltokens.begin();
    1547           0 :     impl::skip_to_eol(ctx, eol, found_eoltokens.end());
    1548           0 :     return true;    // return newline only
    1549             : }
    1550             : 
    1551             : ///////////////////////////////////////////////////////////////////////////////
    1552             : //
    1553             : //  on_include: handle #include <...> or #include "..." directives
    1554             : //
    1555             : ///////////////////////////////////////////////////////////////////////////////
    1556             : template <typename ContextT>
    1557             : inline void
    1558           0 : pp_iterator_functor<ContextT>::on_include (string_type const &s,
    1559             :     bool is_system, bool include_next)
    1560             : {
    1561           0 :     BOOST_ASSERT(ctx.get_if_block_status());
    1562             : 
    1563             : // strip quotes first, extract filename
    1564           0 : typename string_type::size_type pos_end = s.find_last_of(is_system ? '>' : '\"');
    1565             : 
    1566           0 :     if (string_type::npos == pos_end) {
    1567           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
    1568             :             s.c_str(), act_pos);
    1569           0 :         return;
    1570             :     }
    1571             : 
    1572           0 : typename string_type::size_type pos_begin =
    1573             :     s.find_last_of(is_system ? '<' : '\"', pos_end-1);
    1574             : 
    1575           0 :     if (string_type::npos == pos_begin) {
    1576           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
    1577             :             s.c_str(), act_pos);
    1578           0 :         return;
    1579             :     }
    1580             : 
    1581           0 : std::string file_token(s.substr(pos_begin, pos_end-pos_begin+1).c_str());
    1582           0 : std::string file_path(s.substr(pos_begin+1, pos_end-pos_begin-1).c_str());
    1583             : 
    1584             : // finally include the file
    1585           0 :     on_include_helper(file_token.c_str(), file_path.c_str(), is_system,
    1586             :         include_next);
    1587             : }
    1588             : 
    1589             : template <typename ContextT>
    1590             : inline bool
    1591           0 : pp_iterator_functor<ContextT>::on_include_helper (char const *f, char const *s,
    1592             :     bool is_system, bool include_next)
    1593             : {
    1594             :     namespace fs = boost::filesystem;
    1595             : 
    1596             : // try to locate the given file, searching through the include path lists
    1597           0 : std::string file_path(s);
    1598           0 : std::string dir_path;
    1599             : #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
    1600           0 : char const *current_name = include_next ? iter_ctx->real_filename.c_str() : 0;
    1601             : #else
    1602             : char const *current_name = 0;   // never try to match current file name
    1603             : #endif
    1604             : 
    1605             : // call the 'found_include_directive' hook function
    1606             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    1607             :     ctx.get_hooks().found_include_directive(f, include_next);
    1608             : #else
    1609           0 :     if (ctx.get_hooks().found_include_directive(ctx.derived(), f, include_next))
    1610             :         return true;    // client returned false: skip file to include
    1611             : #endif
    1612             : 
    1613           0 :     file_path = util::impl::unescape_lit(file_path);
    1614           0 :     std::string native_path_str;
    1615             : 
    1616           0 :     if (!ctx.get_hooks().locate_include_file(ctx, file_path, is_system,
    1617             :             current_name, dir_path, native_path_str))
    1618             :     {
    1619           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_file,
    1620             :             file_path.c_str(), act_pos);
    1621             :         return false;
    1622             :     }
    1623             : 
    1624             : // test, if this file is known through a #pragma once directive
    1625             : #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
    1626           0 :     if (!ctx.has_pragma_once(native_path_str))
    1627             : #endif
    1628             :     {
    1629             :     // the new include file determines the actual current directory
    1630           0 :         ctx.set_current_directory(native_path_str.c_str());
    1631             : 
    1632             :     // preprocess the opened file
    1633           0 :     boost::shared_ptr<base_iteration_context_type> new_iter_ctx (
    1634           0 :         new iteration_context_type(ctx, native_path_str.c_str(), act_pos,
    1635           0 :             boost::wave::enable_prefer_pp_numbers(ctx.get_language()),
    1636             :             is_system ? base_iteration_context_type::system_header :
    1637             :                 base_iteration_context_type::user_header));
    1638             : 
    1639             :     // call the include policy trace function
    1640             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    1641             :         ctx.get_hooks().opened_include_file(dir_path, file_path,
    1642             :             ctx.get_iteration_depth(), is_system);
    1643             : #else
    1644           0 :         ctx.get_hooks().opened_include_file(ctx.derived(), dir_path, file_path,
    1645             :             is_system);
    1646             : #endif
    1647             : 
    1648             :     // store current file position
    1649           0 :         iter_ctx->real_relative_filename = ctx.get_current_relative_filename().c_str();
    1650           0 :         iter_ctx->filename = act_pos.get_file();
    1651           0 :         iter_ctx->line = act_pos.get_line();
    1652           0 :         iter_ctx->if_block_depth = ctx.get_if_block_depth();
    1653           0 :         iter_ctx->emitted_lines = (unsigned int)(-1);   // force #line directive
    1654             : 
    1655             :     // push the old iteration context onto the stack and continue with the new
    1656           0 :         ctx.push_iteration_context(act_pos, iter_ctx);
    1657           0 :         iter_ctx = new_iter_ctx;
    1658           0 :         seen_newline = true;        // fake a newline to trigger pp_directive
    1659           0 :         must_emit_line_directive = true;
    1660             : 
    1661           0 :         act_pos.set_file(iter_ctx->filename);  // initialize file position
    1662             : #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
    1663           0 :         fs::path rfp(wave::util::create_path(iter_ctx->real_filename.c_str()));
    1664           0 :         std::string real_filename(rfp.string());
    1665           0 :         ctx.set_current_filename(real_filename.c_str());
    1666             : #endif
    1667             : 
    1668           0 :         ctx.set_current_relative_filename(dir_path.c_str());
    1669           0 :         iter_ctx->real_relative_filename = dir_path.c_str();
    1670             : 
    1671           0 :         act_pos.set_line(iter_ctx->line);
    1672           0 :         act_pos.set_column(0);
    1673             :     }
    1674             :     return true;
    1675             : }
    1676             : 
    1677             : ///////////////////////////////////////////////////////////////////////////////
    1678             : //
    1679             : //  on_include(): handle #include ... directives
    1680             : //
    1681             : ///////////////////////////////////////////////////////////////////////////////
    1682             : 
    1683             : namespace impl {
    1684             : 
    1685             :     // trim all whitespace from the beginning and the end of the given string
    1686             :     template <typename StringT>
    1687             :     inline StringT
    1688           0 :     trim_whitespace(StringT const &s)
    1689             :     {
    1690             :         typedef typename StringT::size_type size_type;
    1691             : 
    1692           0 :         size_type first = s.find_first_not_of(" \t\v\f");
    1693           0 :         if (StringT::npos == first)
    1694           0 :             return StringT();
    1695           0 :         size_type last = s.find_last_not_of(" \t\v\f");
    1696           0 :         return s.substr(first, last-first+1);
    1697             :     }
    1698             : }
    1699             : 
    1700             : template <typename ContextT>
    1701             : inline void
    1702           0 : pp_iterator_functor<ContextT>::on_include(
    1703             :     typename parse_tree_type::const_iterator const &begin,
    1704             :     typename parse_tree_type::const_iterator const &end, bool include_next)
    1705             : {
    1706           0 :     BOOST_ASSERT(ctx.get_if_block_status());
    1707             : 
    1708             : // preprocess the given token sequence (the body of the #include directive)
    1709             : get_token_value<result_type, parse_node_type> get_value;
    1710           0 : token_sequence_type expanded;
    1711           0 : token_sequence_type toexpand;
    1712             : 
    1713           0 :     std::copy(make_ref_transform_iterator(begin, get_value),
    1714             :         make_ref_transform_iterator(end, get_value),
    1715             :         std::inserter(toexpand, toexpand.end()));
    1716             : 
    1717           0 :     typename token_sequence_type::iterator begin2 = toexpand.begin();
    1718           0 :     ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
    1719             :         false);
    1720             : 
    1721             : // now, include the file
    1722           0 : string_type s (impl::trim_whitespace(boost::wave::util::impl::as_string(expanded)));
    1723           0 : bool is_system = '<' == s[0] && '>' == s[s.size()-1];
    1724             : 
    1725           0 :     if (!is_system && !('\"' == s[0] && '\"' == s[s.size()-1])) {
    1726             :     // should resolve into something like <...> or "..."
    1727           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
    1728             :             s.c_str(), act_pos);
    1729           0 :         return;
    1730             :     }
    1731           0 :     on_include(s, is_system, include_next);
    1732             : }
    1733             : 
    1734             : ///////////////////////////////////////////////////////////////////////////////
    1735             : //
    1736             : //  on_define(): handle #define directives
    1737             : //
    1738             : ///////////////////////////////////////////////////////////////////////////////
    1739             : 
    1740             : template <typename ContextT>
    1741             : inline void
    1742           0 : pp_iterator_functor<ContextT>::on_define (parse_node_type const &node)
    1743             : {
    1744           0 :     BOOST_ASSERT(ctx.get_if_block_status());
    1745             : 
    1746             : // retrieve the macro definition from the parse tree
    1747           0 : result_type macroname;
    1748           0 : std::vector<result_type> macroparameters;
    1749           0 : token_sequence_type macrodefinition;
    1750           0 : bool has_parameters = false;
    1751           0 : position_type pos(act_token.get_position());
    1752             : 
    1753           0 :     if (!boost::wave::util::retrieve_macroname(ctx, node,
    1754             :             BOOST_WAVE_PLAIN_DEFINE_ID, macroname, pos, false))
    1755           0 :         return;
    1756           0 :     has_parameters = boost::wave::util::retrieve_macrodefinition(node,
    1757             :         BOOST_WAVE_MACRO_PARAMETERS_ID, macroparameters, pos, false);
    1758           0 :     boost::wave::util::retrieve_macrodefinition(node,
    1759             :         BOOST_WAVE_MACRO_DEFINITION_ID, macrodefinition, pos, false);
    1760             : 
    1761           0 :     if (has_parameters) {
    1762             : #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1763           0 :         if (boost::wave::need_variadics(ctx.get_language())) {
    1764             :         // test whether ellipsis are given, and if yes, if these are placed as the
    1765             :         // last argument, test if __VA_ARGS__ is used as a macro parameter name
    1766             :             using namespace cpplexer;
    1767             :             typedef typename std::vector<result_type>::iterator
    1768             :                 parameter_iterator_t;
    1769             : 
    1770           0 :             bool seen_ellipses = false;
    1771           0 :             parameter_iterator_t end = macroparameters.end();
    1772           0 :             for (parameter_iterator_t pit = macroparameters.begin();
    1773           0 :                 pit != end; ++pit)
    1774             :             {
    1775           0 :                 if (seen_ellipses) {
    1776             :                 // ellipses are not the last given formal argument
    1777           0 :                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1778             :                         bad_define_statement, macroname.get_value().c_str(),
    1779             :                         (*pit).get_position());
    1780           0 :                     return;
    1781             :                 }
    1782           0 :                 if (T_ELLIPSIS == token_id(*pit))
    1783           0 :                     seen_ellipses = true;
    1784             : 
    1785             :                 // can't use __VA_ARGS__ as a argument name
    1786           0 :                 if ("__VA_ARGS__" == (*pit).get_value()) {
    1787           0 :                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1788             :                         bad_define_statement_va_args,
    1789             :                         macroname.get_value().c_str(), (*pit).get_position());
    1790             :                     return;
    1791             :                 }
    1792             :             }
    1793             : 
    1794             :         // if there wasn't an ellipsis, then there shouldn't be a __VA_ARGS__
    1795             :         // placeholder in the definition too [C99 Standard 6.10.3.5]
    1796           0 :             if (!seen_ellipses) {
    1797             :                 typedef typename token_sequence_type::iterator definition_iterator_t;
    1798             : 
    1799           0 :                 bool seen_va_args = false;
    1800           0 :                 definition_iterator_t pend = macrodefinition.end();
    1801           0 :                 for (definition_iterator_t dit = macrodefinition.begin();
    1802           0 :                      dit != pend; ++dit)
    1803             :                 {
    1804           0 :                     if (T_IDENTIFIER == token_id(*dit) &&
    1805           0 :                         "__VA_ARGS__" == (*dit).get_value())
    1806             :                     {
    1807             :                         seen_va_args = true;
    1808             :                     }
    1809             :                 }
    1810           0 :                 if (seen_va_args) {
    1811             :                 // must not have seen __VA_ARGS__ placeholder
    1812           0 :                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1813             :                         bad_define_statement_va_args,
    1814             :                         macroname.get_value().c_str(), act_token.get_position());
    1815           0 :                     return;
    1816             :                 }
    1817             :             }
    1818             :         }
    1819             :         else
    1820             : #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
    1821             :         {
    1822             :         // test, that there is no T_ELLIPSES given
    1823             :             using namespace cpplexer;
    1824             :             typedef typename std::vector<result_type>::iterator
    1825             :                 parameter_iterator_t;
    1826             : 
    1827           0 :             parameter_iterator_t end = macroparameters.end();
    1828           0 :             for (parameter_iterator_t pit = macroparameters.begin();
    1829           0 :                 pit != end; ++pit)
    1830             :             {
    1831           0 :                 if (T_ELLIPSIS == token_id(*pit)) {
    1832             :                 // if variadics are disabled, no ellipses should be given
    1833           0 :                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    1834             :                         bad_define_statement, macroname.get_value().c_str(),
    1835             :                         (*pit).get_position());
    1836           0 :                     return;
    1837             :                 }
    1838             :             }
    1839             :         }
    1840             :     }
    1841             : 
    1842             : // add the new macro to the macromap
    1843           0 :     ctx.add_macro_definition(macroname, has_parameters, macroparameters,
    1844             :         macrodefinition);
    1845             : }
    1846             : 
    1847             : ///////////////////////////////////////////////////////////////////////////////
    1848             : //
    1849             : //  on_undefine(): handle #undef directives
    1850             : //
    1851             : ///////////////////////////////////////////////////////////////////////////////
    1852             : template <typename ContextT>
    1853             : inline void
    1854             : pp_iterator_functor<ContextT>::on_undefine (lexer_type const &it)
    1855             : {
    1856             :     BOOST_ASSERT(ctx.get_if_block_status());
    1857             : 
    1858             : // retrieve the macro name to undefine from the parse tree
    1859             :     ctx.remove_macro_definition((*it).get_value()); // throws for predefined macros
    1860             : }
    1861             : 
    1862             : ///////////////////////////////////////////////////////////////////////////////
    1863             : //
    1864             : //  on_ifdef(): handle #ifdef directives
    1865             : //
    1866             : ///////////////////////////////////////////////////////////////////////////////
    1867             : template <typename ContextT>
    1868             : inline void
    1869           0 : pp_iterator_functor<ContextT>::on_ifdef(
    1870             :     result_type const& found_directive, lexer_type const &it)
    1871             : //     typename parse_tree_type::const_iterator const &it)
    1872             : //     typename parse_tree_type::const_iterator const &end)
    1873             : {
    1874             : // get_token_value<result_type, parse_node_type> get_value;
    1875             : // token_sequence_type toexpand;
    1876             : //
    1877             : //     std::copy(make_ref_transform_iterator((*begin).children.begin(), get_value),
    1878             : //         make_ref_transform_iterator((*begin).children.end(), get_value),
    1879             : //         std::inserter(toexpand, toexpand.end()));
    1880             : 
    1881           0 : bool is_defined = false;
    1882           0 : token_sequence_type directive;
    1883             : 
    1884           0 :     directive.insert(directive.end(), *it);
    1885             : 
    1886             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    1887             :     is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end());
    1888             :     ctx.get_hooks().evaluated_conditional_expression(directive, is_defined);
    1889             : #else
    1890           0 :     do {
    1891           0 :         is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end());
    1892           0 :     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
    1893             :              found_directive, directive, is_defined));
    1894             : #endif
    1895           0 :     ctx.enter_if_block(is_defined);
    1896           0 : }
    1897             : 
    1898             : ///////////////////////////////////////////////////////////////////////////////
    1899             : //
    1900             : //  on_ifndef(): handle #ifndef directives
    1901             : //
    1902             : ///////////////////////////////////////////////////////////////////////////////
    1903             : template <typename ContextT>
    1904             : inline void
    1905           0 : pp_iterator_functor<ContextT>::on_ifndef(
    1906             :     result_type const& found_directive, lexer_type const &it)
    1907             : //     typename parse_tree_type::const_iterator const &it)
    1908             : //     typename parse_tree_type::const_iterator const &end)
    1909             : {
    1910             : // get_token_value<result_type, parse_node_type> get_value;
    1911             : // token_sequence_type toexpand;
    1912             : //
    1913             : //     std::copy(make_ref_transform_iterator((*begin).children.begin(), get_value),
    1914             : //         make_ref_transform_iterator((*begin).children.end(), get_value),
    1915             : //         std::inserter(toexpand, toexpand.end()));
    1916             : 
    1917           0 : bool is_defined = false;
    1918           0 : token_sequence_type directive;
    1919             : 
    1920           0 :     directive.insert(directive.end(), *it);
    1921             : 
    1922             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    1923             :     is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end());
    1924             :     ctx.get_hooks().evaluated_conditional_expression(directive, is_defined);
    1925             : #else
    1926           0 :     do {
    1927           0 :         is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end());
    1928           0 :     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
    1929             :              found_directive, directive, is_defined));
    1930             : #endif
    1931           0 :     ctx.enter_if_block(!is_defined);
    1932           0 : }
    1933             : 
    1934             : ///////////////////////////////////////////////////////////////////////////////
    1935             : //
    1936             : //  on_else(): handle #else directives
    1937             : //
    1938             : ///////////////////////////////////////////////////////////////////////////////
    1939             : template <typename ContextT>
    1940             : inline void
    1941             : pp_iterator_functor<ContextT>::on_else()
    1942             : {
    1943             :     if (!ctx.enter_else_block()) {
    1944             :     // #else without matching #if
    1945             :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
    1946             :             "#else", act_pos);
    1947             :     }
    1948             : }
    1949             : 
    1950             : ///////////////////////////////////////////////////////////////////////////////
    1951             : //
    1952             : //  on_endif(): handle #endif directives
    1953             : //
    1954             : ///////////////////////////////////////////////////////////////////////////////
    1955             : template <typename ContextT>
    1956             : inline void
    1957             : pp_iterator_functor<ContextT>::on_endif()
    1958             : {
    1959             :     if (!ctx.exit_if_block()) {
    1960             :     // #endif without matching #if
    1961             :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
    1962             :             "#endif", act_pos);
    1963             :     }
    1964             : }
    1965             : 
    1966             : ///////////////////////////////////////////////////////////////////////////////
    1967             : //  replace all remaining (== undefined) identifiers with an integer literal '0'
    1968             : template <typename ContextT>
    1969             : inline void
    1970           0 : pp_iterator_functor<ContextT>::replace_undefined_identifiers(
    1971             :     token_sequence_type &expanded)
    1972             : {
    1973           0 :     typename token_sequence_type::iterator exp_end = expanded.end();
    1974           0 :     for (typename token_sequence_type::iterator exp_it = expanded.begin();
    1975           0 :          exp_it != exp_end; ++exp_it)
    1976             :     {
    1977             :         using namespace boost::wave;
    1978             : 
    1979           0 :         token_id id = token_id(*exp_it);
    1980           0 :         if (IS_CATEGORY(id, IdentifierTokenType) ||
    1981             :             IS_CATEGORY(id, KeywordTokenType))
    1982             :         {
    1983           0 :             (*exp_it).set_token_id(T_INTLIT);
    1984           0 :             (*exp_it).set_value("0");
    1985             :         }
    1986             :     }
    1987           0 : }
    1988             : 
    1989             : ///////////////////////////////////////////////////////////////////////////////
    1990             : //
    1991             : //  on_if(): handle #if directives
    1992             : //
    1993             : ///////////////////////////////////////////////////////////////////////////////
    1994             : template <typename ContextT>
    1995             : inline void
    1996           0 : pp_iterator_functor<ContextT>::on_if(
    1997             :     result_type const& found_directive,
    1998             :     typename parse_tree_type::const_iterator const &begin,
    1999             :     typename parse_tree_type::const_iterator const &end)
    2000             : {
    2001             : // preprocess the given sequence into the provided list
    2002             : get_token_value<result_type, parse_node_type> get_value;
    2003           0 : token_sequence_type toexpand;
    2004             : 
    2005           0 :     std::copy(make_ref_transform_iterator(begin, get_value),
    2006             :         make_ref_transform_iterator(end, get_value),
    2007             :         std::inserter(toexpand, toexpand.end()));
    2008             : 
    2009           0 :     impl::remove_leading_whitespace(ctx, toexpand);
    2010             : 
    2011           0 : bool if_status = false;
    2012           0 : grammars::value_error status = grammars::error_noerror;
    2013           0 : token_sequence_type expanded;
    2014             : 
    2015             :     do {
    2016           0 :         expanded.clear();
    2017             : 
    2018           0 :         typename token_sequence_type::iterator begin2 = toexpand.begin();
    2019           0 :         ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded);
    2020             : 
    2021             :     // replace all remaining (== undefined) identifiers with an integer literal '0'
    2022           0 :         replace_undefined_identifiers(expanded);
    2023             : 
    2024             : #if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0
    2025             :         {
    2026             :             string_type outstr(boost::wave::util::impl::as_string(toexpand));
    2027             :             outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")";
    2028             :             BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#if " << outstr
    2029             :                 << std::endl;
    2030             :         }
    2031             : #endif
    2032             :         try {
    2033             :         // parse the expression and enter the #if block
    2034             :             if_status = grammars::expression_grammar_gen<result_type>::
    2035           0 :                     evaluate(expanded.begin(), expanded.end(), act_pos,
    2036           0 :                         ctx.get_if_block_status(), status);
    2037             :         }
    2038           0 :         catch (boost::wave::preprocess_exception const& e) {
    2039             :         // any errors occurred have to be dispatched to the context hooks
    2040           0 :             ctx.get_hooks().throw_exception(ctx.derived(), e);
    2041             :             break;
    2042             :         }
    2043             : 
    2044             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    2045             :         ctx.get_hooks().evaluated_conditional_expression(toexpand, if_status);
    2046             :     } while (false);
    2047             : #else
    2048           0 :     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
    2049             :                 found_directive, toexpand, if_status)
    2050           0 :              && status == grammars::error_noerror);
    2051             : #endif
    2052             : 
    2053           0 :     ctx.enter_if_block(if_status);
    2054           0 :     if (grammars::error_noerror != status) {
    2055             :     // division or other error by zero occurred
    2056           0 :         string_type expression = util::impl::as_string(expanded);
    2057           0 :         if (0 == expression.size())
    2058           0 :             expression = "<empty expression>";
    2059             : 
    2060           0 :         if (grammars::error_division_by_zero & status) {
    2061           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, division_by_zero,
    2062             :                 expression.c_str(), act_pos);
    2063             :         }
    2064           0 :         else if (grammars::error_integer_overflow & status) {
    2065           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, integer_overflow,
    2066             :                 expression.c_str(), act_pos);
    2067             :         }
    2068           0 :         else if (grammars::error_character_overflow & status) {
    2069           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    2070             :                 character_literal_out_of_range, expression.c_str(), act_pos);
    2071             :         }
    2072             :     }
    2073           0 : }
    2074             : 
    2075             : ///////////////////////////////////////////////////////////////////////////////
    2076             : //
    2077             : //  on_elif(): handle #elif directives
    2078             : //
    2079             : ///////////////////////////////////////////////////////////////////////////////
    2080             : template <typename ContextT>
    2081             : inline void
    2082           0 : pp_iterator_functor<ContextT>::on_elif(
    2083             :     result_type const& found_directive,
    2084             :     typename parse_tree_type::const_iterator const &begin,
    2085             :     typename parse_tree_type::const_iterator const &end)
    2086             : {
    2087             : // preprocess the given sequence into the provided list
    2088             : get_token_value<result_type, parse_node_type> get_value;
    2089           0 : token_sequence_type toexpand;
    2090             : 
    2091           0 :     std::copy(make_ref_transform_iterator(begin, get_value),
    2092             :         make_ref_transform_iterator(end, get_value),
    2093             :         std::inserter(toexpand, toexpand.end()));
    2094             : 
    2095           0 :     impl::remove_leading_whitespace(ctx, toexpand);
    2096             : 
    2097             : // check current if block status
    2098           0 :     if (ctx.get_if_block_some_part_status()) {
    2099           0 :         if (!ctx.enter_elif_block(false)) {
    2100             :         // #else without matching #if
    2101           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    2102             :                 missing_matching_if, "#elif", act_pos);
    2103             :             // fall through...
    2104             :         }
    2105             : 
    2106             :     // skip all the expression and the trailing whitespace
    2107           0 :     typename token_sequence_type::iterator begin2 = toexpand.begin();
    2108             : 
    2109           0 :         impl::skip_to_eol(ctx, begin2, toexpand.end());
    2110             :         return;     // one of previous #if/#elif was true, so don't enter this #elif
    2111             :     }
    2112             : 
    2113             : // preprocess the given sequence into the provided list
    2114           0 : bool if_status = false;
    2115           0 : grammars::value_error status = grammars::error_noerror;
    2116           0 : token_sequence_type expanded;
    2117             : 
    2118             :     do {
    2119           0 :         expanded.clear();
    2120             : 
    2121           0 :         typename token_sequence_type::iterator begin2 = toexpand.begin();
    2122           0 :         ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded);
    2123             : 
    2124             :     // replace all remaining (== undefined) identifiers with an integer literal '0'
    2125           0 :         replace_undefined_identifiers(expanded);
    2126             : 
    2127             : #if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0
    2128             :         {
    2129             :             string_type outstr(boost::wave::util::impl::as_string(toexpand));
    2130             :             outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")";
    2131             :             BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#elif " << outstr << std::endl;
    2132             :         }
    2133             : #endif
    2134             : 
    2135             :         try {
    2136             :         // parse the expression and enter the #elif block
    2137             :             if_status = grammars::expression_grammar_gen<result_type>::
    2138           0 :                 evaluate(expanded.begin(), expanded.end(), act_pos,
    2139           0 :                     ctx.get_if_block_status(), status);
    2140             :         }
    2141           0 :         catch (boost::wave::preprocess_exception const& e) {
    2142             :         // any errors occurred have to be dispatched to the context hooks
    2143           0 :             ctx.get_hooks().throw_exception(ctx.derived(), e);
    2144             :         }
    2145             : 
    2146             : #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
    2147             :         ctx.get_hooks().evaluated_conditional_expression(toexpand, if_status);
    2148             :     } while (false);
    2149             : #else
    2150           0 :     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
    2151             :                 found_directive, toexpand, if_status)
    2152           0 :              && status == grammars::error_noerror);
    2153             : #endif
    2154             : 
    2155           0 :     if (!ctx.enter_elif_block(if_status)) {
    2156             :     // #elif without matching #if
    2157           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
    2158             :             "#elif", act_pos);
    2159           0 :         return;
    2160             :     }
    2161             : 
    2162           0 :     if (grammars::error_noerror != status) {
    2163             :     // division or other error by zero occurred
    2164           0 :         string_type expression = util::impl::as_string(expanded);
    2165           0 :         if (0 == expression.size())
    2166           0 :             expression = "<empty expression>";
    2167             : 
    2168           0 :         if (grammars::error_division_by_zero & status) {
    2169           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, division_by_zero,
    2170             :                 expression.c_str(), act_pos);
    2171             :         }
    2172           0 :         else if (grammars::error_integer_overflow & status) {
    2173           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    2174             :                 integer_overflow, expression.c_str(), act_pos);
    2175             :         }
    2176           0 :         else if (grammars::error_character_overflow & status) {
    2177           0 :             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
    2178             :                 character_literal_out_of_range, expression.c_str(), act_pos);
    2179             :         }
    2180             :     }
    2181             : }
    2182             : 
    2183             : ///////////////////////////////////////////////////////////////////////////////
    2184             : //
    2185             : //  on_illformed(): handles the illegal directive
    2186             : //
    2187             : ///////////////////////////////////////////////////////////////////////////////
    2188             : template <typename ContextT>
    2189             : inline void
    2190           0 : pp_iterator_functor<ContextT>::on_illformed(
    2191             :     typename result_type::string_type s)
    2192             : {
    2193           0 :     BOOST_ASSERT(ctx.get_if_block_status());
    2194             : 
    2195             :     // some messages have more than one newline at the end
    2196           0 :     typename string_type::size_type p = s.find_last_not_of('\n');
    2197           0 :     if (string_type::npos != p)
    2198           0 :         s = s.substr(0, p+1);
    2199             : 
    2200             :     // throw the exception
    2201           0 :     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_directive,
    2202             :         s.c_str(), act_pos);
    2203           0 : }
    2204             : 
    2205             : ///////////////////////////////////////////////////////////////////////////////
    2206             : //
    2207             : //  on_line(): handle #line directives
    2208             : //
    2209             : ///////////////////////////////////////////////////////////////////////////////
    2210             : 
    2211             : namespace impl {
    2212             : 
    2213             :     template <typename IteratorT, typename StringT>
    2214           0 :     bool retrieve_line_info (IteratorT first, IteratorT const &last,
    2215             :         unsigned int &line, StringT &file,
    2216             :         boost::wave::preprocess_exception::error_code& error)
    2217             :     {
    2218             :         using namespace boost::wave;
    2219           0 :         token_id id = token_id(*first);
    2220           0 :         if (T_PP_NUMBER == id || T_INTLIT == id) {
    2221             :         // extract line number
    2222             :             using namespace std;    // some systems have atoi in namespace std
    2223           0 :             line = (unsigned int)atoi((*first).get_value().c_str());
    2224           0 :             if (0 == line)
    2225           0 :                 error = preprocess_exception::bad_line_number;
    2226             : 
    2227             :         // re-extract line number with spirit to diagnose overflow
    2228             :             using namespace boost::spirit::classic;
    2229           0 :             if (!parse((*first).get_value().c_str(), int_p).full)
    2230           0 :                 error = preprocess_exception::bad_line_number;
    2231             : 
    2232             :         // extract file name (if it is given)
    2233           0 :             while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
    2234             :                 /**/;   // skip whitespace
    2235             : 
    2236           0 :             if (first != last) {
    2237           0 :                 if (T_STRINGLIT != token_id(*first)) {
    2238           0 :                     error = preprocess_exception::bad_line_filename;
    2239           0 :                     return false;
    2240             :                 }
    2241             : 
    2242           0 :             StringT const &file_lit = (*first).get_value();
    2243             : 
    2244           0 :                 if ('L' == file_lit[0]) {
    2245           0 :                     error = preprocess_exception::bad_line_filename;
    2246           0 :                     return false;       // shouldn't be a wide character string
    2247             :                 }
    2248             : 
    2249           0 :                 file = file_lit.substr(1, file_lit.size()-2);
    2250             : 
    2251             :             // test if there is other junk on this line
    2252           0 :                 while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
    2253             :                     /**/;   // skip whitespace
    2254             :             }
    2255           0 :             return first == last;
    2256             :         }
    2257           0 :         error = preprocess_exception::bad_line_statement;
    2258           0 :         return false;
    2259             :     }
    2260             : }
    2261             : 
    2262             : template <typename ContextT>
    2263             : inline void
    2264           0 : pp_iterator_functor<ContextT>::on_line(
    2265             :     typename parse_tree_type::const_iterator const &begin,
    2266             :     typename parse_tree_type::const_iterator const &end)
    2267             : {
    2268           0 :     BOOST_ASSERT(ctx.get_if_block_status());
    2269             : 
    2270             : // Try to extract the line number and file name from the given token list
    2271             : // directly. If that fails, preprocess the whole token sequence and try again
    2272             : // to extract this information.
    2273           0 : token_sequence_type expanded;
    2274             : get_token_value<result_type, parse_node_type> get_value;
    2275             : 
    2276             :     typedef typename ref_transform_iterator_generator<
    2277             :             get_token_value<result_type, parse_node_type>,
    2278             :             typename parse_tree_type::const_iterator
    2279             :         >::type const_tree_iterator_t;
    2280             : 
    2281           0 : const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value);
    2282           0 : const_tree_iterator_t last = make_ref_transform_iterator(end, get_value);
    2283             : 
    2284             : // try to interpret the #line body as a number followed by an optional
    2285             : // string literal
    2286           0 : unsigned int line = 0;
    2287           0 : preprocess_exception::error_code error = preprocess_exception::no_error;
    2288           0 : string_type file_name;
    2289           0 : token_sequence_type toexpand;
    2290             : 
    2291           0 :     std::copy(first, last, std::inserter(toexpand, toexpand.end()));
    2292           0 :     if (!impl::retrieve_line_info(first, last, line, file_name, error)) {
    2293             :     // preprocess the body of this #line message
    2294           0 :         typename token_sequence_type::iterator begin2 = toexpand.begin();
    2295           0 :         ctx.expand_whole_tokensequence(begin2, toexpand.end(),
    2296             :             expanded, false);
    2297             : 
    2298           0 :         error = preprocess_exception::no_error;
    2299           0 :         if (!impl::retrieve_line_info(expanded.begin(), expanded.end(),
    2300             :             line, file_name, error))
    2301             :         {
    2302           0 :             typename ContextT::string_type msg(
    2303             :                 boost::wave::util::impl::as_string(expanded));
    2304           0 :             BOOST_WAVE_THROW_VAR_CTX(ctx, preprocess_exception, error,
    2305             :                 msg.c_str(), act_pos);
    2306           0 :             return;
    2307             :         }
    2308             : 
    2309             :     // call the corresponding pp hook function
    2310           0 :         ctx.get_hooks().found_line_directive(ctx.derived(), expanded, line,
    2311             :             file_name.c_str());
    2312             :     }
    2313             :     else {
    2314             :     // call the corresponding pp hook function
    2315           0 :         ctx.get_hooks().found_line_directive(ctx.derived(), toexpand, line,
    2316             :             file_name.c_str());
    2317             :     }
    2318             : 
    2319             : // the queues should be empty at this point
    2320           0 :     BOOST_ASSERT(unput_queue.empty());
    2321           0 :     BOOST_ASSERT(pending_queue.empty());
    2322             : 
    2323             : // make sure error recovery starts on the next line
    2324           0 :     must_emit_line_directive = true;
    2325             : 
    2326             : // diagnose possible error in detected line directive
    2327           0 :     if (error != preprocess_exception::no_error) {
    2328           0 :         typename ContextT::string_type msg(
    2329             :             boost::wave::util::impl::as_string(expanded));
    2330           0 :         BOOST_WAVE_THROW_VAR_CTX(ctx, preprocess_exception, error,
    2331             :             msg.c_str(), act_pos);
    2332           0 :         return;
    2333             :     }
    2334             : 
    2335             : // set new line number/filename only if ok
    2336           0 :     if (!file_name.empty()) {    // reuse current file name
    2337             :         using boost::wave::util::impl::unescape_lit;
    2338           0 :         act_pos.set_file(unescape_lit(file_name).c_str());
    2339             :     }
    2340           0 :     act_pos.set_line(line);
    2341           0 :     if (iter_ctx->first != iter_ctx->last)
    2342             :     {
    2343           0 :       iter_ctx->first.set_position(act_pos);
    2344             :     }
    2345             : }
    2346             : 
    2347             : ///////////////////////////////////////////////////////////////////////////////
    2348             : //
    2349             : //  on_error(): handle #error directives
    2350             : //
    2351             : ///////////////////////////////////////////////////////////////////////////////
    2352             : template <typename ContextT>
    2353             : inline void
    2354           0 : pp_iterator_functor<ContextT>::on_error(
    2355             :     typename parse_tree_type::const_iterator const &begin,
    2356             :     typename parse_tree_type::const_iterator const &end)
    2357             : {
    2358           0 :     BOOST_ASSERT(ctx.get_if_block_status());
    2359             : 
    2360             : // preprocess the given sequence into the provided list
    2361           0 : token_sequence_type expanded;
    2362             : get_token_value<result_type, parse_node_type> get_value;
    2363             : 
    2364             : typename ref_transform_iterator_generator<
    2365             :         get_token_value<result_type, parse_node_type>,
    2366             :         typename parse_tree_type::const_iterator
    2367           0 :     >::type first = make_ref_transform_iterator(begin, get_value);
    2368             : 
    2369             : #if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0
    2370             : // preprocess the body of this #error message
    2371           0 : token_sequence_type toexpand;
    2372             : 
    2373           0 :     std::copy(first, make_ref_transform_iterator(end, get_value),
    2374             :         std::inserter(toexpand, toexpand.end()));
    2375             : 
    2376           0 :     typename token_sequence_type::iterator begin2 = toexpand.begin();
    2377           0 :     ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
    2378             :         false);
    2379           0 :     if (!ctx.get_hooks().found_error_directive(ctx.derived(), toexpand))
    2380             : #else
    2381             : // simply copy the body of this #error message to the issued diagnostic
    2382             : // message
    2383             :     std::copy(first, make_ref_transform_iterator(end, get_value),
    2384             :         std::inserter(expanded, expanded.end()));
    2385             :     if (!ctx.get_hooks().found_error_directive(ctx.derived(), expanded))
    2386             : #endif
    2387             :     {
    2388             :     // report the corresponding error
    2389           0 :         BOOST_WAVE_STRINGTYPE msg(boost::wave::util::impl::as_string(expanded));
    2390           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, error_directive,
    2391             :             msg.c_str(), act_pos);
    2392             :     }
    2393           0 : }
    2394             : 
    2395             : #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
    2396             : ///////////////////////////////////////////////////////////////////////////////
    2397             : //
    2398             : //  on_warning(): handle #warning directives
    2399             : //
    2400             : ///////////////////////////////////////////////////////////////////////////////
    2401             : template <typename ContextT>
    2402             : inline void
    2403           0 : pp_iterator_functor<ContextT>::on_warning(
    2404             :     typename parse_tree_type::const_iterator const &begin,
    2405             :     typename parse_tree_type::const_iterator const &end)
    2406             : {
    2407           0 :     BOOST_ASSERT(ctx.get_if_block_status());
    2408             : 
    2409             : // preprocess the given sequence into the provided list
    2410           0 : token_sequence_type expanded;
    2411             : get_token_value<result_type, parse_node_type> get_value;
    2412             : 
    2413             : typename ref_transform_iterator_generator<
    2414             :         get_token_value<result_type, parse_node_type>,
    2415             :         typename parse_tree_type::const_iterator
    2416           0 :     >::type first = make_ref_transform_iterator(begin, get_value);
    2417             : 
    2418             : #if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0
    2419             : // preprocess the body of this #warning message
    2420           0 : token_sequence_type toexpand;
    2421             : 
    2422           0 :     std::copy(first, make_ref_transform_iterator(end, get_value),
    2423             :         std::inserter(toexpand, toexpand.end()));
    2424             : 
    2425           0 :     typename token_sequence_type::iterator begin2 = toexpand.begin();
    2426           0 :     ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
    2427             :         false);
    2428           0 :     if (!ctx.get_hooks().found_warning_directive(ctx.derived(), toexpand))
    2429             : #else
    2430             : // simply copy the body of this #warning message to the issued diagnostic
    2431             : // message
    2432             :     std::copy(first, make_ref_transform_iterator(end, get_value),
    2433             :         std::inserter(expanded, expanded.end()));
    2434             :     if (!ctx.get_hooks().found_warning_directive(ctx.derived(), expanded))
    2435             : #endif
    2436             :     {
    2437             :     // report the corresponding error
    2438           0 :         BOOST_WAVE_STRINGTYPE msg(boost::wave::util::impl::as_string(expanded));
    2439           0 :         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, warning_directive,
    2440             :             msg.c_str(), act_pos);
    2441             :     }
    2442           0 : }
    2443             : #endif // BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
    2444             : 
    2445             : ///////////////////////////////////////////////////////////////////////////////
    2446             : //
    2447             : //  on_pragma(): handle #pragma directives
    2448             : //
    2449             : ///////////////////////////////////////////////////////////////////////////////
    2450             : template <typename ContextT>
    2451             : inline bool
    2452           0 : pp_iterator_functor<ContextT>::on_pragma(
    2453             :     typename parse_tree_type::const_iterator const &begin,
    2454             :     typename parse_tree_type::const_iterator const &end)
    2455             : {
    2456             :     using namespace boost::wave;
    2457             : 
    2458           0 :     BOOST_ASSERT(ctx.get_if_block_status());
    2459             : 
    2460             : // Look at the pragma token sequence and decide, if the first token is STDC
    2461             : // (see C99 standard [6.10.6.2]), if it is, the sequence must _not_ be
    2462             : // preprocessed.
    2463           0 : token_sequence_type expanded;
    2464             : get_token_value<result_type, parse_node_type> get_value;
    2465             : 
    2466             :     typedef typename ref_transform_iterator_generator<
    2467             :             get_token_value<result_type, parse_node_type>,
    2468             :             typename parse_tree_type::const_iterator
    2469             :         >::type const_tree_iterator_t;
    2470             : 
    2471           0 : const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value);
    2472           0 : const_tree_iterator_t last = make_ref_transform_iterator(end, get_value);
    2473             : 
    2474           0 :     expanded.push_back(result_type(T_PP_PRAGMA, "#pragma", act_token.get_position()));
    2475           0 :     expanded.push_back(result_type(T_SPACE, " ", act_token.get_position()));
    2476             : 
    2477           0 :     while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
    2478           0 :         expanded.push_back(*first);   // skip whitespace
    2479             : 
    2480           0 :     if (first != last) {
    2481           0 :         if (T_IDENTIFIER == token_id(*first) &&
    2482           0 :             boost::wave::need_c99(ctx.get_language()) &&
    2483           0 :             (*first).get_value() == "STDC")
    2484             :         {
    2485             :         // do _not_ preprocess the token sequence
    2486           0 :             std::copy(first, last, std::inserter(expanded, expanded.end()));
    2487             :         }
    2488             :         else {
    2489             : #if BOOST_WAVE_PREPROCESS_PRAGMA_BODY != 0
    2490             :         // preprocess the given tokensequence
    2491           0 :         token_sequence_type toexpand;
    2492             : 
    2493           0 :             std::copy(first, last, std::inserter(toexpand, toexpand.end()));
    2494             : 
    2495           0 :             typename token_sequence_type::iterator begin2 = toexpand.begin();
    2496           0 :             ctx.expand_whole_tokensequence(begin2, toexpand.end(),
    2497             :                 expanded, false);
    2498             : #else
    2499             :         // do _not_ preprocess the token sequence
    2500             :             std::copy(first, last, std::inserter(expanded, expanded.end()));
    2501             : #endif
    2502             :         }
    2503             :     }
    2504           0 :     expanded.push_back(result_type(T_NEWLINE, "\n", act_token.get_position()));
    2505             : 
    2506             : // the queues should be empty at this point
    2507           0 :     BOOST_ASSERT(unput_queue.empty());
    2508           0 :     BOOST_ASSERT(pending_queue.empty());
    2509             : 
    2510             : // try to interpret the expanded #pragma body
    2511           0 :     token_sequence_type pending;
    2512           0 :     if (interpret_pragma(expanded, pending)) {
    2513             :     // if there is some replacement text, insert it into the pending queue
    2514           0 :         if (!pending.empty())
    2515           0 :             pending_queue.splice(pending_queue.begin(), pending);
    2516           0 :         return true;        // this #pragma was successfully recognized
    2517             :     }
    2518             : 
    2519             : #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
    2520             : // Move the resulting token sequence into the pending_queue, so it will be
    2521             : // returned to the caller.
    2522           0 :     if (boost::wave::need_emit_pragma_directives(ctx.get_language())) {
    2523           0 :         pending_queue.splice(pending_queue.begin(), expanded);
    2524           0 :         return false;       // return the whole #pragma directive
    2525             :     }
    2526             : #endif
    2527             :     return true;            // skip the #pragma at all
    2528             : }
    2529             : 
    2530             : template <typename ContextT>
    2531             : inline bool
    2532           0 : pp_iterator_functor<ContextT>::interpret_pragma(
    2533             :     token_sequence_type const &pragma_body, token_sequence_type &result)
    2534             : {
    2535             :     using namespace cpplexer;
    2536             : 
    2537           0 :     typename token_sequence_type::const_iterator end = pragma_body.end();
    2538           0 :     typename token_sequence_type::const_iterator it = pragma_body.begin();
    2539           0 :     for (++it; it != end && IS_CATEGORY(*it, WhiteSpaceTokenType); ++it)
    2540             :         /**/;   // skip whitespace
    2541             : 
    2542           0 :     if (it == end)      // eof reached
    2543             :         return false;
    2544             : 
    2545           0 :     return boost::wave::util::interpret_pragma(
    2546           0 :         ctx.derived(), act_token, it, end, result);
    2547             : }
    2548             : 
    2549             : ///////////////////////////////////////////////////////////////////////////////
    2550             : }   // namespace impl
    2551             : 
    2552             : ///////////////////////////////////////////////////////////////////////////////
    2553             : //
    2554             : //  pp_iterator
    2555             : //
    2556             : //      The boost::wave::pp_iterator template is the iterator, through which
    2557             : //      the resulting preprocessed input stream is accessible.
    2558             : //
    2559             : ///////////////////////////////////////////////////////////////////////////////
    2560             : 
    2561             : template <typename ContextT>
    2562           0 : class pp_iterator
    2563             : :   public boost::spirit::classic::multi_pass<
    2564             :         boost::wave::impl::pp_iterator_functor<ContextT>,
    2565             :         boost::wave::util::functor_input
    2566             :     >
    2567             : {
    2568             : public:
    2569             :     typedef boost::wave::impl::pp_iterator_functor<ContextT> input_policy_type;
    2570             : 
    2571             : private:
    2572             :     typedef
    2573             :         boost::spirit::classic::multi_pass<input_policy_type, boost::wave::util::functor_input>
    2574             :         base_type;
    2575             :     typedef pp_iterator<ContextT> self_type;
    2576             :     typedef boost::wave::util::functor_input functor_input_type;
    2577             : 
    2578             : public:
    2579           0 :     pp_iterator()
    2580           0 :     {}
    2581             : 
    2582             :     template <typename IteratorT>
    2583           0 :     pp_iterator(ContextT &ctx, IteratorT const &first, IteratorT const &last,
    2584             :         typename ContextT::position_type const &pos)
    2585           0 :     :   base_type(input_policy_type(ctx, first, last, pos))
    2586           0 :     {}
    2587             : 
    2588           0 :     bool force_include(char const *path_, bool is_last)
    2589             :     {
    2590           0 :         bool result = this->get_functor().on_include_helper(path_, path_,
    2591             :             false, false);
    2592           0 :         if (is_last) {
    2593           0 :             this->functor_input_type::
    2594             :                 template inner<input_policy_type>::advance_input();
    2595             :         }
    2596           0 :         return result;
    2597             :     }
    2598             : };
    2599             : 
    2600             : ///////////////////////////////////////////////////////////////////////////////
    2601             : }   // namespace wave
    2602             : }   // namespace boost
    2603             : 
    2604             : // the suffix header occurs after all of the code
    2605             : #ifdef BOOST_HAS_ABI_HEADERS
    2606             : #include BOOST_ABI_SUFFIX
    2607             : #endif
    2608             : 
    2609             : #endif // !defined(CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED)

Generated by: LCOV version 1.14