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(BOOST_CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED)
14 #define BOOST_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
retrieve_macroname(ContextT & ctx,ParseNodeT const & node,boost::spirit::classic::parser_id id,TokenT & macroname,PositionT & act_pos,bool update_position)69 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     ParseNodeT const* name_node = 0;
74 
75     using boost::spirit::classic::find_node;
76     if (!find_node(node, id, &name_node))
77     {
78         // ill formed define statement (unexpected, should not happen)
79         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_define_statement,
80             "bad parse tree (unexpected)", act_pos);
81         return false;
82     }
83 
84     typename ParseNodeT::children_t const& children = name_node->children;
85 
86     if (0 == children.size() ||
87         children.front().value.begin() == children.front().value.end())
88     {
89         // ill formed define statement (unexpected, should not happen)
90         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_define_statement,
91             "bad parse tree (unexpected)", act_pos);
92         return false;
93     }
94 
95     // retrieve the macro name
96     macroname = *children.front().value.begin();
97     if (update_position) {
98         macroname.set_position(act_pos);
99         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
retrieve_macrodefinition(ParseNodeT const & node,boost::spirit::classic::parser_id id,ContainerT & macrodefinition,PositionT & act_pos,bool update_position)108 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     std::pair<const_tree_iterator, const_tree_iterator> nodes;
117 
118     using boost::spirit::classic::get_node_range;
119     if (get_node_range(node, id, nodes)) {
120         // copy all parameters to the supplied container
121         typename ContainerT::iterator last_nonwhite = macrodefinition.end();
122         const_tree_iterator end = nodes.second;
123 
124         for (const_tree_iterator cit = nodes.first; cit != end; ++cit) {
125             if ((*cit).value.begin() != (*cit).value.end()) {
126                 typename ContainerT::iterator inserted = macrodefinition.insert(
127                     macrodefinition.end(), *(*cit).value.begin());
128 
129                 if (!IS_CATEGORY(macrodefinition.back(), WhiteSpaceTokenType) &&
130                     T_NEWLINE != token_id(macrodefinition.back()) &&
131                     T_EOF != token_id(macrodefinition.back()))
132                 {
133                     last_nonwhite = inserted;
134                 }
135 
136                 if (update_position) {
137                     (*inserted).set_position(act_pos);
138                     act_pos.set_column(
139                         act_pos.get_column() + (*inserted).get_value().size());
140                 }
141             }
142         }
143 
144         // trim trailing whitespace (leading whitespace is trimmed by the grammar)
145         if (last_nonwhite != macrodefinition.end()) {
146             if (update_position) {
147                 act_pos.set_column((*last_nonwhite).get_position().get_column() +
148                     (*last_nonwhite).get_value().size());
149             }
150             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>
add_macro_definition(ContextT & ctx,std::string macrostring,bool is_predefined,boost::wave::language_support language)161 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     std::string::iterator begin = macrostring.begin();
175     std::string::iterator end = macrostring.end();
176 
177     while(begin != end && isspace(*begin))
178         ++begin;
179 
180     // parse the macro definition
181     position_type act_pos("<command line>");
182     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     if (!hit.match || (!hit.full && T_EOF != token_id(*hit.stop))) {
187         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     token_type macroname;
194     std::vector<token_type> macroparameters;
195     typename ContextT::token_sequence_type macrodefinition;
196     bool has_parameters = false;
197 
198     if (!boost::wave::util::retrieve_macroname(ctx, *hit.trees.begin(),
199             BOOST_WAVE_PLAIN_DEFINE_ID, macroname, act_pos, true))
200         return false;
201     has_parameters = boost::wave::util::retrieve_macrodefinition(*hit.trees.begin(),
202         BOOST_WAVE_MACRO_PARAMETERS_ID, macroparameters, act_pos, true);
203     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     if (!macrodefinition.empty() && token_id(macrodefinition.back()) == T_EOF)
208         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     if (macrodefinition.empty() && '=' != macrostring[macrostring.size()-1])
213         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         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>
pp_iterator_functor(ContextT & ctx_,IteratorT const & first_,IteratorT const & last_,typename ContextT::position_type const & pos_)273     pp_iterator_functor(ContextT &ctx_, IteratorT const &first_,
274             IteratorT const &last_, typename ContextT::position_type const &pos_)
275     :   ctx(ctx_),
276         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                 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         whitespace(boost::wave::need_insert_whitespace(ctx.get_language()))
285     {
286         act_pos.set_file(pos_.get_file());
287 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
288         ctx_.set_current_filename(pos_.get_file().c_str());
289 #endif
290         iter_ctx->emitted_lines = (unsigned int)(-1);   // force #line directive
291     }
292 
293     // get the next preprocessed token
294     result_type const &operator()();
295 
296     // get the last recognized token (for error processing etc.)
current_token() const297     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
returned_from_include()397 pp_iterator_functor<ContextT>::returned_from_include()
398 {
399     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         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         BOOST_WAVE_STRINGTYPE oldfile = iter_ctx->real_filename;
410         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         if (need_include_guard_detection(ctx.get_language())) {
415             std::string guard_name;
416             if (iter_ctx->first.has_include_guards(guard_name))
417                 ctx.add_pragma_once_header(ctx.get_current_filename(), guard_name);
418         }
419 #endif
420         iter_ctx = ctx.pop_iteration_context();
421 
422         must_emit_line_directive = true;
423         iter_ctx->emitted_lines = (unsigned int)(-1);   // force #line directive
424         seen_newline = true;
425 
426         // restore current file position
427         act_pos.set_file(iter_ctx->filename);
428         act_pos.set_line(iter_ctx->line);
429         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         fs::path rfp(wave::util::create_path(iter_ctx->real_filename.c_str()));
435         std::string real_filename(rfp.string());
436         ctx.set_current_filename(real_filename.c_str());
437 #endif
438         ctx.set_current_directory(iter_ctx->real_filename.c_str());
439         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         if (iter_ctx->if_block_depth != ctx.get_if_block_depth()) {
444             using boost::wave::util::impl::escape_lit;
445             BOOST_WAVE_STRINGTYPE msg(escape_lit(oldfile));
446             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, unbalanced_if_endif,
447                 msg.c_str(), old_pos);
448         }
449         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>
consider_emitting_line_directive(ContextT const & ctx,token_id id)469     bool consider_emitting_line_directive(ContextT const& ctx, token_id id)
470     {
471         if (need_preserve_comments(ctx.get_language()))
472         {
473             if (!IS_CATEGORY(id, EOLTokenType) && !IS_CATEGORY(id, EOFTokenType))
474             {
475                 return true;
476             }
477         }
478         if (!IS_CATEGORY(id, WhiteSpaceTokenType) &&
479             !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 &
operator ()()489 pp_iterator_functor<ContextT>::operator()()
490 {
491     using namespace boost::wave;
492 
493     // make sure the cwd has been initialized
494     ctx.init_context();
495 
496     // loop over skip able whitespace until something significant is found
497     bool was_seen_newline = seen_newline;
498     bool was_skipped_newline = skipped_newline;
499     token_id id = T_UNKNOWN;
500 
501     try {   // catch lexer exceptions
502         do {
503             if (skipped_newline) {
504                 was_skipped_newline = true;
505                 skipped_newline = false;
506             }
507 
508             // get_next_token assigns result to act_token member
509             get_next_token();
510 
511             // if comments shouldn't be preserved replace them with newlines
512             id = token_id(act_token);
513             if (!need_preserve_comments(ctx.get_language()) &&
514                 (T_CPPCOMMENT == id || context_policies::util::ccomment_has_newline(act_token)))
515             {
516                 act_token.set_token_id(id = T_NEWLINE);
517                 act_token.set_value("\n");
518             }
519 
520             if (IS_CATEGORY(id, EOLTokenType))
521                 seen_newline = true;
522 
523         } while (ctx.get_hooks().may_skip_whitespace(ctx.derived(), act_token, skipped_newline));
524     }
525     catch (boost::wave::cpplexer::lexing_exception const& e) {
526         // dispatch any lexer exceptions to the context hook function
527         ctx.get_hooks().throw_exception(ctx.derived(), e);
528         return act_token;
529     }
530 
531     // restore the accumulated skipped_newline state for next invocation
532     if (was_skipped_newline)
533         skipped_newline = true;
534 
535     // if there were skipped any newlines, we must emit a #line directive
536     if ((must_emit_line_directive || (was_seen_newline && skipped_newline)) &&
537         impl::consider_emitting_line_directive(ctx, id))
538     {
539         // must emit a #line directive
540         if (need_emit_line_directives(ctx.get_language()) && emit_line_directive())
541         {
542             skipped_newline = false;
543             ctx.get_hooks().may_skip_whitespace(ctx.derived(), act_token, skipped_newline);     // feed ws eater FSM
544             id = token_id(act_token);
545         }
546     }
547 
548     // cleanup of certain tokens required
549     seen_newline = false;
550     switch (id) {
551     case T_NONREPLACABLE_IDENTIFIER:
552         act_token.set_token_id(id = T_IDENTIFIER);
553         break;
554 
555     case T_GENERATEDNEWLINE:  // was generated by emit_line_directive()
556         act_token.set_token_id(id = T_NEWLINE);
557         ++iter_ctx->emitted_lines;
558         seen_newline = true;
559         break;
560 
561     case T_NEWLINE:
562     case T_CPPCOMMENT:
563         seen_newline = true;
564         ++iter_ctx->emitted_lines;
565         break;
566 
567 #if BOOST_WAVE_SUPPORT_CPP0X != 0
568     case T_RAWSTRINGLIT:
569         iter_ctx->emitted_lines +=
570             context_policies::util::rawstring_count_newlines(act_token);
571         break;
572 #endif
573 
574     case T_CCOMMENT:          // will come here only if whitespace is preserved
575         iter_ctx->emitted_lines +=
576             context_policies::util::ccomment_count_newlines(act_token);
577         break;
578 
579     case T_PP_NUMBER:        // re-tokenize the pp-number
580         {
581             token_sequence_type rescanned;
582 
583             std::string pp_number(
584                 util::to_string<std::string>(act_token.get_value()));
585 
586             lexer_type it = lexer_type(pp_number.begin(),
587                 pp_number.end(), act_token.get_position(),
588                 ctx.get_language());
589             lexer_type end = lexer_type();
590 
591             for (/**/; it != end && T_EOF != token_id(*it); ++it)
592                 rescanned.push_back(*it);
593 
594             pending_queue.splice(pending_queue.begin(), rescanned);
595             act_token = pending_queue.front();
596             id = token_id(act_token);
597             pending_queue.pop_front();
598         }
599         break;
600 
601     case T_EOF:
602         seen_newline = true;
603         break;
604 
605     default:    // make sure whitespace at line begin keeps seen_newline status
606         if (IS_CATEGORY(id, WhiteSpaceTokenType))
607             seen_newline = was_seen_newline;
608         break;
609     }
610 
611     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         whitespace.shift_tokens(T_SPACE);
615         pending_queue.push_front(act_token);        // push this token back
616         return act_token = result_type(T_SPACE,
617             typename result_type::string_type(" "),
618             act_token.get_position());
619     }
620     whitespace.shift_tokens(id);
621     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 &
get_next_token()627 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     if (!pending_queue.empty() || !unput_queue.empty())
634         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     bool returned_from_include_file = returned_from_include();
639 
640     // try to generate the next token
641     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             if (!pending_queue.empty()) {
647                 util::on_exit::pop_front<token_sequence_type>
648                     pop_front_token(pending_queue);
649 
650                 return act_token = pending_queue.front();
651             }
652 
653             // adjust the current position (line and column)
654             bool was_seen_newline = seen_newline || returned_from_include_file;
655 
656             // fetch the current token
657             act_token = *iter_ctx->first;
658             act_pos = act_token.get_position();
659 
660             // act accordingly on the current token
661             token_id id = token_id(act_token);
662 
663             if (T_EOF == id) {
664                 // returned from an include file, continue with the next token
665                 whitespace.shift_tokens(T_EOF);
666                 ++iter_ctx->first;
667 
668                 // now make sure this line has a newline
669                 if ((!seen_newline || act_pos.get_column() > 1) &&
670                     !need_single_line(ctx.get_language()))
671                 {
672                     if (need_no_newline_at_end_of_file(ctx.get_language()))
673                     {
674                         seen_newline = true;
675                         pending_queue.push_back(
676                             result_type(T_NEWLINE, "\n", act_pos)
677                         );
678                     }
679                     else
680                     {
681                         // warn, if this file does not end with a newline
682                         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
683                             last_line_not_terminated, "", act_pos);
684                     }
685                 }
686                 continue;   // if this is the main file, the while loop breaks
687             }
688             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                 seen_newline = true;
692                 ++iter_ctx->first;
693 
694                 if (!ctx.get_if_block_status()) {
695                     // skip this token because of the disabled #if block
696                     whitespace.shift_tokens(id);  // whitespace controller
697                     util::impl::call_skipped_token_hook(ctx, act_token);
698                     continue;
699                 }
700                 return act_token;
701             }
702             seen_newline = false;
703 
704             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                 if (iter_ctx->first == iter_ctx->last)
710                 {
711                     seen_newline = true;
712                     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             else if (ctx.get_if_block_status()) {
720                 // preprocess this token, eat up more, if appropriate, return
721                 // the next preprocessed token
722                 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                 if (T_NEWLINE == token_id(act_token)) {
729                     seen_newline = true;
730                     must_emit_line_directive = true;
731                 }
732 
733                 // next token
734                 util::impl::call_skipped_token_hook(ctx, act_token);
735                 ++iter_ctx->first;
736             }
737 
738         } while ((iter_ctx->first != iter_ctx->last) ||
739                  (returned_from_include_file = returned_from_include()));
740 
741         // overall eof reached
742         if (ctx.get_if_block_depth() > 0 && !need_single_line(ctx.get_language()))
743         {
744             // missing endif directive(s)
745             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
746                 missing_matching_endif, "", act_pos);
747         }
748     }
749     else {
750         act_token = eof;            // this is the last token
751     }
752 
753 //  whitespace.shift_tokens(T_EOF);     // whitespace controller
754     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
emit_line_directive()764 pp_iterator_functor<ContextT>::emit_line_directive()
765 {
766     using namespace boost::wave;
767 
768     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     if (must_emit_line_directive ||
779         iter_ctx->emitted_lines+1 != act_pos.get_line())
780     {
781         // unput the current token
782         pending_queue.push_front(act_token);
783         pos.set_line(act_pos.get_line());
784 
785         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             act_token = result_type(T_NEWLINE, "\n", pos);
789         }
790         else {
791             // account for the newline emitted here
792             act_pos.set_line(act_pos.get_line()-1);
793             iter_ctx->emitted_lines = act_pos.get_line()-1;
794 
795             token_sequence_type pending;
796 
797             if (!ctx.get_hooks().emit_line_directive(ctx, pending, act_token))
798             {
799                 unsigned int column = 6;
800 
801                 // the hook did not generate anything, emit default #line
802                 pos.set_column(1);
803                 pending.push_back(result_type(T_PP_LINE, "#line", pos));
804 
805                 pos.set_column(column);      // account for '#line'
806                 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                 std::string buffer = lexical_cast<std::string>(pos.get_line());
812 
813                 pos.set_column(++column);                 // account for ' '
814                 pending.push_back(result_type(T_INTLIT, buffer.c_str(), pos));
815                 pos.set_column(column += (unsigned int)buffer.size()); // account for <number>
816                 pending.push_back(result_type(T_SPACE, " ", pos));
817                 pos.set_column(++column);                 // account for ' '
818 
819                 std::string file("\"");
820                 boost::filesystem::path filename(
821                     wave::util::create_path(act_pos.get_file().c_str()));
822 
823                 using wave::util::impl::escape_lit;
824                 file += escape_lit(wave::util::native_file_string(filename)) + "\"";
825 
826                 pending.push_back(result_type(T_STRINGLIT, file.c_str(), pos));
827                 pos.set_column(column += (unsigned int)file.size());    // account for filename
828                 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             if (!pending.empty()) {
833                 pending_queue.splice(pending_queue.begin(), pending);
834                 act_token = pending_queue.front();
835                 pending_queue.pop_front();
836             }
837         }
838 
839         must_emit_line_directive = false;     // we are now in sync
840         return true;
841     }
842 
843     must_emit_line_directive = false;         // we are now in sync
844     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 &
pp_token()854 pp_iterator_functor<ContextT>::pp_token()
855 {
856     using namespace boost::wave;
857 
858     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         if (!pending_queue.empty()) {
864             // if there are pending tokens in the queue, return the first one
865             act_token = pending_queue.front();
866             pending_queue.pop_front();
867             act_pos = act_token.get_position();
868         }
869         else if (!unput_queue.empty()
870               || T_IDENTIFIER == id
871               || IS_CATEGORY(id, KeywordTokenType)
872               || IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType)
873               || IS_CATEGORY(id, BoolLiteralTokenType))
874         {
875             //  call the lexer, preprocess the required number of tokens, put them
876             //  into the unput queue
877             act_token = ctx.expand_tokensequence(iter_ctx->first,
878                 iter_ctx->last, pending_queue, unput_queue, skipped_newline);
879         }
880         else {
881             // simply return the next token
882             act_token = *iter_ctx->first;
883             ++iter_ctx->first;
884         }
885         id = token_id(act_token);
886 
887     } while (T_PLACEHOLDER == id);
888     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>
call_found_directive_hook(ContextT & ctx,typename ContextT::token_type const & found_directive)900     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         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>
next_token_is_pp_directive(ContextT & ctx,IteratorT & it,IteratorT const & end)925     bool next_token_is_pp_directive(ContextT &ctx, IteratorT &it, IteratorT const &end)
926     {
927         using namespace boost::wave;
928 
929         token_id id = T_UNKNOWN;
930         for (/**/; it != end; ++it) {
931             id = token_id(*it);
932             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             if (T_CPPCOMMENT == id ||
937                 context_policies::util::ccomment_has_newline(*it))
938             {
939                 break;
940             }
941 
942             // this token gets skipped
943             util::impl::call_skipped_token_hook(ctx, *it);
944         }
945         BOOST_ASSERT(it == end || id != T_UNKNOWN);
946         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>
pp_is_last_on_line(ContextT & ctx,IteratorT & it,IteratorT const & end,bool call_hook=true)951     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         if (call_hook)
958             util::impl::call_skipped_token_hook(ctx, *it);
959 
960         for (++it; it != end; ++it) {
961         token_id id = token_id(*it);
962 
963             if (T_CPPCOMMENT == id || T_NEWLINE == id ||
964                 context_policies::util::ccomment_has_newline(*it))
965             {
966                 if (call_hook)
967                     util::impl::call_skipped_token_hook(ctx, *it);
968                 ++it;           // skip eol/C/C++ comment
969                 return true;    // no more significant tokens on this line
970             }
971 
972             if (!IS_CATEGORY(id, WhiteSpaceTokenType))
973                 break;
974 
975             // this token gets skipped
976             if (call_hook)
977                 util::impl::call_skipped_token_hook(ctx, *it);
978         }
979         return need_no_newline_at_end_of_file(ctx.get_language());
980     }
981 
982     ///////////////////////////////////////////////////////////////////////////
983     template <typename ContextT, typename IteratorT>
skip_to_eol(ContextT & ctx,IteratorT & it,IteratorT const & end,bool call_hook=true)984     bool skip_to_eol(ContextT &ctx, IteratorT &it, IteratorT const &end,
985         bool call_hook = true)
986     {
987         using namespace boost::wave;
988 
989         for (/**/; it != end; ++it) {
990         token_id id = token_id(*it);
991 
992             if (T_CPPCOMMENT == id || T_NEWLINE == id ||
993                 context_policies::util::ccomment_has_newline(*it))
994             {
995                 // always call hook for eol
996                 util::impl::call_skipped_token_hook(ctx, *it);
997                 ++it;           // skip eol/C/C++ comment
998                 return true;    // found eol
999             }
1000 
1001             if (call_hook)
1002                 util::impl::call_skipped_token_hook(ctx, *it);
1003         }
1004         return false;
1005     }
1006 
1007     ///////////////////////////////////////////////////////////////////////////
1008     template <typename ContextT, typename ContainerT>
1009     inline void
remove_leading_whitespace(ContextT & ctx,ContainerT & c,bool call_hook=true)1010     remove_leading_whitespace(ContextT &ctx, ContainerT& c, bool call_hook = true)
1011     {
1012         typename ContainerT::iterator it = c.begin();
1013         while (IS_CATEGORY(*it, WhiteSpaceTokenType)) {
1014             typename ContainerT::iterator save = it++;
1015             if (call_hook)
1016                 util::impl::call_skipped_token_hook(ctx, *save);
1017             c.erase(save);
1018         }
1019     }
1020 }
1021 
1022 ///////////////////////////////////////////////////////////////////////////////
1023 template <typename ContextT>
1024 template <typename IteratorT>
1025 inline bool
extract_identifier(IteratorT & it)1026 pp_iterator_functor<ContextT>::extract_identifier(IteratorT &it)
1027 {
1028     token_id id = util::impl::skip_whitespace(it, iter_ctx->last);
1029     if (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType) ||
1030         IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
1031         IS_CATEGORY(id, BoolLiteralTokenType))
1032     {
1033         IteratorT save = it;
1034         if (impl::pp_is_last_on_line(ctx, save, iter_ctx->last, false))
1035             return true;
1036     }
1037 
1038     // report the ill formed directive
1039     impl::skip_to_eol(ctx, it, iter_ctx->last);
1040 
1041     string_type str(util::impl::as_string<string_type>(iter_ctx->first, it));
1042 
1043     seen_newline = true;
1044     iter_ctx->first = it;
1045     on_illformed(str);
1046     return false;
1047 }
1048 
1049 ///////////////////////////////////////////////////////////////////////////////
1050 template <typename ContextT>
1051 template <typename IteratorT>
1052 inline bool
ensure_is_last_on_line(IteratorT & it,bool call_hook)1053 pp_iterator_functor<ContextT>::ensure_is_last_on_line(IteratorT& it, bool call_hook)
1054 {
1055     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         impl::skip_to_eol(ctx, it, iter_ctx->last);
1059 
1060     string_type str(util::impl::as_string<string_type>(
1061         iter_ctx->first, it));
1062 
1063         seen_newline = true;
1064         iter_ctx->first = it;
1065 
1066         // report an invalid directive
1067         on_illformed(str);
1068         return false;
1069     }
1070 
1071     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         seen_newline = true;    // allow to resume after warning
1075         iter_ctx->first = it;
1076 
1077         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             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1082                 last_line_not_terminated, "", act_pos);
1083         }
1084 
1085         return false;
1086     }
1087     return true;
1088 }
1089 
1090 template <typename ContextT>
1091 template <typename IteratorT>
1092 inline bool
skip_to_eol_with_check(IteratorT & it,bool call_hook)1093 pp_iterator_functor<ContextT>::skip_to_eol_with_check(IteratorT &it, bool call_hook)
1094 {
1095     typename ContextT::string_type value ((*it).get_value());
1096     if (!impl::skip_to_eol(ctx, it, iter_ctx->last, call_hook) &&
1097         !need_single_line(ctx.get_language()))
1098     {
1099         // The line doesn't end with an eol but eof token.
1100         seen_newline = true;    // allow to resume after warning
1101         iter_ctx->first = it;
1102 
1103         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             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1108                 last_line_not_terminated, "", act_pos);
1109         }
1110         return false;
1111     }
1112 
1113     // normal line ending reached, adjust iterator and flag
1114     seen_newline = true;
1115     iter_ctx->first = it;
1116     return true;
1117 }
1118 
1119 ///////////////////////////////////////////////////////////////////////////////
1120 //  handle_pp_directive: handle certain pp_directives
1121 template <typename ContextT>
1122 template <typename IteratorT>
1123 inline bool
handle_pp_directive(IteratorT & it)1124 pp_iterator_functor<ContextT>::handle_pp_directive(IteratorT &it)
1125 {
1126     token_id id = token_id(*it);
1127     bool can_exit = true;
1128     bool call_hook_in_skip = true;
1129     if (!ctx.get_if_block_status()) {
1130         if (IS_EXTCATEGORY(*it, PPConditionalTokenType)) {
1131             // simulate the if block hierarchy
1132             switch (id) {
1133             case T_PP_IFDEF:        // #ifdef
1134             case T_PP_IFNDEF:       // #ifndef
1135             case T_PP_IF:           // #if
1136                 ctx.enter_if_block(false);
1137                 break;
1138 
1139             case T_PP_ELIF:         // #elif
1140                 if (!ctx.get_enclosing_if_block_status()) {
1141                     if (!ctx.enter_elif_block(false)) {
1142                         // #else without matching #if
1143                         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1144                             missing_matching_if, "#elif", act_pos);
1145                         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             case T_PP_ELSE:         // #else
1154             case T_PP_ENDIF:        // #endif
1155                 {
1156                 // handle this directive
1157                     if (T_PP_ELSE == token_id(*it))
1158                         on_else();
1159                     else
1160                         on_endif();
1161 
1162                 // make sure, there are no (non-whitespace) tokens left on
1163                 // this line
1164                     ensure_is_last_on_line(it);
1165 
1166                 // we skipped to the end of this line already
1167                     seen_newline = true;
1168                     iter_ctx->first = it;
1169                 }
1170                 return true;
1171 
1172             default:                // #something else
1173                 on_illformed((*it).get_value());
1174                 break;
1175             }
1176         }
1177         else {
1178             util::impl::call_skipped_token_hook(ctx, *it);
1179             ++it;
1180         }
1181     }
1182     else {
1183         // try to handle the simple pp directives without parsing
1184         result_type directive = *it;
1185         bool include_next = false;
1186         switch (id) {
1187         case T_PP_QHEADER:        // #include "..."
1188 #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
1189         case T_PP_QHEADER_NEXT:
1190 #endif
1191             include_next = (T_PP_QHEADER_NEXT == id) ? true : false;
1192             if (!impl::call_found_directive_hook(ctx, *it))
1193             {
1194                 string_type dir((*it).get_value());
1195 
1196                 // make sure, there are no (non-whitespace) tokens left on
1197                 // this line
1198                 if (ensure_is_last_on_line(it))
1199                 {
1200                     seen_newline = true;
1201                     iter_ctx->first = it;
1202                     on_include (dir, false, include_next);
1203                 }
1204                 return true;
1205             }
1206             break;
1207 
1208         case T_PP_HHEADER:        // #include <...>
1209 #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
1210         case T_PP_HHEADER_NEXT:
1211 #endif
1212             include_next = (T_PP_HHEADER_NEXT == id) ? true : false;
1213             if (!impl::call_found_directive_hook(ctx, *it))
1214             {
1215                 string_type dir((*it).get_value());
1216 
1217                 // make sure, there are no (non-whitespace) tokens left on
1218                 // this line
1219                 if (ensure_is_last_on_line(it))
1220                 {
1221                     seen_newline = true;
1222                     iter_ctx->first = it;
1223                     on_include (dir, true, include_next);
1224                 }
1225                 return true;
1226             }
1227             break;
1228 
1229         case T_PP_ELSE:         // #else
1230         case T_PP_ENDIF:        // #endif
1231             if (!impl::call_found_directive_hook(ctx, *it))
1232             {
1233                 // handle this directive
1234                 if (T_PP_ELSE == token_id(*it))
1235                     on_else();
1236                 else
1237                     on_endif();
1238 
1239                 // make sure, there are no (non-whitespace) tokens left on
1240                 // this line
1241                 ensure_is_last_on_line(it);
1242 
1243                 // we skipped to the end of this line already
1244                 seen_newline = true;
1245                 iter_ctx->first = it;
1246                 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         case T_PP_UNDEF:                // #undef
1261             if (!impl::call_found_directive_hook(ctx, *it) &&
1262                 extract_identifier(it))
1263             {
1264                 on_undefine(it);
1265             }
1266             call_hook_in_skip = false;
1267             break;
1268 
1269         case T_PP_IFDEF:                // #ifdef
1270             if (!impl::call_found_directive_hook(ctx, *it) &&
1271                 extract_identifier(it))
1272             {
1273                 on_ifdef(directive, it);
1274             }
1275             call_hook_in_skip = false;
1276             break;
1277 
1278         case T_PP_IFNDEF:               // #ifndef
1279             if (!impl::call_found_directive_hook(ctx, *it) &&
1280                 extract_identifier(it))
1281             {
1282                 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     if (can_exit) {
1303         skip_to_eol_with_check(it, call_hook_in_skip);
1304         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
pp_directive()1313 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     lexer_type it = iter_ctx->first;
1319 
1320     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         if (it != iter_ctx->last && T_POUND == BASE_TOKEN(token_id(*it))) {
1323             if (impl::pp_is_last_on_line(ctx, it, iter_ctx->last)) {
1324                 // start over with the next line
1325                 seen_newline = true;
1326                 iter_ctx->first = it;
1327                 return true;
1328             }
1329             else if (ctx.get_if_block_status()) {
1330                 // report invalid pp directive
1331                 impl::skip_to_eol(ctx, it, iter_ctx->last);
1332                 seen_newline = true;
1333 
1334                 string_type str(boost::wave::util::impl::as_string<string_type>(
1335                     iter_ctx->first, it));
1336 
1337                 token_sequence_type faulty_line;
1338 
1339                 for (/**/; iter_ctx->first != it; ++iter_ctx->first)
1340                     faulty_line.push_back(*iter_ctx->first);
1341 
1342                 token_sequence_type pending;
1343                 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                 on_illformed(str);
1353             }
1354         }
1355 
1356         // this line does not contain a pp directive, so simply return
1357         return false;
1358     }
1359 
1360     // found eof
1361     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     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     bool found_eof = false;
1374     result_type found_directive;
1375     token_sequence_type found_eoltokens;
1376 
1377     tree_parse_info_type hit = cpp_grammar_type::parse_cpp_grammar(
1378         it, iter_ctx->last, act_pos, found_eof, found_directive, found_eoltokens);
1379 
1380     if (hit.match) {
1381         // position the iterator past the matched sequence to allow
1382         // resynchronization, if an error occurs
1383         iter_ctx->first = hit.stop;
1384         seen_newline = true;
1385         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         bool result = dispatch_directive(hit, found_directive, found_eoltokens);
1390 
1391         if (found_eof && !need_single_line(ctx.get_language()) &&
1392             !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             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1398                 last_line_not_terminated, "", act_pos);
1399         }
1400         return result;
1401     }
1402     else if (token_id(found_directive) != T_EOF) {
1403         // recognized invalid directive
1404         impl::skip_to_eol(ctx, it, iter_ctx->last);
1405         seen_newline = true;
1406 
1407         string_type str(boost::wave::util::impl::as_string<string_type>(
1408             iter_ctx->first, it));
1409         iter_ctx->first = it;
1410 
1411         // report the ill formed directive
1412         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
dispatch_directive(tree_parse_info_type const & hit,result_type const & found_directive,token_sequence_type const & found_eoltokens)1424 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     const_child_iterator_t begin = hit.trees.begin();
1434 
1435     // decide, which preprocessor directive was found
1436     parse_tree_type const& root = (*begin).children;
1437     parse_node_value_type const& nodeval = get_first_leaf(*root.begin()).value;
1438     //long node_id = nodeval.id().to_long();
1439 
1440     const_child_iterator_t begin_child_it = (*root.begin()).children.begin();
1441     const_child_iterator_t end_child_it = (*root.begin()).children.end();
1442 
1443     token_id id = token_id(found_directive);
1444 
1445     // call preprocessing hook
1446     if (impl::call_found_directive_hook(ctx, found_directive))
1447         return true;    // skip this directive and return newline only
1448 
1449     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     case T_PP_INCLUDE:      // #include ...
1467 #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
1468     case T_PP_INCLUDE_NEXT: // #include_next ...
1469 #endif
1470         on_include (begin_child_it, end_child_it, T_PP_INCLUDE_NEXT == id);
1471         break;
1472 
1473     case T_PP_DEFINE:       // #define
1474         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     case T_PP_IF:           // #if
1490         on_if(found_directive, begin_child_it, end_child_it);
1491         break;
1492 
1493     case T_PP_ELIF:         // #elif
1494         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     case T_PP_LINE:         // #line
1506         on_line(begin_child_it, end_child_it);
1507         break;
1508 
1509     case T_PP_ERROR:        // #error
1510         on_error(begin_child_it, end_child_it);
1511         break;
1512 
1513 #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
1514     case T_PP_WARNING:      // #warning
1515         on_warning(begin_child_it, end_child_it);
1516         break;
1517 #endif
1518 
1519     case T_PP_PRAGMA:       // #pragma
1520         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     default:                // #something else
1529         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             token_sequence_type expanded;
1535             get_token_value<result_type, parse_node_type> get_value;
1536 
1537             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             pending_queue.splice(pending_queue.begin(), expanded);
1541         }
1542         break;
1543     }
1544 
1545     // properly skip trailing newline for all directives
1546     typename token_sequence_type::const_iterator eol = found_eoltokens.begin();
1547     impl::skip_to_eol(ctx, eol, found_eoltokens.end());
1548     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
on_include(string_type const & s,bool is_system,bool include_next)1558 pp_iterator_functor<ContextT>::on_include (string_type const &s,
1559     bool is_system, bool include_next)
1560 {
1561     BOOST_ASSERT(ctx.get_if_block_status());
1562 
1563 // strip quotes first, extract filename
1564 typename string_type::size_type pos_end = s.find_last_of(is_system ? '>' : '\"');
1565 
1566     if (string_type::npos == pos_end) {
1567         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
1568             s.c_str(), act_pos);
1569         return;
1570     }
1571 
1572 typename string_type::size_type pos_begin =
1573     s.find_last_of(is_system ? '<' : '\"', pos_end-1);
1574 
1575     if (string_type::npos == pos_begin) {
1576         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
1577             s.c_str(), act_pos);
1578         return;
1579     }
1580 
1581     std::string file_token(s.substr(pos_begin, pos_end - pos_begin + 1).c_str());
1582     std::string file_path(s.substr(pos_begin + 1, pos_end - pos_begin - 1).c_str());
1583 
1584     // finally include the file
1585     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
on_include_helper(char const * f,char const * s,bool is_system,bool include_next)1591 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     std::string file_path(s);
1598     std::string dir_path;
1599 #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
1600     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     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     file_path = util::impl::unescape_lit(file_path);
1614     std::string native_path_str;
1615 
1616     if (!ctx.get_hooks().locate_include_file(ctx, file_path, is_system,
1617             current_name, dir_path, native_path_str))
1618     {
1619         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     if (!ctx.has_pragma_once(native_path_str))
1627 #endif
1628     {
1629         // the new include file determines the actual current directory
1630         ctx.set_current_directory(native_path_str.c_str());
1631 
1632         // preprocess the opened file
1633         boost::shared_ptr<base_iteration_context_type> new_iter_ctx(
1634             new iteration_context_type(ctx, native_path_str.c_str(), act_pos,
1635                 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         ctx.get_hooks().opened_include_file(ctx.derived(), dir_path, file_path,
1645             is_system);
1646 #endif
1647 
1648         // store current file position
1649         iter_ctx->real_relative_filename = ctx.get_current_relative_filename().c_str();
1650         iter_ctx->filename = act_pos.get_file();
1651         iter_ctx->line = act_pos.get_line();
1652         iter_ctx->if_block_depth = ctx.get_if_block_depth();
1653         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         ctx.push_iteration_context(act_pos, iter_ctx);
1657         iter_ctx = new_iter_ctx;
1658         seen_newline = true;        // fake a newline to trigger pp_directive
1659         must_emit_line_directive = true;
1660 
1661         act_pos.set_file(iter_ctx->filename);  // initialize file position
1662 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
1663         fs::path rfp(wave::util::create_path(iter_ctx->real_filename.c_str()));
1664         std::string real_filename(rfp.string());
1665         ctx.set_current_filename(real_filename.c_str());
1666 #endif
1667 
1668         ctx.set_current_relative_filename(dir_path.c_str());
1669         iter_ctx->real_relative_filename = dir_path.c_str();
1670 
1671         act_pos.set_line(iter_ctx->line);
1672         act_pos.set_column(0);
1673     }
1674     return true;
1675 }
1676 
1677 ///////////////////////////////////////////////////////////////////////////////
1678 //
1679 //  on_include(): handle #include ... directives
1680 //
1681 ///////////////////////////////////////////////////////////////////////////////
1682 
1683 template <typename ContextT>
1684 inline void
on_include(typename parse_tree_type::const_iterator const & begin,typename parse_tree_type::const_iterator const & end,bool include_next)1685 pp_iterator_functor<ContextT>::on_include(
1686     typename parse_tree_type::const_iterator const &begin,
1687     typename parse_tree_type::const_iterator const &end, bool include_next)
1688 {
1689     BOOST_ASSERT(ctx.get_if_block_status());
1690 
1691     // preprocess the given token sequence (the body of the #include directive)
1692     get_token_value<result_type, parse_node_type> get_value;
1693     token_sequence_type expanded;
1694     token_sequence_type toexpand;
1695 
1696     std::copy(make_ref_transform_iterator(begin, get_value),
1697         make_ref_transform_iterator(end, get_value),
1698         std::inserter(toexpand, toexpand.end()));
1699 
1700     typename token_sequence_type::iterator begin2 = toexpand.begin();
1701     // expanding the computed include
1702     ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
1703                                    false, false);
1704 
1705     // now, include the file
1706     using namespace boost::wave::util::impl;
1707     string_type s (trim_whitespace(as_string(expanded)));
1708     bool is_system = '<' == s[0] && '>' == s[s.size()-1];
1709 
1710     if (!is_system && !('\"' == s[0] && '\"' == s[s.size()-1])) {
1711     // should resolve into something like <...> or "..."
1712         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
1713             s.c_str(), act_pos);
1714         return;
1715     }
1716     on_include(s, is_system, include_next);
1717 }
1718 
1719 ///////////////////////////////////////////////////////////////////////////////
1720 //
1721 //  on_define(): handle #define directives
1722 //
1723 ///////////////////////////////////////////////////////////////////////////////
1724 
1725 template <typename ContextT>
1726 inline void
on_define(parse_node_type const & node)1727 pp_iterator_functor<ContextT>::on_define (parse_node_type const &node)
1728 {
1729     BOOST_ASSERT(ctx.get_if_block_status());
1730 
1731     // retrieve the macro definition from the parse tree
1732     result_type macroname;
1733     std::vector<result_type> macroparameters;
1734     token_sequence_type macrodefinition;
1735     bool has_parameters = false;
1736     position_type pos(act_token.get_position());
1737 
1738     if (!boost::wave::util::retrieve_macroname(ctx, node,
1739             BOOST_WAVE_PLAIN_DEFINE_ID, macroname, pos, false))
1740         return;
1741     has_parameters = boost::wave::util::retrieve_macrodefinition(node,
1742         BOOST_WAVE_MACRO_PARAMETERS_ID, macroparameters, pos, false);
1743     boost::wave::util::retrieve_macrodefinition(node,
1744         BOOST_WAVE_MACRO_DEFINITION_ID, macrodefinition, pos, false);
1745 
1746     if (has_parameters) {
1747 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1748         if (boost::wave::need_variadics(ctx.get_language())) {
1749             // test whether ellipsis are given, and if yes, if these are placed as the
1750             // last argument, test if __VA_ARGS__ is used as a macro parameter name
1751             using namespace cpplexer;
1752             typedef typename std::vector<result_type>::iterator
1753                 parameter_iterator_t;
1754 
1755             bool seen_ellipses = false;
1756             parameter_iterator_t end = macroparameters.end();
1757             for (parameter_iterator_t pit = macroparameters.begin();
1758                 pit != end; ++pit)
1759             {
1760                 if (seen_ellipses) {
1761                     // ellipses are not the last given formal argument
1762                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1763                         bad_define_statement, macroname.get_value().c_str(),
1764                         (*pit).get_position());
1765                     return;
1766                 }
1767                 if (T_ELLIPSIS == token_id(*pit))
1768                     seen_ellipses = true;
1769 
1770                 // can't use __VA_ARGS__ as a argument name
1771                 if ("__VA_ARGS__" == (*pit).get_value()) {
1772                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1773                         bad_define_statement_va_args,
1774                         macroname.get_value().c_str(), (*pit).get_position());
1775                     return;
1776                 }
1777 
1778 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1779                 // can't use __VA_OPT__ either
1780                 if (boost::wave::need_va_opt(ctx.get_language()) &&
1781                     ("__VA_OPT__" == (*pit).get_value())) {
1782                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1783                         bad_define_statement_va_opt,
1784                         macroname.get_value().c_str(), (*pit).get_position());
1785                     return;
1786                 }
1787 #endif
1788             }
1789 
1790             // if there wasn't an ellipsis, then there shouldn't be a __VA_ARGS__
1791             // placeholder in the definition too [C99 Standard 6.10.3.5]
1792             if (!seen_ellipses) {
1793                 typedef typename token_sequence_type::iterator definition_iterator_t;
1794 
1795                 bool seen_va_args = false;
1796 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1797                 bool seen_va_opt = false;
1798 #endif
1799                 definition_iterator_t pend = macrodefinition.end();
1800                 for (definition_iterator_t dit = macrodefinition.begin();
1801                      dit != pend; ++dit)
1802                 {
1803                     if (T_IDENTIFIER == token_id(*dit) &&
1804                         "__VA_ARGS__" == (*dit).get_value())
1805                     {
1806                         seen_va_args = true;
1807                     }
1808 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1809                     if (T_IDENTIFIER == token_id(*dit) &&
1810                         "__VA_OPT__" == (*dit).get_value())
1811                     {
1812                         seen_va_opt = true;
1813                     }
1814 #endif
1815                 }
1816                 if (seen_va_args) {
1817                     // must not have seen __VA_ARGS__ placeholder
1818                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1819                         bad_define_statement_va_args,
1820                         macroname.get_value().c_str(), act_token.get_position());
1821                     return;
1822                 }
1823 #if BOOST_WAVE_SUPPORT_VA_OPT != 0
1824                 if (seen_va_opt) {
1825                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1826                         bad_define_statement_va_opt,
1827                         macroname.get_value().c_str(), act_token.get_position());
1828                     return;
1829                 }
1830 #endif
1831             }
1832         }
1833         else
1834 #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1835         {
1836             // test, that there is no T_ELLIPSES given
1837             using namespace cpplexer;
1838             typedef typename std::vector<result_type>::iterator
1839                 parameter_iterator_t;
1840 
1841             parameter_iterator_t end = macroparameters.end();
1842             for (parameter_iterator_t pit = macroparameters.begin();
1843                 pit != end; ++pit)
1844             {
1845                 if (T_ELLIPSIS == token_id(*pit)) {
1846                     // if variadics are disabled, no ellipses should be given
1847                     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
1848                         bad_define_statement, macroname.get_value().c_str(),
1849                         (*pit).get_position());
1850                     return;
1851                 }
1852             }
1853         }
1854     }
1855 
1856     // add the new macro to the macromap
1857     ctx.add_macro_definition(macroname, has_parameters, macroparameters,
1858         macrodefinition);
1859 }
1860 
1861 ///////////////////////////////////////////////////////////////////////////////
1862 //
1863 //  on_undefine(): handle #undef directives
1864 //
1865 ///////////////////////////////////////////////////////////////////////////////
1866 template <typename ContextT>
1867 inline void
on_undefine(lexer_type const & it)1868 pp_iterator_functor<ContextT>::on_undefine (lexer_type const &it)
1869 {
1870     BOOST_ASSERT(ctx.get_if_block_status());
1871 
1872     // retrieve the macro name to undefine from the parse tree
1873     ctx.remove_macro_definition((*it).get_value()); // throws for predefined macros
1874 }
1875 
1876 ///////////////////////////////////////////////////////////////////////////////
1877 //
1878 //  on_ifdef(): handle #ifdef directives
1879 //
1880 ///////////////////////////////////////////////////////////////////////////////
1881 template <typename ContextT>
1882 inline void
on_ifdef(result_type const & found_directive,lexer_type const & it)1883 pp_iterator_functor<ContextT>::on_ifdef(
1884     result_type const& found_directive, lexer_type const &it)
1885 //     typename parse_tree_type::const_iterator const &it)
1886 //     typename parse_tree_type::const_iterator const &end)
1887 {
1888     // get_token_value<result_type, parse_node_type> get_value;
1889     // token_sequence_type toexpand;
1890     //
1891     //     std::copy(make_ref_transform_iterator((*begin).children.begin(), get_value),
1892     //         make_ref_transform_iterator((*begin).children.end(), get_value),
1893     //         std::inserter(toexpand, toexpand.end()));
1894 
1895     bool is_defined = false;
1896     token_sequence_type directive;
1897 
1898     directive.insert(directive.end(), *it);
1899 
1900 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
1901     is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end());
1902     ctx.get_hooks().evaluated_conditional_expression(directive, is_defined);
1903 #else
1904     do {
1905         is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end());
1906     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
1907              found_directive, directive, is_defined));
1908 #endif
1909     ctx.enter_if_block(is_defined);
1910 }
1911 
1912 ///////////////////////////////////////////////////////////////////////////////
1913 //
1914 //  on_ifndef(): handle #ifndef directives
1915 //
1916 ///////////////////////////////////////////////////////////////////////////////
1917 template <typename ContextT>
1918 inline void
on_ifndef(result_type const & found_directive,lexer_type const & it)1919 pp_iterator_functor<ContextT>::on_ifndef(
1920     result_type const& found_directive, lexer_type const &it)
1921 //     typename parse_tree_type::const_iterator const &it)
1922 //     typename parse_tree_type::const_iterator const &end)
1923 {
1924     // get_token_value<result_type, parse_node_type> get_value;
1925     // token_sequence_type toexpand;
1926     //
1927     //     std::copy(make_ref_transform_iterator((*begin).children.begin(), get_value),
1928     //         make_ref_transform_iterator((*begin).children.end(), get_value),
1929     //         std::inserter(toexpand, toexpand.end()));
1930 
1931     bool is_defined = false;
1932     token_sequence_type directive;
1933 
1934     directive.insert(directive.end(), *it);
1935 
1936 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
1937     is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end());
1938     ctx.get_hooks().evaluated_conditional_expression(directive, is_defined);
1939 #else
1940     do {
1941         is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end());
1942     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
1943              found_directive, directive, is_defined));
1944 #endif
1945     ctx.enter_if_block(!is_defined);
1946 }
1947 
1948 ///////////////////////////////////////////////////////////////////////////////
1949 //
1950 //  on_else(): handle #else directives
1951 //
1952 ///////////////////////////////////////////////////////////////////////////////
1953 template <typename ContextT>
1954 inline void
on_else()1955 pp_iterator_functor<ContextT>::on_else()
1956 {
1957     if (!ctx.enter_else_block()) {
1958         // #else without matching #if
1959         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
1960             "#else", act_pos);
1961     }
1962 }
1963 
1964 ///////////////////////////////////////////////////////////////////////////////
1965 //
1966 //  on_endif(): handle #endif directives
1967 //
1968 ///////////////////////////////////////////////////////////////////////////////
1969 template <typename ContextT>
1970 inline void
on_endif()1971 pp_iterator_functor<ContextT>::on_endif()
1972 {
1973     if (!ctx.exit_if_block()) {
1974         // #endif without matching #if
1975         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
1976             "#endif", act_pos);
1977     }
1978 }
1979 
1980 ///////////////////////////////////////////////////////////////////////////////
1981 //  replace all remaining (== undefined) identifiers with an integer literal '0'
1982 template <typename ContextT>
1983 inline void
replace_undefined_identifiers(token_sequence_type & expanded)1984 pp_iterator_functor<ContextT>::replace_undefined_identifiers(
1985     token_sequence_type &expanded)
1986 {
1987     typename token_sequence_type::iterator exp_end = expanded.end();
1988     for (typename token_sequence_type::iterator exp_it = expanded.begin();
1989          exp_it != exp_end; ++exp_it)
1990     {
1991         using namespace boost::wave;
1992 
1993         token_id id = token_id(*exp_it);
1994         if (IS_CATEGORY(id, IdentifierTokenType) ||
1995             IS_CATEGORY(id, KeywordTokenType))
1996         {
1997             (*exp_it).set_token_id(T_INTLIT);
1998             (*exp_it).set_value("0");
1999         }
2000     }
2001 }
2002 
2003 ///////////////////////////////////////////////////////////////////////////////
2004 //
2005 //  on_if(): handle #if directives
2006 //
2007 ///////////////////////////////////////////////////////////////////////////////
2008 template <typename ContextT>
2009 inline void
on_if(result_type const & found_directive,typename parse_tree_type::const_iterator const & begin,typename parse_tree_type::const_iterator const & end)2010 pp_iterator_functor<ContextT>::on_if(
2011     result_type const& found_directive,
2012     typename parse_tree_type::const_iterator const &begin,
2013     typename parse_tree_type::const_iterator const &end)
2014 {
2015     // preprocess the given sequence into the provided list
2016     get_token_value<result_type, parse_node_type> get_value;
2017     token_sequence_type toexpand;
2018 
2019     std::copy(make_ref_transform_iterator(begin, get_value),
2020         make_ref_transform_iterator(end, get_value),
2021         std::inserter(toexpand, toexpand.end()));
2022 
2023     impl::remove_leading_whitespace(ctx, toexpand);
2024 
2025     bool if_status = false;
2026     grammars::value_error status = grammars::error_noerror;
2027     token_sequence_type expanded;
2028 
2029     do {
2030         expanded.clear();
2031 
2032         typename token_sequence_type::iterator begin2 = toexpand.begin();
2033         ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded);
2034 
2035         // replace all remaining (== undefined) identifiers with an integer literal '0'
2036         replace_undefined_identifiers(expanded);
2037 
2038 #if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0
2039         {
2040             string_type outstr(boost::wave::util::impl::as_string(toexpand));
2041             outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")";
2042             BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#if " << outstr
2043                 << std::endl;
2044         }
2045 #endif
2046         try {
2047             // parse the expression and enter the #if block
2048             if_status = grammars::expression_grammar_gen<result_type>::
2049                     evaluate(expanded.begin(), expanded.end(), act_pos,
2050                         ctx.get_if_block_status(), status);
2051         }
2052         catch (boost::wave::preprocess_exception const& e) {
2053             // any errors occurred have to be dispatched to the context hooks
2054             ctx.get_hooks().throw_exception(ctx.derived(), e);
2055             break;
2056         }
2057 
2058 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
2059         ctx.get_hooks().evaluated_conditional_expression(toexpand, if_status);
2060     } while (false);
2061 #else
2062     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
2063                 found_directive, toexpand, if_status)
2064              && status == grammars::error_noerror);
2065 #endif
2066 
2067     ctx.enter_if_block(if_status);
2068     if (grammars::error_noerror != status) {
2069         // division or other error by zero occurred
2070         string_type expression = util::impl::as_string(expanded);
2071         if (0 == expression.size())
2072             expression = "<empty expression>";
2073 
2074         if (grammars::error_division_by_zero & status) {
2075             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, division_by_zero,
2076                 expression.c_str(), act_pos);
2077         }
2078         else if (grammars::error_integer_overflow & status) {
2079             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, integer_overflow,
2080                 expression.c_str(), act_pos);
2081         }
2082         else if (grammars::error_character_overflow & status) {
2083             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2084                 character_literal_out_of_range, expression.c_str(), act_pos);
2085         }
2086     }
2087 }
2088 
2089 ///////////////////////////////////////////////////////////////////////////////
2090 //
2091 //  on_elif(): handle #elif directives
2092 //
2093 ///////////////////////////////////////////////////////////////////////////////
2094 template <typename ContextT>
2095 inline void
on_elif(result_type const & found_directive,typename parse_tree_type::const_iterator const & begin,typename parse_tree_type::const_iterator const & end)2096 pp_iterator_functor<ContextT>::on_elif(
2097     result_type const& found_directive,
2098     typename parse_tree_type::const_iterator const &begin,
2099     typename parse_tree_type::const_iterator const &end)
2100 {
2101     // preprocess the given sequence into the provided list
2102     get_token_value<result_type, parse_node_type> get_value;
2103     token_sequence_type toexpand;
2104 
2105     std::copy(make_ref_transform_iterator(begin, get_value),
2106         make_ref_transform_iterator(end, get_value),
2107         std::inserter(toexpand, toexpand.end()));
2108 
2109     impl::remove_leading_whitespace(ctx, toexpand);
2110 
2111     // check current if block status
2112     if (ctx.get_if_block_some_part_status()) {
2113         if (!ctx.enter_elif_block(false)) {
2114             // #else without matching #if
2115             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2116                 missing_matching_if, "#elif", act_pos);
2117             // fall through...
2118         }
2119 
2120         // skip all the expression and the trailing whitespace
2121         typename token_sequence_type::iterator begin2 = toexpand.begin();
2122 
2123         impl::skip_to_eol(ctx, begin2, toexpand.end());
2124         return;     // one of previous #if/#elif was true, so don't enter this #elif
2125     }
2126 
2127     // preprocess the given sequence into the provided list
2128     bool if_status = false;
2129     grammars::value_error status = grammars::error_noerror;
2130     token_sequence_type expanded;
2131 
2132     do {
2133         expanded.clear();
2134 
2135         typename token_sequence_type::iterator begin2 = toexpand.begin();
2136         ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded);
2137 
2138         // replace all remaining (== undefined) identifiers with an integer literal '0'
2139         replace_undefined_identifiers(expanded);
2140 
2141 #if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0
2142         {
2143             string_type outstr(boost::wave::util::impl::as_string(toexpand));
2144             outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")";
2145             BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#elif " << outstr << std::endl;
2146         }
2147 #endif
2148 
2149         try {
2150             // parse the expression and enter the #elif block
2151             if_status = grammars::expression_grammar_gen<result_type>::
2152                 evaluate(expanded.begin(), expanded.end(), act_pos,
2153                     ctx.get_if_block_status(), status);
2154         }
2155         catch (boost::wave::preprocess_exception const& e) {
2156             // any errors occurred have to be dispatched to the context hooks
2157             ctx.get_hooks().throw_exception(ctx.derived(), e);
2158         }
2159 
2160 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
2161         ctx.get_hooks().evaluated_conditional_expression(toexpand, if_status);
2162     } while (false);
2163 #else
2164     } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
2165                 found_directive, toexpand, if_status)
2166              && status == grammars::error_noerror);
2167 #endif
2168 
2169     if (!ctx.enter_elif_block(if_status)) {
2170         // #elif without matching #if
2171         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
2172             "#elif", act_pos);
2173         return;
2174     }
2175 
2176     if (grammars::error_noerror != status) {
2177         // division or other error by zero occurred
2178         string_type expression = util::impl::as_string(expanded);
2179         if (0 == expression.size())
2180             expression = "<empty expression>";
2181 
2182         if (grammars::error_division_by_zero & status) {
2183             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, division_by_zero,
2184                 expression.c_str(), act_pos);
2185         }
2186         else if (grammars::error_integer_overflow & status) {
2187             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2188                 integer_overflow, expression.c_str(), act_pos);
2189         }
2190         else if (grammars::error_character_overflow & status) {
2191             BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
2192                 character_literal_out_of_range, expression.c_str(), act_pos);
2193         }
2194     }
2195 }
2196 
2197 ///////////////////////////////////////////////////////////////////////////////
2198 //
2199 //  on_illformed(): handles the illegal directive
2200 //
2201 ///////////////////////////////////////////////////////////////////////////////
2202 template <typename ContextT>
2203 inline void
on_illformed(typename result_type::string_type s)2204 pp_iterator_functor<ContextT>::on_illformed(
2205     typename result_type::string_type s)
2206 {
2207     BOOST_ASSERT(ctx.get_if_block_status());
2208 
2209     // some messages have more than one newline at the end
2210     typename string_type::size_type p = s.find_last_not_of('\n');
2211     if (string_type::npos != p)
2212         s = s.substr(0, p+1);
2213 
2214     // throw the exception
2215     BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_directive,
2216         s.c_str(), act_pos);
2217 }
2218 
2219 ///////////////////////////////////////////////////////////////////////////////
2220 //
2221 //  on_line(): handle #line directives
2222 //
2223 ///////////////////////////////////////////////////////////////////////////////
2224 
2225 namespace impl {
2226 
2227     template <typename IteratorT, typename StringT>
retrieve_line_info(IteratorT first,IteratorT const & last,unsigned int & line,StringT & file,boost::wave::preprocess_exception::error_code & error)2228     bool retrieve_line_info (IteratorT first, IteratorT const &last,
2229         unsigned int &line, StringT &file,
2230         boost::wave::preprocess_exception::error_code& error)
2231     {
2232         using namespace boost::wave;
2233         token_id id = token_id(*first);
2234         if (T_PP_NUMBER == id || T_INTLIT == id) {
2235         // extract line number
2236             using namespace std;    // some systems have atoi in namespace std
2237             line = (unsigned int)atoi((*first).get_value().c_str());
2238             if (0 == line)
2239                 error = preprocess_exception::bad_line_number;
2240 
2241         // re-extract line number with spirit to diagnose overflow
2242             using namespace boost::spirit::classic;
2243             if (!parse((*first).get_value().c_str(), int_p).full)
2244                 error = preprocess_exception::bad_line_number;
2245 
2246         // extract file name (if it is given)
2247             while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
2248                 /**/;   // skip whitespace
2249 
2250             if (first != last) {
2251                 if (T_STRINGLIT != token_id(*first)) {
2252                     error = preprocess_exception::bad_line_filename;
2253                     return false;
2254                 }
2255 
2256                 StringT const& file_lit = (*first).get_value();
2257 
2258                 if ('L' == file_lit[0]) {
2259                     error = preprocess_exception::bad_line_filename;
2260                     return false;       // shouldn't be a wide character string
2261                 }
2262 
2263                 file = file_lit.substr(1, file_lit.size()-2);
2264 
2265             // test if there is other junk on this line
2266                 while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
2267                     /**/;   // skip whitespace
2268             }
2269             return first == last;
2270         }
2271         error = preprocess_exception::bad_line_statement;
2272         return false;
2273     }
2274 }
2275 
2276 template <typename ContextT>
2277 inline void
on_line(typename parse_tree_type::const_iterator const & begin,typename parse_tree_type::const_iterator const & end)2278 pp_iterator_functor<ContextT>::on_line(
2279     typename parse_tree_type::const_iterator const &begin,
2280     typename parse_tree_type::const_iterator const &end)
2281 {
2282     BOOST_ASSERT(ctx.get_if_block_status());
2283 
2284     // Try to extract the line number and file name from the given token list
2285     // directly. If that fails, preprocess the whole token sequence and try again
2286     // to extract this information.
2287     token_sequence_type expanded;
2288     get_token_value<result_type, parse_node_type> get_value;
2289 
2290     typedef typename ref_transform_iterator_generator<
2291             get_token_value<result_type, parse_node_type>,
2292             typename parse_tree_type::const_iterator
2293         >::type const_tree_iterator_t;
2294 
2295     const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value);
2296     const_tree_iterator_t last = make_ref_transform_iterator(end, get_value);
2297 
2298     // try to interpret the #line body as a number followed by an optional
2299     // string literal
2300     unsigned int line = 0;
2301     preprocess_exception::error_code error = preprocess_exception::no_error;
2302     string_type file_name;
2303     token_sequence_type toexpand;
2304 
2305     std::copy(first, last, std::inserter(toexpand, toexpand.end()));
2306     if (!impl::retrieve_line_info(first, last, line, file_name, error)) {
2307         // preprocess the body of this #line message
2308         typename token_sequence_type::iterator begin2 = toexpand.begin();
2309         ctx.expand_whole_tokensequence(begin2, toexpand.end(),
2310                                        expanded, false, false);
2311 
2312         error = preprocess_exception::no_error;
2313         if (!impl::retrieve_line_info(expanded.begin(), expanded.end(),
2314             line, file_name, error))
2315         {
2316             typename ContextT::string_type msg(
2317                 boost::wave::util::impl::as_string(expanded));
2318             BOOST_WAVE_THROW_VAR_CTX(ctx, preprocess_exception, error,
2319                 msg.c_str(), act_pos);
2320             return;
2321         }
2322 
2323         // call the corresponding pp hook function
2324         ctx.get_hooks().found_line_directive(ctx.derived(), expanded, line,
2325             file_name.c_str());
2326     }
2327     else {
2328         // call the corresponding pp hook function
2329         ctx.get_hooks().found_line_directive(ctx.derived(), toexpand, line,
2330             file_name.c_str());
2331     }
2332 
2333     // the queues should be empty at this point
2334     BOOST_ASSERT(unput_queue.empty());
2335     BOOST_ASSERT(pending_queue.empty());
2336 
2337     // make sure error recovery starts on the next line
2338     must_emit_line_directive = true;
2339 
2340     // diagnose possible error in detected line directive
2341     if (error != preprocess_exception::no_error) {
2342         typename ContextT::string_type msg(
2343             boost::wave::util::impl::as_string(expanded));
2344         BOOST_WAVE_THROW_VAR_CTX(ctx, preprocess_exception, error,
2345             msg.c_str(), act_pos);
2346         return;
2347     }
2348 
2349     // set new line number/filename only if ok
2350     if (!file_name.empty()) {    // reuse current file name
2351         using boost::wave::util::impl::unescape_lit;
2352         act_pos.set_file(unescape_lit(file_name).c_str());
2353     }
2354     act_pos.set_line(line);
2355     if (iter_ctx->first != iter_ctx->last)
2356     {
2357       iter_ctx->first.set_position(act_pos);
2358     }
2359 }
2360 
2361 ///////////////////////////////////////////////////////////////////////////////
2362 //
2363 //  on_error(): handle #error directives
2364 //
2365 ///////////////////////////////////////////////////////////////////////////////
2366 template <typename ContextT>
2367 inline void
on_error(typename parse_tree_type::const_iterator const & begin,typename parse_tree_type::const_iterator const & end)2368 pp_iterator_functor<ContextT>::on_error(
2369     typename parse_tree_type::const_iterator const &begin,
2370     typename parse_tree_type::const_iterator const &end)
2371 {
2372     BOOST_ASSERT(ctx.get_if_block_status());
2373 
2374     // preprocess the given sequence into the provided list
2375     token_sequence_type expanded;
2376     get_token_value<result_type, parse_node_type> get_value;
2377 
2378     typename ref_transform_iterator_generator<
2379         get_token_value<result_type, parse_node_type>,
2380         typename parse_tree_type::const_iterator
2381     >::type first = make_ref_transform_iterator(begin, get_value);
2382 
2383 #if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0
2384     // preprocess the body of this #error message
2385     token_sequence_type toexpand;
2386 
2387     std::copy(first, make_ref_transform_iterator(end, get_value),
2388         std::inserter(toexpand, toexpand.end()));
2389 
2390     typename token_sequence_type::iterator begin2 = toexpand.begin();
2391     ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
2392                                    false, false);
2393     if (!ctx.get_hooks().found_error_directive(ctx.derived(), toexpand))
2394 #else
2395     // simply copy the body of this #error message to the issued diagnostic
2396     // message
2397     std::copy(first, make_ref_transform_iterator(end, get_value),
2398         std::inserter(expanded, expanded.end()));
2399     if (!ctx.get_hooks().found_error_directive(ctx.derived(), expanded))
2400 #endif
2401     {
2402         // report the corresponding error
2403         BOOST_WAVE_STRINGTYPE msg(boost::wave::util::impl::as_string(expanded));
2404         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, error_directive,
2405             msg.c_str(), act_pos);
2406     }
2407 }
2408 
2409 #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
2410 ///////////////////////////////////////////////////////////////////////////////
2411 //
2412 //  on_warning(): handle #warning directives
2413 //
2414 ///////////////////////////////////////////////////////////////////////////////
2415 template <typename ContextT>
2416 inline void
on_warning(typename parse_tree_type::const_iterator const & begin,typename parse_tree_type::const_iterator const & end)2417 pp_iterator_functor<ContextT>::on_warning(
2418     typename parse_tree_type::const_iterator const &begin,
2419     typename parse_tree_type::const_iterator const &end)
2420 {
2421     BOOST_ASSERT(ctx.get_if_block_status());
2422 
2423     // preprocess the given sequence into the provided list
2424     token_sequence_type expanded;
2425     get_token_value<result_type, parse_node_type> get_value;
2426 
2427     typename ref_transform_iterator_generator<
2428         get_token_value<result_type, parse_node_type>,
2429         typename parse_tree_type::const_iterator
2430     >::type first = make_ref_transform_iterator(begin, get_value);
2431 
2432 #if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0
2433     // preprocess the body of this #warning message
2434     token_sequence_type toexpand;
2435 
2436     std::copy(first, make_ref_transform_iterator(end, get_value),
2437         std::inserter(toexpand, toexpand.end()));
2438 
2439     typename token_sequence_type::iterator begin2 = toexpand.begin();
2440     ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
2441                                    false, false);
2442     if (!ctx.get_hooks().found_warning_directive(ctx.derived(), toexpand))
2443 #else
2444     // simply copy the body of this #warning message to the issued diagnostic
2445     // message
2446     std::copy(first, make_ref_transform_iterator(end, get_value),
2447         std::inserter(expanded, expanded.end()));
2448     if (!ctx.get_hooks().found_warning_directive(ctx.derived(), expanded))
2449 #endif
2450     {
2451         // report the corresponding error
2452         BOOST_WAVE_STRINGTYPE msg(boost::wave::util::impl::as_string(expanded));
2453         BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, warning_directive,
2454             msg.c_str(), act_pos);
2455     }
2456 }
2457 #endif // BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
2458 
2459 ///////////////////////////////////////////////////////////////////////////////
2460 //
2461 //  on_pragma(): handle #pragma directives
2462 //
2463 ///////////////////////////////////////////////////////////////////////////////
2464 template <typename ContextT>
2465 inline bool
on_pragma(typename parse_tree_type::const_iterator const & begin,typename parse_tree_type::const_iterator const & end)2466 pp_iterator_functor<ContextT>::on_pragma(
2467     typename parse_tree_type::const_iterator const &begin,
2468     typename parse_tree_type::const_iterator const &end)
2469 {
2470     using namespace boost::wave;
2471 
2472     BOOST_ASSERT(ctx.get_if_block_status());
2473 
2474     // Look at the pragma token sequence and decide, if the first token is STDC
2475     // (see C99 standard [6.10.6.2]), if it is, the sequence must _not_ be
2476     // preprocessed.
2477     token_sequence_type expanded;
2478     get_token_value<result_type, parse_node_type> get_value;
2479 
2480     typedef typename ref_transform_iterator_generator<
2481             get_token_value<result_type, parse_node_type>,
2482             typename parse_tree_type::const_iterator
2483         >::type const_tree_iterator_t;
2484 
2485     const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value);
2486     const_tree_iterator_t last = make_ref_transform_iterator(end, get_value);
2487 
2488     expanded.push_back(result_type(T_PP_PRAGMA, "#pragma", act_token.get_position()));
2489     expanded.push_back(result_type(T_SPACE, " ", act_token.get_position()));
2490 
2491     while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
2492         expanded.push_back(*first);   // skip whitespace
2493 
2494     if (first != last) {
2495         if (T_IDENTIFIER == token_id(*first) &&
2496             boost::wave::need_c99(ctx.get_language()) &&
2497             (*first).get_value() == "STDC")
2498         {
2499         // do _not_ preprocess the token sequence
2500             std::copy(first, last, std::inserter(expanded, expanded.end()));
2501         }
2502         else {
2503 #if BOOST_WAVE_PREPROCESS_PRAGMA_BODY != 0
2504             // preprocess the given tokensequence
2505             token_sequence_type toexpand;
2506 
2507             std::copy(first, last, std::inserter(toexpand, toexpand.end()));
2508 
2509             typename token_sequence_type::iterator begin2 = toexpand.begin();
2510             ctx.expand_whole_tokensequence(begin2, toexpand.end(),
2511                                            expanded, false, false);
2512 #else
2513             // do _not_ preprocess the token sequence
2514             std::copy(first, last, std::inserter(expanded, expanded.end()));
2515 #endif
2516         }
2517     }
2518     expanded.push_back(result_type(T_NEWLINE, "\n", act_token.get_position()));
2519 
2520     // the queues should be empty at this point
2521     BOOST_ASSERT(unput_queue.empty());
2522     BOOST_ASSERT(pending_queue.empty());
2523 
2524     // try to interpret the expanded #pragma body
2525     token_sequence_type pending;
2526     if (interpret_pragma(expanded, pending)) {
2527         // if there is some replacement text, insert it into the pending queue
2528         if (!pending.empty())
2529             pending_queue.splice(pending_queue.begin(), pending);
2530         return true;        // this #pragma was successfully recognized
2531     }
2532 
2533 #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
2534     // Move the resulting token sequence into the pending_queue, so it will be
2535     // returned to the caller.
2536     if (boost::wave::need_emit_pragma_directives(ctx.get_language())) {
2537         pending_queue.splice(pending_queue.begin(), expanded);
2538         return false;       // return the whole #pragma directive
2539     }
2540 #endif
2541     return true;            // skip the #pragma at all
2542 }
2543 
2544 template <typename ContextT>
2545 inline bool
interpret_pragma(token_sequence_type const & pragma_body,token_sequence_type & result)2546 pp_iterator_functor<ContextT>::interpret_pragma(
2547     token_sequence_type const &pragma_body, token_sequence_type &result)
2548 {
2549     using namespace cpplexer;
2550 
2551     typename token_sequence_type::const_iterator end = pragma_body.end();
2552     typename token_sequence_type::const_iterator it = pragma_body.begin();
2553     for (++it; it != end && IS_CATEGORY(*it, WhiteSpaceTokenType); ++it)
2554         /**/;   // skip whitespace
2555 
2556     if (it == end)      // eof reached
2557         return false;
2558 
2559     return boost::wave::util::interpret_pragma(
2560         ctx.derived(), act_token, it, end, result);
2561 }
2562 
2563 ///////////////////////////////////////////////////////////////////////////////
2564 }   // namespace impl
2565 
2566 ///////////////////////////////////////////////////////////////////////////////
2567 //
2568 //  pp_iterator
2569 //
2570 //      The boost::wave::pp_iterator template is the iterator, through which
2571 //      the resulting preprocessed input stream is accessible.
2572 //
2573 ///////////////////////////////////////////////////////////////////////////////
2574 
2575 template <typename ContextT>
2576 class pp_iterator
2577 :   public boost::spirit::classic::multi_pass<
2578         boost::wave::impl::pp_iterator_functor<ContextT>,
2579         boost::wave::util::functor_input
2580     >
2581 {
2582 public:
2583     typedef boost::wave::impl::pp_iterator_functor<ContextT> input_policy_type;
2584 
2585 private:
2586     typedef
2587         boost::spirit::classic::multi_pass<input_policy_type, boost::wave::util::functor_input>
2588         base_type;
2589     typedef pp_iterator<ContextT> self_type;
2590     typedef boost::wave::util::functor_input functor_input_type;
2591 
2592 public:
pp_iterator()2593     pp_iterator()
2594     {}
2595 
2596     template <typename IteratorT>
pp_iterator(ContextT & ctx,IteratorT const & first,IteratorT const & last,typename ContextT::position_type const & pos)2597     pp_iterator(ContextT &ctx, IteratorT const &first, IteratorT const &last,
2598         typename ContextT::position_type const &pos)
2599     :   base_type(input_policy_type(ctx, first, last, pos))
2600     {}
2601 
force_include(char const * path_,bool is_last)2602     bool force_include(char const *path_, bool is_last)
2603     {
2604         bool result = this->get_functor().on_include_helper(path_, path_,
2605             false, false);
2606         if (is_last) {
2607             this->functor_input_type::
2608                 template inner<input_policy_type>::advance_input();
2609         }
2610         return result;
2611     }
2612 };
2613 
2614 ///////////////////////////////////////////////////////////////////////////////
2615 }   // namespace wave
2616 }   // namespace boost
2617 
2618 // the suffix header occurs after all of the code
2619 #ifdef BOOST_HAS_ABI_HEADERS
2620 #include BOOST_ABI_SUFFIX
2621 #endif
2622 
2623 #endif // !defined(BOOST_CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED)
2624