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 ¶meters,
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 ¶meters,
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 ¶meter_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 ¶meter_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 ¯odef, 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 ¶meters, 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 ¶meters,
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 ¯o_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 ¶meter_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 ¶meter_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 ¯o_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 ¯o_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