source: NonGTP/Boost/boost/wave/util/cpp_macromap.hpp @ 857

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