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