Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/wave/util/cpp_iterator.hpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

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