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