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