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