]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Boost.Wave: A Standard compliant C++ preprocessor library | |
3 | ||
4 | Macro expansion engine | |
5 | ||
6 | http://www.boost.org/ | |
7 | ||
8 | Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost | |
9 | Software License, Version 1.0. (See accompanying file | |
10 | LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
11 | =============================================================================*/ | |
12 | ||
13 | #if !defined(CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED) | |
14 | #define CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED | |
15 | ||
16 | #include <cstdlib> | |
17 | #include <cstdio> | |
18 | #include <ctime> | |
19 | ||
20 | #include <list> | |
21 | #include <map> | |
22 | #include <set> | |
23 | #include <vector> | |
24 | #include <iterator> | |
25 | #include <algorithm> | |
26 | ||
27 | #include <boost/assert.hpp> | |
28 | #include <boost/wave/wave_config.hpp> | |
29 | #if BOOST_WAVE_SERIALIZATION != 0 | |
30 | #include <boost/serialization/serialization.hpp> | |
31 | #include <boost/serialization/shared_ptr.hpp> | |
32 | #endif | |
33 | ||
34 | #include <boost/filesystem/path.hpp> | |
35 | ||
36 | #include <boost/wave/util/time_conversion_helper.hpp> | |
37 | #include <boost/wave/util/unput_queue_iterator.hpp> | |
38 | #include <boost/wave/util/macro_helpers.hpp> | |
39 | #include <boost/wave/util/macro_definition.hpp> | |
40 | #include <boost/wave/util/symbol_table.hpp> | |
41 | #include <boost/wave/util/cpp_macromap_utils.hpp> | |
42 | #include <boost/wave/util/cpp_macromap_predef.hpp> | |
43 | #include <boost/wave/util/filesystem_compatibility.hpp> | |
44 | #include <boost/wave/grammars/cpp_defined_grammar_gen.hpp> | |
45 | ||
46 | #include <boost/wave/wave_version.hpp> | |
47 | #include <boost/wave/cpp_exceptions.hpp> | |
48 | #include <boost/wave/language_support.hpp> | |
49 | ||
50 | // this must occur after all of the includes and before any code appears | |
51 | #ifdef BOOST_HAS_ABI_HEADERS | |
52 | #include BOOST_ABI_PREFIX | |
53 | #endif | |
54 | ||
55 | /////////////////////////////////////////////////////////////////////////////// | |
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) |