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