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