Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/wave/util/cpp_macromap.hpp @ 30

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

updated boost from 1_33_1 to 1_34_1

File size: 65.3 KB
Line 
1/*=============================================================================
2    Boost.Wave: A Standard compliant C++ preprocessor library
3
4    Macro expansion engine
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_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED)
14#define CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED
15
16#include <cstdlib>
17#include <cstdio>
18#include <ctime>
19
20#include <list>
21#include <map>
22#include <set>
23#include <vector>
24#include <iterator>
25#include <algorithm>
26
27#include <boost/assert.hpp>
28#include <boost/wave/wave_config.hpp>
29#if BOOST_WAVE_SERIALIZATION != 0
30#include <boost/serialization/serialization.hpp>
31#include <boost/serialization/shared_ptr.hpp>
32#endif
33
34#include <boost/filesystem/path.hpp>
35
36#include <boost/wave/util/time_conversion_helper.hpp>
37#include <boost/wave/util/unput_queue_iterator.hpp>
38#include <boost/wave/util/macro_helpers.hpp>
39#include <boost/wave/util/macro_definition.hpp>
40#include <boost/wave/util/symbol_table.hpp>
41#include <boost/wave/util/cpp_macromap_utils.hpp>
42#include <boost/wave/util/cpp_macromap_predef.hpp>
43#include <boost/wave/grammars/cpp_defined_grammar_gen.hpp>
44
45#include <boost/wave/wave_version.hpp>
46#include <boost/wave/cpp_exceptions.hpp>
47#include <boost/wave/language_support.hpp>
48
49// this must occur after all of the includes and before any code appears
50#ifdef BOOST_HAS_ABI_HEADERS
51#include BOOST_ABI_PREFIX
52#endif
53
54///////////////////////////////////////////////////////////////////////////////
55namespace boost { namespace wave { namespace util {
56
57///////////////////////////////////////////////////////////////////////////////
58//
59//  macromap
60//
61//      This class holds all currently defined macros and on demand expands
62//      those macro definitions
63//
64///////////////////////////////////////////////////////////////////////////////
65template <typename ContextT>
66class macromap {
67
68    typedef macromap<ContextT>                      self_type;
69    typedef typename ContextT::token_type           token_type;
70    typedef typename token_type::string_type        string_type;
71    typedef typename token_type::position_type      position_type;
72       
73    typedef typename ContextT::token_sequence_type  definition_container_type;
74    typedef std::vector<token_type>                 parameter_container_type;
75   
76    typedef macro_definition<token_type, definition_container_type> 
77        macro_definition_type;
78    typedef symbol_table<string_type, macro_definition_type> 
79        defined_macros_type;
80    typedef typename defined_macros_type::value_type::second_type
81        macro_ref_type;
82
83public:
84    macromap(ContextT &ctx_) 
85    :   current_macros(0), defined_macros(new defined_macros_type(1)), 
86        main_pos("", 0), ctx(ctx_), macro_uid(1)
87    {
88        current_macros = defined_macros.get();
89    }
90    ~macromap() {}
91
92//  Add a new macro to the given macro scope
93    bool add_macro(token_type const &name, bool has_parameters, 
94        parameter_container_type &parameters, 
95        definition_container_type &definition, bool is_predefined = false, 
96        defined_macros_type *scope = 0);
97
98//  Tests, whether the given macro name is defined in the given macro scope
99    bool is_defined(string_type const &name, 
100        typename defined_macros_type::iterator &it, 
101        defined_macros_type *scope = 0) const;
102    template <typename IteratorT>
103    bool is_defined(IteratorT const &begin, IteratorT const &end);
104
105//  Get the macro definition for the given macro scope
106    bool get_macro(string_type const &name, bool &has_parameters, 
107        bool &is_predefined, position_type &pos, parameter_container_type &parameters, 
108        definition_container_type &definition, defined_macros_type *scope = 0);
109       
110//  Remove a macro name from the given macro scope
111    bool remove_macro(token_type const &token, bool even_predefined = false);
112   
113    template <typename IteratorT, typename ContainerT>
114    token_type const &expand_tokensequence(IteratorT &first, 
115        IteratorT const &last, ContainerT &pending, ContainerT &expanded, 
116        bool expand_operator_defined);
117
118//  Expand all macros inside the given token sequence
119    template <typename IteratorT, typename ContainerT>
120    void expand_whole_tokensequence(ContainerT &expanded, 
121        IteratorT &first, IteratorT const &last, 
122        bool expand_operator_defined);
123
124//  Init the predefined macros (add them to the given scope)
125    void init_predefined_macros(char const *fname = "<Unknown>", 
126        defined_macros_type *scope = 0, bool at_global_scope = true);
127    void predefine_macro(defined_macros_type *scope, string_type const &name, 
128        token_type const &t);
129       
130//  Init the internal macro symbol namespace
131    void reset_macromap();
132
133    position_type &get_main_pos() { return main_pos; }
134   
135protected:
136//  Helper functions for expanding all macros in token sequences
137    template <typename IteratorT, typename ContainerT>
138    token_type const &expand_tokensequence_worker(ContainerT &pending, 
139        unput_queue_iterator<IteratorT, token_type, ContainerT> &first, 
140        unput_queue_iterator<IteratorT, token_type, ContainerT> const &last, 
141        bool expand_operator_defined);
142
143//  Collect all arguments supplied to a macro invocation
144    template <typename IteratorT, typename ContainerT, typename SizeT>
145    typename std::vector<ContainerT>::size_type collect_arguments (
146        token_type const curr_token, std::vector<ContainerT> &arguments, 
147        IteratorT &next, IteratorT const &end, SizeT const &parameter_count);
148
149//  Expand a single macro name
150    template <typename IteratorT, typename ContainerT>
151    bool expand_macro(ContainerT &pending, token_type const &name, 
152        typename defined_macros_type::iterator it, 
153        IteratorT &first, IteratorT const &last, bool expand_operator_defined,
154        defined_macros_type *scope = 0, ContainerT *queue_symbol = 0);
155
156//  Expand a predefined macro (__LINE__, __FILE__ and __INCLUDE_LEVEL__)
157    template <typename ContainerT>
158    bool expand_predefined_macro(token_type const &curr_token, 
159        ContainerT &expanded);
160
161//  Expand a single macro argument
162    template <typename ContainerT>
163    void expand_argument (typename std::vector<ContainerT>::size_type arg,
164        std::vector<ContainerT> &arguments, 
165        std::vector<ContainerT> &expanded_args, bool expand_operator_defined,
166        std::vector<bool> &has_expanded_args);
167
168//  Expand the replacement list (replaces parameters with arguments)
169    template <typename ContainerT>
170    void expand_replacement_list(
171        macro_definition_type const &macrodefinition,
172        std::vector<ContainerT> &arguments, 
173        bool expand_operator_defined, ContainerT &expanded);
174
175//  Rescans the replacement list for macro expansion
176    template <typename IteratorT, typename ContainerT>
177    void rescan_replacement_list(token_type const &curr_token, 
178        macro_definition_type &macrodef, ContainerT &replacement_list, 
179        ContainerT &expanded, bool expand_operator_defined,
180        IteratorT &nfirst, IteratorT const &nlast);
181
182//  Resolves the operator defined() and replces the token with "0" or "1"
183    template <typename IteratorT, typename ContainerT>
184    token_type const &resolve_defined(IteratorT &first, IteratorT const &last,
185        ContainerT &expanded);
186       
187//  Resolve operator _Pragma or the #pragma directive
188    template <typename IteratorT, typename ContainerT>
189    bool resolve_operator_pragma(IteratorT &first, 
190        IteratorT const &last, ContainerT &expanded);
191
192//  Handle the concatenation operator '##'
193    template <typename ContainerT>
194    void concat_tokensequence(ContainerT &expanded);
195
196    template <typename ContainerT>
197    bool is_valid_concat(string_type new_value, 
198        position_type const &pos, ContainerT &rescanned);
199   
200#if BOOST_WAVE_SERIALIZATION != 0
201public:
202    BOOST_STATIC_CONSTANT(unsigned int, version = 0x10);
203    BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f);
204
205private:
206    friend class boost::serialization::access;
207    template<typename Archive>
208    void save(Archive &ar, const unsigned int version) const
209    {
210        ar & defined_macros;
211    }
212    template<typename Archive>
213    void load(Archive &ar, const unsigned int loaded_version)
214    {
215        if (version != (loaded_version & ~version_mask)) {
216            BOOST_WAVE_THROW(preprocess_exception, incompatible_config, 
217                "cpp_context state version", get_main_pos());
218        }
219        ar & defined_macros;
220        current_macros = defined_macros.get();
221    }
222    BOOST_SERIALIZATION_SPLIT_MEMBER()
223#endif
224
225private:
226    defined_macros_type *current_macros;                   // current symbol table
227    boost::shared_ptr<defined_macros_type> defined_macros; // global symbol table
228
229    token_type act_token;       // current token
230    position_type main_pos;     // last token position in the pp_iterator
231    string_type base_name;      // the name to be expanded by __BASE_FILE__
232    ContextT &ctx;              // context object associated with the macromap
233    long macro_uid;
234};
235///////////////////////////////////////////////////////////////////////////////
236
237///////////////////////////////////////////////////////////////////////////////
238//
239//  add_macro(): adds a new macro to the macromap
240//
241///////////////////////////////////////////////////////////////////////////////
242template <typename ContextT>
243inline bool 
244macromap<ContextT>::add_macro(token_type const &name, bool has_parameters, 
245    parameter_container_type &parameters, definition_container_type &definition, 
246    bool is_predefined, defined_macros_type *scope)
247{
248    if (!is_predefined && impl::is_special_macroname (name.get_value())) {
249    // exclude special macro names
250        BOOST_WAVE_THROW_NAME(macro_handling_exception, illegal_redefinition, 
251            name.get_value().c_str(), main_pos, name.get_value().c_str());
252    }
253    if (boost::wave::need_variadics(ctx.get_language()) && 
254        "__VA_ARGS__" == name.get_value()) 
255    {
256    // can't use __VA_ARGS__ as a macro name
257        BOOST_WAVE_THROW_NAME(macro_handling_exception, bad_define_statement_va_args, 
258            name.get_value().c_str(), main_pos, name.get_value().c_str());
259    }
260    if (AltExtTokenType == (token_id(name) & ExtTokenOnlyMask)) {
261    // exclude special operator names
262        BOOST_WAVE_THROW_NAME(macro_handling_exception, 
263            illegal_operator_redefinition, name.get_value().c_str(), main_pos,
264            name.get_value().c_str());
265    }
266   
267// try to define the new macro
268defined_macros_type *current_scope = scope ? scope : current_macros;
269typename defined_macros_type::iterator it = current_scope->find(name.get_value());
270
271    if (it != current_scope->end()) {
272    // redefinition, should not be different
273        if ((*it).second->is_functionlike != has_parameters ||
274            !impl::parameters_equal((*it).second->macroparameters, parameters) ||
275            !impl::definition_equals((*it).second->macrodefinition, definition))
276        {
277            BOOST_WAVE_THROW_NAME(macro_handling_exception, macro_redefinition, 
278                name.get_value().c_str(), main_pos, name.get_value().c_str());
279        }
280        return false;
281    }
282
283// test the validity of the parameter names
284    if (has_parameters) {
285        std::set<typename token_type::string_type> names;
286   
287        typedef typename parameter_container_type::iterator
288            parameter_iterator_type;
289        typedef typename std::set<typename token_type::string_type>::iterator
290            name_iterator_type;
291           
292        parameter_iterator_type end = parameters.end();
293        for (parameter_iterator_type itp = parameters.begin(); itp != end; ++itp) 
294        {
295        name_iterator_type pit = names.find((*itp).get_value());
296       
297            if (pit != names.end()) {
298            // duplicate parameter name
299                BOOST_WAVE_THROW_NAME(macro_handling_exception, 
300                    duplicate_parameter_name, (*pit).c_str(), main_pos, 
301                    name.get_value().c_str());
302            }
303            names.insert((*itp).get_value());
304        }
305    }
306   
307// insert a new macro node
308    std::pair<typename defined_macros_type::iterator, bool> p = 
309        current_scope->insert(
310            typename defined_macros_type::value_type(
311                name.get_value(), 
312                macro_ref_type(new macro_definition_type(name, 
313                    has_parameters, is_predefined, ++macro_uid)
314                )
315            )
316        );
317
318    if (!p.second) {
319        BOOST_WAVE_THROW_NAME(macro_handling_exception, macro_insertion_error, 
320            name.get_value().c_str(), main_pos, name.get_value().c_str());
321    }
322
323// add the parameters and the definition
324    std::swap((*p.first).second->macroparameters, parameters);
325    std::swap((*p.first).second->macrodefinition, definition);
326   
327// call the context supplied preprocessing hook
328    ctx.get_hooks().defined_macro(name, has_parameters, 
329        (*p.first).second->macroparameters, 
330        (*p.first).second->macrodefinition, is_predefined);
331    return true;
332}
333
334///////////////////////////////////////////////////////////////////////////////
335//
336//  is_defined(): returns, whether a given macro is already defined
337//
338///////////////////////////////////////////////////////////////////////////////
339template <typename ContextT>
340inline bool 
341macromap<ContextT>::is_defined(typename token_type::string_type const &name,
342    typename defined_macros_type::iterator &it, 
343    defined_macros_type *scope) const
344{
345    if (0 == scope) scope = current_macros;
346   
347    if ((it = scope->find(name)) != scope->end())
348        return true;        // found in symbol table
349
350// quick pre-check
351    if (name.size() < 8 || '_' != name[0] || '_' != name[1])
352        return false;       // quick check failed
353
354    return name == "__LINE__" || name == "__FILE__" || 
355        name == "__INCLUDE_LEVEL__";
356}
357
358template <typename ContextT>
359template <typename IteratorT>
360inline bool 
361macromap<ContextT>::is_defined(IteratorT const &begin, 
362    IteratorT const &end) 
363{
364// in normal mode the name under inspection should consist of an identifier
365// only
366token_id id = token_id(*begin);
367
368    if (T_IDENTIFIER != id && 
369        !IS_CATEGORY(id, KeywordTokenType) &&
370        !IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) &&
371        !IS_CATEGORY(id, BoolLiteralTokenType)) 
372    {
373        BOOST_WAVE_THROW(preprocess_exception, invalid_macroname, 
374            impl::get_full_name(begin, end).c_str(), main_pos);
375    }
376
377IteratorT it = begin;
378string_type name ((*it).get_value());
379typename defined_macros_type::iterator cit(current_macros -> find(name));
380
381    if (++it != end) {
382    // there should be only one token as the inspected name
383        BOOST_WAVE_THROW(preprocess_exception, invalid_macroname, 
384            impl::get_full_name(begin, end).c_str(), main_pos);
385    }
386    return cit != current_macros -> end();
387}
388
389///////////////////////////////////////////////////////////////////////////////
390//
391//  Get the macro definition for the given macro scope
392//
393///////////////////////////////////////////////////////////////////////////////
394template <typename ContextT>
395inline bool 
396macromap<ContextT>::get_macro(string_type const &name, bool &has_parameters, 
397    bool &is_predefined, position_type &pos, 
398    parameter_container_type &parameters, 
399    definition_container_type &definition, 
400    defined_macros_type *scope)
401{
402    typename defined_macros_type::iterator it;
403    if (!is_defined(name, it, scope))
404        return false;
405       
406macro_definition_type &macro_def = *(*it).second.get();
407
408    has_parameters = macro_def.is_functionlike;
409    is_predefined = macro_def.is_predefined;
410    pos = macro_def.macroname.get_position();
411    parameters = macro_def.macroparameters;
412    definition = macro_def.macrodefinition;
413    return true;
414}
415
416///////////////////////////////////////////////////////////////////////////////
417//
418//  remove_macro(): remove a macro from the macromap
419//
420///////////////////////////////////////////////////////////////////////////////
421template <typename ContextT>
422inline bool 
423macromap<ContextT>::remove_macro(token_type const &token, 
424    bool even_predefined)
425{
426    string_type name (token.get_value());
427    typename defined_macros_type::iterator it = current_macros->find(name);
428   
429    if (it != current_macros->end()) {
430        if ((*it).second->is_predefined) {
431            if (!even_predefined || impl::is_special_macroname(name)) {
432                BOOST_WAVE_THROW(preprocess_exception, bad_undefine_statement, 
433                    name.c_str(), main_pos);
434            }
435        }
436        current_macros->erase(it);
437       
438    // call the context supplied preprocessing hook function
439        ctx.get_hooks().undefined_macro(token);
440        return true;
441    }
442    else if (impl::is_special_macroname(name)) {
443        BOOST_WAVE_THROW(preprocess_exception, bad_undefine_statement, 
444            name.c_str(), main_pos);
445    }
446    return false;       // macro was not defined
447}
448
449///////////////////////////////////////////////////////////////////////////////
450//
451//  expand_tokensequence
452//
453//      This function is a helper function which wraps the given iterator
454//      range into corresponding unput_iterator's and calls the main workhorse
455//      of the macro expansion engine (the function expand_tokensequence_worker)
456//
457//      This is the top level macro expansion function called from the
458//      preprocessing iterator component only.
459//
460///////////////////////////////////////////////////////////////////////////////
461template <typename ContextT>
462template <typename IteratorT, typename ContainerT>
463inline typename ContextT::token_type const &
464macromap<ContextT>::expand_tokensequence(IteratorT &first, 
465    IteratorT const &last, ContainerT &pending, ContainerT &expanded, 
466    bool expand_operator_defined)
467{
468    typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT> 
469        gen_type;
470    typedef typename gen_type::return_type iterator_type;
471
472    iterator_type first_it = gen_type::generate(expanded, first);
473    iterator_type last_it = gen_type::generate(last);
474
475on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
476
477    return expand_tokensequence_worker(pending, first_it, last_it, 
478        expand_operator_defined);
479}
480
481///////////////////////////////////////////////////////////////////////////////
482//
483//  expand_tokensequence_worker
484//
485//      This function is the main workhorse of the macro expansion engine. It
486//      expands as much tokens as needed to identify the next preprocessed
487//      token to return to the caller.
488//      It returns the next preprocessed token.
489//
490//      The iterator 'first' is adjusted accordingly.
491//
492///////////////////////////////////////////////////////////////////////////////
493template <typename ContextT>
494template <typename IteratorT, typename ContainerT>
495inline typename ContextT::token_type const &
496macromap<ContextT>::expand_tokensequence_worker(
497    ContainerT &pending, 
498    unput_queue_iterator<IteratorT, token_type, ContainerT> &first, 
499    unput_queue_iterator<IteratorT, token_type, ContainerT> const &last, 
500    bool expand_operator_defined)
501{
502// if there exist pending tokens (tokens, which are already preprocessed), then
503// return the next one from there
504    if (!pending.empty()) {
505    on_exit::pop_front<definition_container_type> pop_front_token(pending);
506   
507        return act_token = pending.front();
508    }
509
510//  analyze the next element of the given sequence, if it is an
511//  T_IDENTIFIER token, try to replace this as a macro etc.
512    using namespace boost::wave;
513    typedef unput_queue_iterator<IteratorT, token_type, ContainerT> iterator_type;
514   
515    if (first != last) {
516    token_id id = token_id(*first);
517
518    // ignore placeholder tokens
519        if (T_PLACEHOLDER == id) {
520        token_type placeholder = *first;
521       
522            ++first;
523            if (first == last)
524                return act_token = placeholder;
525            id = token_id(*first);
526        }
527           
528        if (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType) ||
529            IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
530            IS_CATEGORY(id, BoolLiteralTokenType)) 
531        {
532        // try to replace this identifier as a macro
533            if (expand_operator_defined && (*first).get_value() == "defined") {
534            // resolve operator defined()
535                return resolve_defined(first, last, pending);
536            }
537            else if (boost::wave::need_variadics(ctx.get_language()) && 
538                (*first).get_value() == "_Pragma") 
539            {
540            // in C99 mode only: resolve the operator _Pragma
541            token_type curr_token = *first;
542           
543                if (!resolve_operator_pragma(first, last, pending) ||
544                    pending.size() > 0) 
545                {
546                // unknown to us pragma or supplied replacement, return the
547                // next token
548                on_exit::pop_front<definition_container_type> pop_token(pending);
549
550                    return act_token = pending.front();
551                }
552               
553            // the operator _Pragma() was eaten completely, continue
554                return act_token = token_type(T_PLACEHOLDER, "_", 
555                    curr_token.get_position());
556            }
557
558        token_type name_token (*first);
559        typename defined_macros_type::iterator it;
560       
561            if (is_defined(name_token.get_value(), it)) {
562            // the current token contains an identifier, which is currently
563            // defined as a macro
564                if (expand_macro(pending, name_token, it, first, last, 
565                    expand_operator_defined)) 
566                {
567                // the tokens returned by expand_macro should be rescanned
568                // beginning at the last token of the returned replacement list
569                    if (first != last) {
570                    // splice the last token back into the input queue
571                    typename ContainerT::reverse_iterator rit = pending.rbegin();
572                   
573                        first.get_unput_queue().splice(
574                            first.get_unput_queue().begin(), pending,
575                            (++rit).base(), pending.end());
576                    }
577                                           
578                // fall through ...
579                }
580                else if (!pending.empty()) {
581                // return the first token from the pending queue
582                on_exit::pop_front<definition_container_type> pop_queue (pending);
583               
584                    return act_token = pending.front();
585                }
586                else {
587                // macro expansion reached the eoi
588                    return act_token = token_type();
589                }
590
591            // return the next preprocessed token
592                return expand_tokensequence_worker(pending, first, last, 
593                    expand_operator_defined);
594            }
595//            else if (expand_operator_defined) {
596//            // in preprocessing conditionals undefined identifiers and keywords
597//            // are to be replaced with '0' (see. C++ standard 16.1.4, [cpp.cond])
598//                return act_token =
599//                    token_type(T_INTLIT, "0", (*first++).get_position());
600//            }
601            else {
602                act_token = name_token;
603                ++first;
604                return act_token;
605            }
606        }
607        else if (expand_operator_defined && IS_CATEGORY(*first, BoolLiteralTokenType)) {
608        // expanding a constant expression inside #if/#elif, special handling
609        // of 'true' and 'false'       
610
611        // all remaining identifiers and keywords, except for true and false,
612        // are replaced with the pp-number 0 (C++ standard 16.1.4, [cpp.cond])
613            return act_token = token_type(T_INTLIT, T_TRUE != id ? "0" : "1", 
614                (*first++).get_position());
615        }
616        else {
617            act_token = *first;
618            ++first;
619            return act_token;
620        }
621    }
622    return act_token = token_type();     // eoi
623}
624
625///////////////////////////////////////////////////////////////////////////////
626//
627//  collect_arguments(): collect the actual arguments of a macro invocation
628//
629//      return the number of successfully detected non-empty arguments
630//
631///////////////////////////////////////////////////////////////////////////////
632template <typename ContextT>
633template <typename IteratorT, typename ContainerT, typename SizeT>
634inline typename std::vector<ContainerT>::size_type
635macromap<ContextT>::collect_arguments (token_type const curr_token, 
636    std::vector<ContainerT> &arguments, IteratorT &next, IteratorT const &end, 
637    SizeT const &parameter_count)
638{
639    using namespace boost::wave;
640
641    arguments.push_back(ContainerT());
642   
643// collect the actual arguments
644typename std::vector<ContainerT>::size_type count_arguments = 0;
645int nested_parenthesis_level = 1;
646ContainerT *argument = &arguments[0];
647bool was_whitespace = false;
648token_type startof_argument_list = *next;
649
650    while (++next != end && nested_parenthesis_level) {
651    token_id id = token_id(*next);
652
653        if (0 == parameter_count && 
654            !IS_CATEGORY((*next), WhiteSpaceTokenType) && id != T_NEWLINE &&
655            id != T_RIGHTPAREN && id != T_LEFTPAREN) 
656        {
657        // there shouldn't be any arguments
658            BOOST_WAVE_THROW(preprocess_exception, too_many_macroarguments, 
659                curr_token.get_value().c_str(), main_pos);
660        }
661       
662        switch (static_cast<unsigned int>(id)) {
663        case T_LEFTPAREN:
664            ++nested_parenthesis_level;
665            argument->push_back(*next);
666            was_whitespace = false;
667            break;
668           
669        case T_RIGHTPAREN:
670            {
671                if (--nested_parenthesis_level >= 1)
672                    argument->push_back(*next);
673                else {
674                // found closing parenthesis
675//                    trim_sequence(argument);
676                    if (parameter_count > 0) {
677                        if (argument->empty() || 
678                            impl::is_whitespace_only(*argument)) 
679                        {
680#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
681                            if (boost::wave::need_variadics(ctx.get_language())) {
682                            // store a placemarker as the argument
683                                argument->push_back(token_type(T_PLACEMARKER, "§", 
684                                    (*next).get_position()));
685                                ++count_arguments;
686                            }
687#endif
688                        }
689                        else {
690                            ++count_arguments;
691                        }
692                    }
693                }
694                was_whitespace = false;
695            }
696            break;
697       
698        case T_COMMA:
699            if (1 == nested_parenthesis_level) {
700            // next parameter
701//                trim_sequence(argument);
702                if (argument->empty() || 
703                    impl::is_whitespace_only(*argument)) 
704                {
705#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
706                    if (boost::wave::need_variadics(ctx.get_language())) {
707                    // store a placemarker as the argument
708                        argument->push_back(token_type(T_PLACEMARKER, "§", 
709                            (*next).get_position()));
710                        ++count_arguments;
711                    }
712#endif
713                }
714                else {
715                    ++count_arguments;
716                }
717                arguments.push_back(ContainerT()); // add new arg
718                argument = &arguments[arguments.size()-1];
719            }
720            else {
721            // surrounded by parenthesises, so store to current argument
722                argument->push_back(*next);
723            }
724            was_whitespace = false;
725            break;
726
727        case T_SPACE:
728        case T_SPACE2:
729        case T_CCOMMENT:
730        case T_NEWLINE:
731            if (!was_whitespace) 
732                argument->push_back(token_type(T_SPACE, " ", (*next).get_position()));
733            was_whitespace = true;
734            break;      // skip whitespace
735
736        case T_PLACEHOLDER:
737            break;      // ignore placeholder
738                       
739        default:
740            argument->push_back(*next);
741            was_whitespace = false;
742            break;
743        }
744    }
745
746    if (nested_parenthesis_level >= 1) {
747    // missing ')': improperly terminated macro invocation
748        BOOST_WAVE_THROW(preprocess_exception, improperly_terminated_macro, 
749            "missing ')'", main_pos);
750    }
751
752// if there isn't expected any argument and there really wasn't found any,
753// than remove the empty element
754    if (0 == parameter_count && 0 == count_arguments) {
755        BOOST_ASSERT(1 == arguments.size());
756        arguments.clear();
757    }
758    return count_arguments;
759}       
760
761///////////////////////////////////////////////////////////////////////////////
762//
763//  expand_whole_tokensequence
764//
765//      fully expands a given token sequence
766//
767///////////////////////////////////////////////////////////////////////////////
768template <typename ContextT>
769template <typename IteratorT, typename ContainerT>
770inline void
771macromap<ContextT>::expand_whole_tokensequence(ContainerT &expanded, 
772    IteratorT &first, IteratorT const &last, 
773    bool expand_operator_defined)
774{
775    typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT> 
776        gen_type;
777    typedef typename gen_type::return_type iterator_type;
778
779iterator_type first_it = gen_type::generate(first);
780iterator_type last_it = gen_type::generate(last);
781
782on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
783ContainerT pending_queue;
784   
785    while (!pending_queue.empty() || first_it != last_it) {
786        token_type t = expand_tokensequence_worker(pending_queue, first_it, 
787                    last_it, expand_operator_defined);
788
789        expanded.push_back(t);
790    }
791
792// should have returned all expanded tokens
793    BOOST_ASSERT(pending_queue.empty()/* && unput_queue.empty()*/);
794}
795
796///////////////////////////////////////////////////////////////////////////////
797//
798//  expand_argument
799//
800//      fully expands the given argument of a macro call
801//
802///////////////////////////////////////////////////////////////////////////////
803template <typename ContextT>
804template <typename ContainerT>
805inline void 
806macromap<ContextT>::expand_argument (
807    typename std::vector<ContainerT>::size_type arg, 
808    std::vector<ContainerT> &arguments, std::vector<ContainerT> &expanded_args, 
809    bool expand_operator_defined, std::vector<bool> &has_expanded_args)
810{
811    if (!has_expanded_args[arg]) {
812    // expand the argument only once
813        typedef typename std::vector<ContainerT>::value_type::iterator
814            argument_iterator_type;
815           
816        argument_iterator_type begin_it = arguments[arg].begin();
817        argument_iterator_type end_it = arguments[arg].end();
818       
819        expand_whole_tokensequence(expanded_args[arg], begin_it, end_it,
820            expand_operator_defined);
821        impl::remove_placeholders(expanded_args[arg]);
822        has_expanded_args[arg] = true;
823    }
824}
825                   
826///////////////////////////////////////////////////////////////////////////////
827//
828//  expand_replacement_list
829//
830//      fully expands the replacement list of a given macro with the
831//      actual arguments/expanded arguments
832//      handles the '#' [cpp.stringize] and the '##' [cpp.concat] operator
833//
834///////////////////////////////////////////////////////////////////////////////
835template <typename ContextT>
836template <typename ContainerT>
837inline void
838macromap<ContextT>::expand_replacement_list(
839    macro_definition_type const &macrodef,
840    std::vector<ContainerT> &arguments, bool expand_operator_defined, 
841    ContainerT &expanded)
842{
843    using namespace boost::wave;
844    typedef typename macro_definition_type::const_definition_iterator_t
845        macro_definition_iter_t;
846
847std::vector<ContainerT> expanded_args(arguments.size());
848std::vector<bool> has_expanded_args(arguments.size());
849bool seen_concat = false;
850bool adjacent_concat = false;
851bool adjacent_stringize = false;
852
853    macro_definition_iter_t cend = macrodef.macrodefinition.end();
854    for (macro_definition_iter_t cit = macrodef.macrodefinition.begin();
855        cit != cend; ++cit)
856    {
857    bool use_replaced_arg = true;
858    token_id base_id = BASE_TOKEN(token_id(*cit));
859   
860        if (T_POUND_POUND == base_id) {
861        // concatenation operator
862            adjacent_concat = true;
863            seen_concat = true;
864        }
865        else if (T_POUND == base_id) {
866        // stringize operator
867            adjacent_stringize = true;
868        }
869        else {
870            if (adjacent_stringize || adjacent_concat || 
871                T_POUND_POUND == impl::next_token<macro_definition_iter_t>
872                    ::peek(cit, cend))
873            {
874                use_replaced_arg = false;
875            }
876            if (adjacent_concat)    // spaces after '##' ?
877                adjacent_concat = IS_CATEGORY(*cit, WhiteSpaceTokenType);
878        }
879
880        if (IS_CATEGORY((*cit), ParameterTokenType)) {
881        // copy argument 'i' instead of the parameter token i
882        typename ContainerT::size_type i;
883#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
884        bool is_ellipsis = false;
885       
886            if (IS_EXTCATEGORY((*cit), ExtParameterTokenType)) {
887                BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
888                i = token_id(*cit) - T_EXTPARAMETERBASE;
889                is_ellipsis = true;
890            } 
891            else 
892#endif
893            {
894                i = token_id(*cit) - T_PARAMETERBASE;
895            }
896           
897            BOOST_ASSERT(i < arguments.size());
898            if (use_replaced_arg) {
899               
900#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
901                if (is_ellipsis) {
902                position_type const &pos = (*cit).get_position();
903
904                    BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
905                   
906                // ensure all variadic arguments to be expanded
907                    for (typename vector<ContainerT>::size_type arg = i; 
908                         arg < expanded_args.size(); ++arg)
909                    {
910                        expand_argument(arg, arguments, expanded_args, 
911                            expand_operator_defined, has_expanded_args);
912                    }
913                    impl::replace_ellipsis(expanded_args, i, expanded, pos);
914                }
915                else 
916#endif
917                {
918                // ensure argument i to be expanded
919                    expand_argument(i, arguments, expanded_args, 
920                        expand_operator_defined, has_expanded_args);
921                   
922                // replace argument
923                ContainerT const &arg = expanded_args[i];
924               
925                    std::copy(arg.begin(), arg.end(), 
926                        std::inserter(expanded, expanded.end()));
927                }
928            }
929            else if (adjacent_stringize && 
930                    !IS_CATEGORY(*cit, WhiteSpaceTokenType)) 
931            {
932            // stringize the current argument
933                BOOST_ASSERT(!arguments[i].empty());
934               
935            // safe a copy of the first tokens position (not a reference!)
936            position_type pos ((*arguments[i].begin()).get_position());
937
938#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
939                if (is_ellipsis && boost::wave::need_variadics(ctx.get_language())) {
940                    impl::trim_sequence_left(arguments[i]);
941                    impl::trim_sequence_right(arguments.back());
942                    expanded.push_back(token_type(T_STRINGLIT, 
943                        impl::as_stringlit(arguments, i, pos), pos));
944                }
945                else 
946#endif
947                {
948                    impl::trim_sequence(arguments[i]);
949                    expanded.push_back(token_type(T_STRINGLIT, 
950                        impl::as_stringlit(arguments[i], pos), pos));
951                }
952                adjacent_stringize = false;
953            }
954            else {
955            // simply copy the original argument (adjacent '##' or '#')
956#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
957                if (is_ellipsis) {
958                position_type const &pos = (*cit).get_position();
959
960                    impl::trim_sequence_left(arguments[i]);
961                    impl::trim_sequence_right(arguments.back());
962                    BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
963                    impl::replace_ellipsis(arguments, i, expanded, pos);
964                }
965                else
966#endif
967                {
968                ContainerT &arg = arguments[i];
969               
970                    impl::trim_sequence(arg);
971                    std::copy(arg.begin(), arg.end(), 
972                        std::inserter(expanded, expanded.end()));
973                }
974            }
975        }
976        else if (!adjacent_stringize || T_POUND != base_id) {
977        // insert the actual replacement token (if it is not the '#' operator)
978            expanded.push_back(*cit);
979        }
980    }
981
982    if (adjacent_stringize) {
983    // error, '#' should not be the last token
984        BOOST_WAVE_THROW(preprocess_exception, ill_formed_operator,
985            "stringize ('#')", main_pos);
986    }
987       
988// handle the cpp.concat operator
989    if (seen_concat)
990        concat_tokensequence(expanded);
991}
992
993///////////////////////////////////////////////////////////////////////////////
994//
995//  rescan_replacement_list
996//
997//    As the name implies, this function is used to rescan the replacement list
998//    after the first macro substitution phase.
999//
1000///////////////////////////////////////////////////////////////////////////////
1001template <typename ContextT>
1002template <typename IteratorT, typename ContainerT>
1003inline void 
1004macromap<ContextT>::rescan_replacement_list(token_type const &curr_token, 
1005    macro_definition_type &macro_def, ContainerT &replacement_list, 
1006    ContainerT &expanded, bool expand_operator_defined,
1007    IteratorT &nfirst, IteratorT const &nlast)
1008{
1009    if (!replacement_list.empty()) {
1010#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1011    // remove the placemarkers
1012        if (boost::wave::need_variadics(ctx.get_language())) {
1013        typename ContainerT::iterator end = replacement_list.end();
1014        typename ContainerT::iterator it = replacement_list.begin();
1015       
1016            while (it != end) {
1017                using namespace boost::wave;
1018                if (T_PLACEMARKER == token_id(*it)) {
1019                typename ContainerT::iterator placemarker = it;
1020               
1021                    ++it;
1022                    replacement_list.erase(placemarker);
1023                }
1024                else {
1025                    ++it;
1026                }
1027            }
1028        }
1029#endif
1030
1031    // rescan the replacement list, during this rescan the current macro under
1032    // expansion isn't available as an expandable macro
1033    on_exit::reset<bool> on_exit(macro_def.is_available_for_replacement, false);
1034    typename ContainerT::iterator begin_it = replacement_list.begin();
1035    typename ContainerT::iterator end_it = replacement_list.end();
1036   
1037        expand_whole_tokensequence(expanded, begin_it, end_it, 
1038            expand_operator_defined);     
1039       
1040    // trim replacement list, leave placeholder tokens untouched
1041        impl::trim_replacement_list(expanded);
1042    }
1043   
1044    if (expanded.empty()) {
1045    // the resulting replacement list should contain at least a placeholder
1046    // token
1047        expanded.push_back(token_type(T_PLACEHOLDER, "_", curr_token.get_position()));
1048    }
1049}
1050
1051///////////////////////////////////////////////////////////////////////////////
1052//
1053//  expand_macro(): expands a defined macro
1054//
1055//      This functions tries to expand the macro, to which points the 'first'
1056//      iterator. The functions eats up more tokens, if the macro to expand is
1057//      a function-like macro.
1058//
1059///////////////////////////////////////////////////////////////////////////////
1060template <typename ContextT>
1061template <typename IteratorT, typename ContainerT>
1062inline bool 
1063macromap<ContextT>::expand_macro(ContainerT &expanded, 
1064    token_type const &curr_token, typename defined_macros_type::iterator it, 
1065    IteratorT &first, IteratorT const &last, 
1066    bool expand_operator_defined, defined_macros_type *scope, 
1067    ContainerT *queue_symbol) 
1068{
1069    using namespace boost::wave;
1070   
1071    if (0 == scope) scope = current_macros;
1072   
1073    BOOST_ASSERT(T_IDENTIFIER == token_id(curr_token) ||
1074        IS_CATEGORY(token_id(curr_token), KeywordTokenType) ||
1075        IS_EXTCATEGORY(token_id(curr_token), OperatorTokenType|AltExtTokenType) ||
1076        IS_CATEGORY(token_id(curr_token), BoolLiteralTokenType));
1077       
1078    if (it == scope->end()) {
1079        ++first;    // advance
1080
1081    // try to expand a predefined macro (__FILE__, __LINE__ or __INCLUDE_LEVEL__)
1082        if (expand_predefined_macro(curr_token, expanded))
1083            return false;
1084       
1085    // not defined as a macro
1086        if (0 != queue_symbol) {
1087            expanded.splice(expanded.end(), *queue_symbol);
1088        }
1089        else {
1090            expanded.push_back(curr_token);
1091        }
1092        return false;
1093    }
1094
1095// ensure the parameters to be replaced with special parameter tokens
1096macro_definition_type &macro_def = *(*it).second.get();
1097
1098    macro_def.replace_parameters();
1099
1100// test if this macro is currently available for replacement
1101    if (!macro_def.is_available_for_replacement) {
1102    // this macro is marked as non-replaceable
1103    // copy the macro name itself
1104        if (0 != queue_symbol) {
1105            queue_symbol->push_back(token_type(T_NONREPLACABLE_IDENTIFIER,
1106                curr_token.get_value(), curr_token.get_position()));
1107            expanded.splice(expanded.end(), *queue_symbol);
1108        }
1109        else {
1110            expanded.push_back(token_type(T_NONREPLACABLE_IDENTIFIER,
1111                curr_token.get_value(), curr_token.get_position()));
1112        }
1113        ++first;
1114        return false;
1115    }
1116
1117// try to replace the current identifier as a function-like macro
1118ContainerT replacement_list;
1119
1120    if (T_LEFTPAREN == impl::next_token<IteratorT>::peek(first, last)) {
1121    // called as a function-like macro
1122        impl::skip_to_token(first, last, T_LEFTPAREN);
1123       
1124        if (macro_def.is_functionlike) {
1125        // defined as a function-like macro
1126       
1127        // collect the arguments
1128        std::vector<ContainerT> arguments;
1129        typename std::vector<ContainerT>::size_type count_args = 
1130            collect_arguments (curr_token, arguments, first, last, 
1131                macro_def.macroparameters.size());
1132
1133        // verify the parameter count
1134            if (count_args < macro_def.macroparameters.size() ||
1135                arguments.size() < macro_def.macroparameters.size()) 
1136            {
1137                if (count_args != arguments.size()) {
1138                // must been at least one empty argument in C++ mode
1139                    BOOST_WAVE_THROW(preprocess_exception, 
1140                        empty_macroarguments, curr_token.get_value().c_str(), 
1141                        main_pos);
1142                }
1143                else {
1144                // too few macro arguments
1145                    BOOST_WAVE_THROW(preprocess_exception, 
1146                        too_few_macroarguments, curr_token.get_value().c_str(), 
1147                        main_pos);
1148                }
1149            }
1150           
1151            if (count_args > macro_def.macroparameters.size() ||
1152                arguments.size() > macro_def.macroparameters.size()) 
1153            {
1154#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1155                if (!macro_def.has_ellipsis) 
1156#endif
1157                {
1158                // too many macro arguments
1159                    BOOST_WAVE_THROW(preprocess_exception, too_many_macroarguments, 
1160                        curr_token.get_value().c_str(), main_pos);
1161                }
1162            }
1163               
1164        // inject tracing support
1165            ctx.get_hooks().expanding_function_like_macro(
1166                macro_def.macroname, macro_def.macroparameters, 
1167                macro_def.macrodefinition, curr_token, arguments);
1168       
1169        // expand the replacement list of this macro
1170            expand_replacement_list(macro_def, arguments, expand_operator_defined,
1171                replacement_list);
1172        }
1173        else {
1174        // defined as an object-like macro
1175            ctx.get_hooks().expanding_object_like_macro(
1176                macro_def.macroname, macro_def.macrodefinition, curr_token);
1177
1178        bool found = false;
1179        impl::find_concat_operator concat_tag(found);
1180       
1181            std::remove_copy_if(macro_def.macrodefinition.begin(), 
1182                macro_def.macrodefinition.end(), 
1183                std::inserter(replacement_list, replacement_list.end()),
1184                concat_tag);
1185               
1186        // handle concatenation operators
1187            if (found)
1188                concat_tokensequence(replacement_list);
1189        }
1190    }
1191    else {
1192    // called as an object like macro
1193        if ((*it).second->is_functionlike) {
1194        // defined as a function-like macro
1195            if (0 != queue_symbol) {
1196                queue_symbol->push_back(curr_token);
1197                expanded.splice(expanded.end(), *queue_symbol);
1198            }
1199            else {
1200                expanded.push_back(curr_token);
1201            }
1202            ++first;                // skip macro name
1203            return false;           // no further preprocessing required
1204        }
1205        else {
1206        // defined as an object-like macro (expand it)
1207            ctx.get_hooks().expanding_object_like_macro(
1208                macro_def.macroname, macro_def.macrodefinition, curr_token);
1209
1210        bool found = false;
1211        impl::find_concat_operator concat_tag(found);
1212       
1213            std::remove_copy_if(macro_def.macrodefinition.begin(), 
1214                macro_def.macrodefinition.end(), 
1215                std::inserter(replacement_list, replacement_list.end()),
1216                concat_tag);
1217
1218        // handle concatenation operators
1219            if (found)
1220                concat_tokensequence(replacement_list);
1221
1222            ++first;                // skip macro name
1223        }
1224    }
1225
1226// rescan the replacement list
1227ContainerT expanded_list;
1228
1229    ctx.get_hooks().expanded_macro(replacement_list);
1230   
1231    rescan_replacement_list(curr_token, macro_def, replacement_list, 
1232        expanded_list, expand_operator_defined, first, last);
1233   
1234    ctx.get_hooks().rescanned_macro(expanded_list); 
1235    expanded.splice(expanded.end(), expanded_list);
1236    return true;        // rescan is required
1237}
1238
1239///////////////////////////////////////////////////////////////////////////////
1240//
1241//  If the token under inspection points to a certain predefined macro it will
1242//  be expanded, otherwise false is returned.
1243//  (only __FILE__, __LINE__ and __INCLUDE_LEVEL__ macros are expaned here)
1244//
1245///////////////////////////////////////////////////////////////////////////////
1246template <typename ContextT>
1247template <typename ContainerT>
1248inline bool 
1249macromap<ContextT>::expand_predefined_macro(token_type const &curr_token, 
1250    ContainerT &expanded)
1251{
1252    using namespace boost::wave;
1253   
1254string_type const &value = curr_token.get_value();
1255
1256    if (value.size() < 8 || '_' != value[0] || '_' != value[1])
1257        return false;       // quick check failed
1258       
1259    if (value == "__LINE__") { 
1260    // expand the __LINE__ macro
1261    char buffer[22];    // 21 bytes holds all NUL-terminated unsigned 64-bit numbers
1262
1263        using namespace std;    // for some systems sprintf is in namespace std
1264        sprintf(buffer, "%d", main_pos.get_line());
1265        expanded.push_back(token_type(T_INTLIT, buffer, curr_token.get_position()));
1266        return true;
1267    }
1268    else if (value == "__FILE__") {
1269    // expand the __FILE__ macro
1270        namespace fs = boost::filesystem;
1271       
1272    std::string file("\"");
1273    fs::path filename(main_pos.get_file().c_str(), fs::native);
1274   
1275        using boost::wave::util::impl::escape_lit;
1276        file += escape_lit(filename.native_file_string()) + "\"";
1277        expanded.push_back(token_type(T_STRINGLIT, file.c_str(), 
1278            curr_token.get_position()));
1279        return true;
1280    }
1281    else if (value == "__INCLUDE_LEVEL__") {
1282    // expand the __INCLUDE_LEVEL__ macro
1283    char buffer[22];    // 21 bytes holds all NUL-terminated unsigned 64-bit numbers
1284
1285        using namespace std;    // for some systems sprintf is in namespace std
1286        sprintf(buffer, "%d", (int)ctx.get_iteration_depth());
1287        expanded.push_back(token_type(T_INTLIT, buffer, curr_token.get_position()));
1288        return true;
1289    }
1290    return false;   // no predefined token
1291}
1292
1293///////////////////////////////////////////////////////////////////////////////
1294//
1295//  resolve_defined(): resolve the operator defined() and replace it with the
1296//                     correct T_INTLIT token
1297//
1298///////////////////////////////////////////////////////////////////////////////
1299template <typename ContextT>
1300template <typename IteratorT, typename ContainerT>
1301inline typename ContextT::token_type const &
1302macromap<ContextT>::resolve_defined(IteratorT &first, 
1303    IteratorT const &last, ContainerT &pending) 
1304{
1305    using namespace boost::wave;
1306    using namespace boost::wave::grammars;
1307
1308ContainerT result;
1309IteratorT start = first;
1310boost::spirit::parse_info<IteratorT> hit = 
1311    defined_grammar_gen<typename ContextT::lexer_type>::
1312        parse_operator_defined(start, last, result);
1313   
1314    if (!hit.hit) {
1315        string_type msg ("defined(): ");
1316        msg = msg + util::impl::as_string<string_type>(first, last);
1317        BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression, 
1318            msg.c_str(), main_pos);
1319    }
1320    impl::assign_iterator<IteratorT>::do_(first, hit.stop);
1321
1322// insert a token, which reflects the outcome
1323    pending.push_back(token_type(T_INTLIT, 
1324        is_defined(result.begin(), result.end()) ? "1" : "0", 
1325        main_pos));
1326
1327on_exit::pop_front<definition_container_type> pop_front_token(pending);
1328
1329    return act_token = pending.front();
1330}
1331
1332///////////////////////////////////////////////////////////////////////////////
1333//
1334//  resolve_operator_pragma(): resolve the operator _Pragma() and dispatch to
1335//                             the associated action
1336//
1337//      This function returns true, if the pragma was correctly interpreted.
1338//      The iterator 'first' is positioned behind the closing ')'.
1339//      This function returns false, if the _Pragma was not known, the
1340//      preprocessed token sequence is pushed back to the 'pending' sequence.
1341//
1342///////////////////////////////////////////////////////////////////////////////
1343template <typename ContextT>
1344template <typename IteratorT, typename ContainerT>
1345inline bool
1346macromap<ContextT>::resolve_operator_pragma(IteratorT &first, 
1347    IteratorT const &last, ContainerT &pending) 
1348{
1349// isolate the parameter of the operator _Pragma
1350    token_type pragma_token = *first;
1351   
1352    if (!impl::skip_to_token(first, last, T_LEFTPAREN)) {
1353    // misformed operator _Pragma
1354        BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression, 
1355            "operator _Pragma()", pragma_token.get_position());
1356    }
1357   
1358    std::vector<ContainerT> arguments;
1359    typename std::vector<ContainerT>::size_type count_args = 
1360        collect_arguments (pragma_token, arguments, first, last, 1);
1361
1362// verify the parameter count
1363    if (pragma_token.get_position().get_file().empty())
1364        pragma_token.set_position(act_token.get_position());
1365       
1366    if (1 > count_args || 1 > arguments.size()) {
1367    // too few macro arguments
1368        BOOST_WAVE_THROW(preprocess_exception, too_few_macroarguments, 
1369            pragma_token.get_value().c_str(), pragma_token.get_position());
1370    }
1371    if (1 < count_args || 1 < arguments.size()) {
1372    // too many macro arguments
1373        BOOST_WAVE_THROW(preprocess_exception, too_many_macroarguments, 
1374            pragma_token.get_value().c_str(), pragma_token.get_position());
1375    }
1376
1377// preprocess the pragma token body
1378    typedef typename std::vector<ContainerT>::value_type::iterator
1379        argument_iterator_type;
1380       
1381    ContainerT expanded;
1382    argument_iterator_type begin_it = arguments[0].begin();
1383    argument_iterator_type end_it = arguments[0].end();
1384    expand_whole_tokensequence(expanded, begin_it, end_it, false);
1385
1386// un-escape the parameter of the operator _Pragma
1387    typedef typename token_type::string_type string_type;
1388   
1389    string_type pragma_cmd;
1390    typename ContainerT::const_iterator end_exp = expanded.end();
1391    for (typename ContainerT::const_iterator it_exp = expanded.begin();
1392         it_exp != end_exp; ++it_exp)
1393    {
1394        if (T_EOF == token_id(*it_exp))
1395            break;
1396        if (IS_CATEGORY(*it_exp, WhiteSpaceTokenType))
1397            continue;
1398           
1399        if (T_STRINGLIT != token_id(*it_exp)) {
1400        // ill formed operator _Pragma
1401            BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option, 
1402                "_Pragma", pragma_token.get_position());
1403        }
1404
1405        if (pragma_cmd.size() > 0) {
1406        // there should be exactly one string literal (string literals are to
1407        // be concatenated at translation phase 6, but _Pragma operators are
1408        // to be executed at translation phase 4)
1409            BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option, 
1410                "_Pragma", pragma_token.get_position());
1411        }
1412       
1413    // remove the '\"' and concat all given string literal-values
1414        string_type token_str = (*it_exp).get_value();
1415        pragma_cmd += token_str.substr(1, token_str.size() - 2);
1416    }
1417    string_type pragma_cmd_unesc = impl::unescape_lit(pragma_cmd);
1418
1419// tokenize the pragma body
1420    typedef typename ContextT::lexer_type lexer_type;
1421   
1422    ContainerT pragma;
1423    std::string pragma_cmd_str(pragma_cmd_unesc.c_str());
1424    lexer_type it = lexer_type(pragma_cmd_str.begin(), pragma_cmd_str.end(), 
1425        pragma_token.get_position(), ctx.get_language());
1426    lexer_type end = lexer_type();
1427    for (/**/; it != end; ++it) 
1428        pragma.push_back(*it);
1429
1430// analyze the preprocessed token sequence and eventually dispatch to the
1431// associated action
1432    if (interpret_pragma(ctx, pragma_token, pragma.begin(), pragma.end(), 
1433        pending))
1434    {
1435        return true;    // successfully recognized a wave specific pragma
1436    }
1437   
1438// unknown pragma token sequence, push it back and return to the caller
1439    pending.push_front(token_type(T_SPACE, " ", pragma_token.get_position()));
1440    pending.push_front(token_type(T_RIGHTPAREN, ")", pragma_token.get_position()));
1441    pending.push_front(token_type(T_STRINGLIT, string_type("\"") + pragma_cmd + "\"",
1442        pragma_token.get_position()));
1443    pending.push_front(token_type(T_LEFTPAREN, "(", pragma_token.get_position()));
1444    pending.push_front(pragma_token);
1445    return false;
1446}
1447
1448///////////////////////////////////////////////////////////////////////////////
1449//
1450//  Test, whether the result of a concat operator is well formed or not.
1451//
1452//  This is done by re-scanning (re-tokenizing) the resulting token sequence,
1453//  which should give back exactly one token.
1454//
1455///////////////////////////////////////////////////////////////////////////////
1456template <typename ContextT>
1457template <typename ContainerT>
1458inline bool
1459macromap<ContextT>::is_valid_concat(string_type new_value, 
1460    position_type const &pos, ContainerT &rescanned)
1461{
1462// re-tokenize the newly generated string
1463    typedef typename ContextT::lexer_type lexer_type;
1464   
1465    std::string value_to_test(new_value.c_str());
1466
1467    boost::wave::language_support lang = 
1468        boost::wave::enable_prefer_pp_numbers(ctx.get_language());
1469    lang = boost::wave::enable_single_line(lang);
1470   
1471    lexer_type it = lexer_type(value_to_test.begin(), value_to_test.end(), pos, 
1472        lang);
1473    lexer_type end = lexer_type();
1474    for (/**/; it != end && T_EOF != token_id(*it); ++it) 
1475        rescanned.push_back(*it);
1476
1477#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1478    if (boost::wave::need_variadics(ctx.get_language()))
1479        return true;       // in variadics mode token pasting is well defined
1480#endif
1481       
1482// test if the newly generated token sequence contains more than 1 token
1483// the second one is the T_EOF token
1484//    BOOST_ASSERT(T_EOF == token_id(rescanned.back()));
1485    return 1 == rescanned.size();
1486}
1487
1488///////////////////////////////////////////////////////////////////////////////
1489//
1490//  Handle all occurrences of the concatenation operator '##' inside the given
1491//  token sequence.
1492//
1493///////////////////////////////////////////////////////////////////////////////
1494template <typename ContextT>
1495template <typename ContainerT>
1496inline void 
1497macromap<ContextT>::concat_tokensequence(ContainerT &expanded)
1498{
1499    using namespace boost::wave;
1500    typedef typename ContainerT::iterator iterator_type;
1501   
1502    iterator_type end = expanded.end();
1503    iterator_type prev = end;
1504    for (iterator_type it = expanded.begin(); it != end; /**/) 
1505    {
1506        if (T_POUND_POUND == BASE_TOKEN(token_id(*it))) {
1507        iterator_type next = it;
1508   
1509            ++next;
1510            if (prev == end || next == end) {
1511            // error, '##' should be in between two tokens
1512                BOOST_WAVE_THROW(preprocess_exception, ill_formed_operator,
1513                    "concat ('##')", main_pos);
1514            }
1515
1516        // replace prev##next with the concatenated value, skip whitespace
1517        // before and after the '##' operator
1518            while (IS_CATEGORY(*next, WhiteSpaceTokenType)) {
1519                ++next;
1520                if (next == end) {
1521                // error, '##' should be in between two tokens
1522                    BOOST_WAVE_THROW(preprocess_exception, ill_formed_operator,
1523                        "concat ('##')", main_pos);
1524                }
1525            }
1526           
1527#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1528            if (boost::wave::need_variadics(ctx.get_language())) {
1529                if (T_PLACEMARKER == token_id(*next)) {
1530                // remove the '##' and the next tokens from the sequence
1531                iterator_type first_to_delete = prev;
1532
1533                    expanded.erase(++first_to_delete, ++next);
1534                    it = next;
1535                    continue;
1536                }
1537                else if (T_PLACEMARKER == token_id(*prev)) {
1538                // remove the '##' and the next tokens from the sequence
1539                iterator_type first_to_delete = prev;
1540
1541                    *prev = *next;
1542                    expanded.erase(++first_to_delete, ++next); 
1543                    it = next;
1544                    continue;
1545                }
1546            }
1547#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1548
1549        // test if the concat operator has to concatenate two unrelated
1550        // tokens i.e. the result yields more then one token
1551        string_type concat_result;
1552        ContainerT rescanned;
1553
1554            concat_result = ((*prev).get_value() + (*next).get_value());
1555
1556        // analyze the validity of the concatenation result
1557            if (!is_valid_concat(concat_result, (*prev).get_position(), 
1558                    rescanned) &&
1559                !IS_CATEGORY(*prev, WhiteSpaceTokenType) && 
1560                !IS_CATEGORY(*next, WhiteSpaceTokenType)) 
1561            {
1562            string_type error_string("\"");
1563           
1564                error_string += (*prev).get_value();
1565                error_string += "\" and \"";
1566                error_string += (*next).get_value();
1567                error_string += "\"";
1568                BOOST_WAVE_THROW(preprocess_exception, invalid_concat,
1569                    error_string.c_str(), main_pos);
1570            }
1571
1572#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1573            if (boost::wave::need_variadics(ctx.get_language())) {
1574            // remove the prev, '##' and the next tokens from the sequence
1575                expanded.erase(prev, ++next);       // remove not needed tokens   
1576               
1577            // some stl implementations clear() the container if we erased all
1578            // the elements, which orphans all iterators. we re-initialize these
1579            // here
1580                if (expanded.empty()) 
1581                    end = next = expanded.end();
1582                   
1583            // replace the old token (pointed to by *prev) with the re-tokenized
1584            // sequence
1585                expanded.splice(next, rescanned);
1586
1587            // the last token of the inserted sequence is the new previous
1588                prev = next;
1589                if (next != expanded.end())
1590                    --prev;
1591            }
1592            else
1593#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1594            {
1595            // we leave the token_id unchanged, but unmark the token as
1596            // disabled, if appropriate
1597                (*prev).set_value(concat_result);
1598                if (T_NONREPLACABLE_IDENTIFIER == token_id(*prev))
1599                    (*prev).set_token_id(T_IDENTIFIER);
1600               
1601            // remove the '##' and the next tokens from the sequence
1602            iterator_type first_to_delete = prev;
1603
1604                expanded.erase(++first_to_delete, ++next); 
1605            }
1606            it = next;
1607            continue;
1608        }
1609
1610    // save last non-whitespace token position
1611        if (!IS_CATEGORY(*it, WhiteSpaceTokenType))       
1612            prev = it;
1613
1614        ++it;           // next token, please
1615    }
1616}
1617
1618///////////////////////////////////////////////////////////////////////////////
1619//
1620//  predefined_macro(): predefine a single macro
1621//
1622///////////////////////////////////////////////////////////////////////////////
1623template <typename ContextT>
1624inline void
1625macromap<ContextT>::predefine_macro(defined_macros_type *scope, 
1626    string_type const &name, token_type const &t)
1627{
1628definition_container_type macrodefinition;
1629std::vector<token_type> param;
1630
1631    macrodefinition.push_back(t);
1632    add_macro(token_type(T_IDENTIFIER, name, t.get_position()), 
1633        false, param, macrodefinition, true, scope);
1634}
1635
1636///////////////////////////////////////////////////////////////////////////////
1637//
1638//  init_predefined_macros(): init the predefined macros
1639//
1640///////////////////////////////////////////////////////////////////////////////
1641template <typename ContextT>
1642inline void 
1643macromap<ContextT>::init_predefined_macros(char const *fname, 
1644    defined_macros_type *scope, bool at_global_scope)
1645{
1646    using namespace predefined_macros;
1647
1648// if no scope is given, use the current one
1649defined_macros_type *current_scope = scope ? scope : current_macros;
1650
1651// first, add the static macros
1652position_type pos("<built-in>");
1653
1654#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1655    if (boost::wave::need_c99(ctx.get_language())) {
1656    // define C99 specifics
1657        for (int i = 0; 0 != static_data_c99(i).name; ++i) {
1658            predefine_macro(current_scope, static_data_c99(i).name,
1659                token_type(static_data_c99(i).token_id, 
1660                    static_data_c99(i).value, pos));
1661        }
1662    }
1663    else 
1664#endif
1665    {
1666    // define C++ specifics
1667        for (int i = 0; 0 != static_data_cpp(i).name; ++i) {
1668            predefine_macro(current_scope, static_data_cpp(i).name, 
1669                token_type(static_data_cpp(i).token_id, 
1670                    static_data_cpp(i).value, pos));
1671        }
1672       
1673#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1674    // define __WAVE_HAS_VARIADICS__, if appropriate
1675        if (boost::wave::need_variadics(ctx.get_language())) {
1676            predefine_macro(current_scope, "__WAVE_HAS_VARIADICS__",
1677                token_type(T_INTLIT, "1", pos));
1678        }
1679#endif
1680    }
1681
1682// predefine the __BASE_FILE__ macro which contains the main file name
1683    namespace fs = boost::filesystem; 
1684    if (string_type(fname) != "<Unknown>") {
1685    fs::path filename(fname, fs::native);
1686   
1687        using boost::wave::util::impl::escape_lit;
1688        predefine_macro(current_scope, "__BASE_FILE__",
1689            token_type(T_STRINGLIT, string_type("\"") + 
1690                escape_lit(filename.native_file_string()).c_str() + "\"", pos));
1691        base_name = fname;
1692    }
1693    else if (!base_name.empty()) {
1694    fs::path filename(base_name.c_str(), fs::native);
1695   
1696        using boost::wave::util::impl::escape_lit;
1697        predefine_macro(current_scope, "__BASE_FILE__",
1698            token_type(T_STRINGLIT, string_type("\"") + 
1699                escape_lit(filename.native_file_string()).c_str() + "\"", pos));
1700    }
1701   
1702// now add the dynamic macros
1703    for (int j = 0; 0 != dynamic_data(j).name; ++j) {
1704        predefine_macro(current_scope, dynamic_data(j).name,
1705            token_type(dynamic_data(j).token_id, 
1706                dynamic_data(j).generator(false), pos));
1707    }
1708}
1709
1710///////////////////////////////////////////////////////////////////////////////
1711//
1712//  reset_macromap(): initialize the internal macro symbol namespace
1713//
1714///////////////////////////////////////////////////////////////////////////////
1715template <typename ContextT>
1716inline void 
1717macromap<ContextT>::reset_macromap()
1718{
1719    current_macros->clear();
1720    predefined_macros::get_time(true);
1721    predefined_macros::get_date(true);
1722    act_token = token_type();
1723}
1724
1725///////////////////////////////////////////////////////////////////////////////
1726}}}   // namespace boost::wave::util
1727
1728#if BOOST_WAVE_SERIALIZATION != 0
1729namespace boost { namespace serialization {
1730
1731template<typename ContextT>
1732struct version<boost::wave::util::macromap<ContextT> >
1733{
1734    typedef boost::wave::util::macromap<ContextT> target_type;
1735    typedef mpl::int_<target_type::version> type;
1736    typedef mpl::integral_c_tag tag;
1737    BOOST_STATIC_CONSTANT(unsigned int, value = version::type::value);
1738};
1739
1740}}    // namespace boost::serialization
1741#endif
1742
1743// the suffix header occurs after all of the code
1744#ifdef BOOST_HAS_ABI_HEADERS
1745#include BOOST_ABI_SUFFIX
1746#endif
1747
1748#endif // !defined(CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED)
Note: See TracBrowser for help on using the repository browser.