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