Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/wave/util/cpp_macromap.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
15:663ca0da4350 | 16:2665513ce2d3 |
---|---|
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 /////////////////////////////////////////////////////////////////////////////// | |
56 namespace 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 /////////////////////////////////////////////////////////////////////////////// | |
66 template <typename ContextT> | |
67 class 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 | |
84 public: | |
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 ¶meters, | |
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 ¶meters, | |
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 | |
158 protected: | |
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 ¶meter_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 ¶meter_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 ¯odefinition, | |
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 ¯odef, 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 | |
234 public: | |
235 BOOST_STATIC_CONSTANT(unsigned int, version = 0x10); | |
236 BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f); | |
237 | |
238 private: | |
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 | |
260 private: | |
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 /////////////////////////////////////////////////////////////////////////////// | |
278 template <typename ContextT> | |
279 inline bool | |
280 macromap<ContextT>::add_macro(token_type const &name, bool has_parameters, | |
281 parameter_container_type ¶meters, 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 | |
309 defined_macros_type *current_scope = scope ? scope : current_macros; | |
310 typename 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 /////////////////////////////////////////////////////////////////////////////// | |
391 template <typename ContextT> | |
392 inline bool | |
393 macromap<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 | |
410 template <typename ContextT> | |
411 template <typename IteratorT> | |
412 inline bool | |
413 macromap<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 | |
418 token_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 | |
431 IteratorT it = begin; | |
432 string_type name ((*it).get_value()); | |
433 typename 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 | |
447 template <typename ContextT> | |
448 inline bool | |
449 macromap<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 /////////////////////////////////////////////////////////////////////////////// | |
460 template <typename ContextT> | |
461 inline bool | |
462 macromap<ContextT>::get_macro(string_type const &name, bool &has_parameters, | |
463 bool &is_predefined, position_type &pos, | |
464 parameter_container_type ¶meters, | |
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 | |
472 macro_definition_type ¯o_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 /////////////////////////////////////////////////////////////////////////////// | |
487 template <typename ContextT> | |
488 inline bool | |
489 macromap<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 /////////////////////////////////////////////////////////////////////////////// | |
533 template <typename ContextT> | |
534 template <typename IteratorT, typename ContainerT> | |
535 inline typename ContextT::token_type const & | |
536 macromap<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 | |
547 on_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 /////////////////////////////////////////////////////////////////////////////// | |
565 template <typename ContextT> | |
566 template <typename IteratorT, typename ContainerT> | |
567 inline typename ContextT::token_type const & | |
568 macromap<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 | |
705 template <typename ContextT> | |
706 template <typename IteratorT, typename ContainerT, typename SizeT> | |
707 inline typename std::vector<ContainerT>::size_type | |
708 macromap<ContextT>::collect_arguments (token_type const curr_token, | |
709 std::vector<ContainerT> &arguments, IteratorT &next, | |
710 IteratorT const &end, SizeT const ¶meter_count, bool& seen_newline) | |
711 #else | |
712 template <typename ContextT> | |
713 template <typename IteratorT, typename ContainerT, typename SizeT> | |
714 inline typename std::vector<ContainerT>::size_type | |
715 macromap<ContextT>::collect_arguments (token_type const curr_token, | |
716 std::vector<ContainerT> &arguments, IteratorT &next, IteratorT &endparen, | |
717 IteratorT const &end, SizeT const ¶meter_count, bool& seen_newline) | |
718 #endif | |
719 { | |
720 using namespace boost::wave; | |
721 | |
722 arguments.push_back(ContainerT()); | |
723 | |
724 // collect the actual arguments | |
725 typename std::vector<ContainerT>::size_type count_arguments = 0; | |
726 int nested_parenthesis_level = 1; | |
727 ContainerT *argument = &arguments[0]; | |
728 bool was_whitespace = false; | |
729 token_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 /////////////////////////////////////////////////////////////////////////////// | |
857 template <typename ContextT> | |
858 template <typename IteratorT, typename ContainerT> | |
859 inline void | |
860 macromap<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 /////////////////////////////////////////////////////////////////////////////// | |
894 template <typename ContextT> | |
895 template <typename ContainerT> | |
896 inline void | |
897 macromap<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 /////////////////////////////////////////////////////////////////////////////// | |
926 template <typename ContextT> | |
927 template <typename ContainerT> | |
928 inline void | |
929 macromap<ContextT>::expand_replacement_list( | |
930 macro_definition_type const ¯odef, | |
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 | |
938 std::vector<ContainerT> expanded_args(arguments.size()); | |
939 std::vector<bool> has_expanded_args(arguments.size()); | |
940 bool seen_concat = false; | |
941 bool adjacent_concat = false; | |
942 bool 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 /////////////////////////////////////////////////////////////////////////////// | |
1093 template <typename ContextT> | |
1094 template <typename IteratorT, typename ContainerT> | |
1095 inline void | |
1096 macromap<ContextT>::rescan_replacement_list(token_type const &curr_token, | |
1097 macro_definition_type ¯o_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 /////////////////////////////////////////////////////////////////////////////// | |
1152 template <typename ContextT> | |
1153 template <typename IteratorT, typename ContainerT> | |
1154 inline bool | |
1155 macromap<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 | |
1188 macro_definition_type ¯o_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 | |
1210 ContainerT 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 | |
1372 ContainerT 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 /////////////////////////////////////////////////////////////////////////////// | |
1399 template <typename ContextT> | |
1400 template <typename ContainerT> | |
1401 inline bool | |
1402 macromap<ContextT>::expand_predefined_macro(token_type const &curr_token, | |
1403 ContainerT &expanded) | |
1404 { | |
1405 using namespace boost::wave; | |
1406 | |
1407 string_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 /////////////////////////////////////////////////////////////////////////////// | |
1452 template <typename ContextT> | |
1453 template <typename IteratorT, typename ContainerT> | |
1454 inline typename ContextT::token_type const & | |
1455 macromap<ContextT>::resolve_defined(IteratorT &first, | |
1456 IteratorT const &last, ContainerT &pending) | |
1457 { | |
1458 using namespace boost::wave; | |
1459 using namespace boost::wave::grammars; | |
1460 | |
1461 ContainerT result; | |
1462 IteratorT start = first; | |
1463 boost::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 | |
1485 on_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 /////////////////////////////////////////////////////////////////////////////// | |
1501 template <typename ContextT> | |
1502 template <typename IteratorT, typename ContainerT> | |
1503 inline bool | |
1504 macromap<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 /////////////////////////////////////////////////////////////////////////////// | |
1627 template <typename ContextT> | |
1628 template <typename ContainerT> | |
1629 inline bool | |
1630 macromap<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 /////////////////////////////////////////////////////////////////////////////// | |
1669 template <typename Context> | |
1670 inline 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 { | |
1675 typename 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 | |
1685 template <typename ContextT> | |
1686 template <typename ContainerT> | |
1687 inline bool | |
1688 macromap<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 /////////////////////////////////////////////////////////////////////////////// | |
1811 template <typename ContextT> | |
1812 inline void | |
1813 macromap<ContextT>::predefine_macro(defined_macros_type *scope, | |
1814 string_type const &name, token_type const &t) | |
1815 { | |
1816 definition_container_type macrodefinition; | |
1817 std::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 /////////////////////////////////////////////////////////////////////////////// | |
1829 template <typename ContextT> | |
1830 inline void | |
1831 macromap<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 | |
1835 defined_macros_type *current_scope = scope ? scope : current_macros; | |
1836 | |
1837 // first, add the static macros | |
1838 position_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 /////////////////////////////////////////////////////////////////////////////// | |
1914 template <typename ContextT> | |
1915 inline void | |
1916 macromap<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 | |
1927 namespace boost { namespace serialization { | |
1928 | |
1929 template<typename ContextT> | |
1930 struct 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) |