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