1 | /*============================================================================= |
---|
2 | Boost.Wave: A Standard compliant C++ preprocessor library |
---|
3 | http://www.boost.org/ |
---|
4 | |
---|
5 | Copyright (c) 2001-2007 Hartmut Kaiser. Distributed under the Boost |
---|
6 | Software License, Version 1.0. (See accompanying file |
---|
7 | LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
---|
8 | =============================================================================*/ |
---|
9 | |
---|
10 | #if !defined(TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED) |
---|
11 | #define TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED |
---|
12 | |
---|
13 | #include <cstdio> |
---|
14 | #include <cstdlib> |
---|
15 | #include <ctime> |
---|
16 | |
---|
17 | #include <ostream> |
---|
18 | #include <string> |
---|
19 | |
---|
20 | #include <boost/assert.hpp> |
---|
21 | #include <boost/config.hpp> |
---|
22 | #include <boost/filesystem/path.hpp> |
---|
23 | #include <boost/filesystem/operations.hpp> |
---|
24 | #include <boost/filesystem/convenience.hpp> |
---|
25 | |
---|
26 | #include <boost/wave/token_ids.hpp> |
---|
27 | #include <boost/wave/util/macro_helpers.hpp> |
---|
28 | #include <boost/wave/preprocessing_hooks.hpp> |
---|
29 | #include <boost/wave/whitespace_handling.hpp> |
---|
30 | #include <boost/wave/language_support.hpp> |
---|
31 | |
---|
32 | #include "stop_watch.hpp" |
---|
33 | |
---|
34 | #ifdef BOOST_NO_STRINGSTREAM |
---|
35 | #include <strstream> |
---|
36 | #define BOOST_WAVE_OSSTREAM std::ostrstream |
---|
37 | std::string BOOST_WAVE_GETSTRING(std::ostrstream& ss) |
---|
38 | { |
---|
39 | ss << std::ends; |
---|
40 | std::string rval = ss.str(); |
---|
41 | ss.freeze(false); |
---|
42 | return rval; |
---|
43 | } |
---|
44 | #else |
---|
45 | #include <sstream> |
---|
46 | #define BOOST_WAVE_GETSTRING(ss) ss.str() |
---|
47 | #define BOOST_WAVE_OSSTREAM std::ostringstream |
---|
48 | #endif |
---|
49 | |
---|
50 | // trace_flags: enable single tracing functionality |
---|
51 | enum trace_flags { |
---|
52 | trace_nothing = 0, // disable tracing |
---|
53 | trace_macros = 1, // enable macro tracing |
---|
54 | trace_includes = 2 // enable include file tracing |
---|
55 | }; |
---|
56 | |
---|
57 | /////////////////////////////////////////////////////////////////////////////// |
---|
58 | // |
---|
59 | // Special error thrown whenever the #pragma wave system() directive is |
---|
60 | // disabled |
---|
61 | // |
---|
62 | /////////////////////////////////////////////////////////////////////////////// |
---|
63 | class no_pragma_system_exception : |
---|
64 | public boost::wave::preprocess_exception |
---|
65 | { |
---|
66 | public: |
---|
67 | enum error_code { |
---|
68 | pragma_system_not_enabled = boost::wave::preprocess_exception::last_error_number + 1 |
---|
69 | }; |
---|
70 | |
---|
71 | no_pragma_system_exception(char const *what_, error_code code, int line_, |
---|
72 | int column_, char const *filename_) throw() |
---|
73 | : boost::wave::preprocess_exception(what_, |
---|
74 | (boost::wave::preprocess_exception::error_code)code, line_, |
---|
75 | column_, filename_) |
---|
76 | { |
---|
77 | } |
---|
78 | ~no_pragma_system_exception() throw() {} |
---|
79 | |
---|
80 | |
---|
81 | virtual char const *what() const throw() |
---|
82 | { |
---|
83 | return "boost::wave::no_pragma_system_exception"; |
---|
84 | } |
---|
85 | virtual bool is_recoverable() const throw() |
---|
86 | { |
---|
87 | return true; |
---|
88 | } |
---|
89 | virtual int get_severity() const throw() |
---|
90 | { |
---|
91 | return boost::wave::util::severity_remark; |
---|
92 | } |
---|
93 | |
---|
94 | static char const *error_text(int code) |
---|
95 | { |
---|
96 | return "the directive '#pragma wave system()' was not enabled, use the " |
---|
97 | "-x command line argument to enable the execution of"; |
---|
98 | } |
---|
99 | static boost::wave::util::severity severity_level(int code) |
---|
100 | { |
---|
101 | return boost::wave::util::severity_remark; |
---|
102 | } |
---|
103 | static char const *severity_text(int code) |
---|
104 | { |
---|
105 | return boost::wave::util::get_severity(boost::wave::util::severity_remark); |
---|
106 | } |
---|
107 | }; |
---|
108 | |
---|
109 | /////////////////////////////////////////////////////////////////////////////// |
---|
110 | // |
---|
111 | // The trace_macro_expansion policy is used to trace the macro expansion of |
---|
112 | // macros whenever it is requested from inside the input stream to preprocess |
---|
113 | // through the '#pragma wave_option(trace: enable)' directive. The macro |
---|
114 | // tracing is disabled with the help of a '#pragma wave_option(trace: disable)' |
---|
115 | // directive. |
---|
116 | // |
---|
117 | // This policy type is used as a template parameter to the boost::wave::context<> |
---|
118 | // object. |
---|
119 | // |
---|
120 | /////////////////////////////////////////////////////////////////////////////// |
---|
121 | template <typename TokenT> |
---|
122 | class trace_macro_expansion |
---|
123 | : public boost::wave::context_policies::eat_whitespace<TokenT> |
---|
124 | { |
---|
125 | typedef boost::wave::context_policies::eat_whitespace<TokenT> base_type; |
---|
126 | |
---|
127 | public: |
---|
128 | trace_macro_expansion(bool preserve_whitespace_, |
---|
129 | std::ofstream &output_, std::ostream &tracestrm_, |
---|
130 | std::ostream &includestrm_, trace_flags flags_, |
---|
131 | bool enable_system_command_, bool& generate_output_, |
---|
132 | std::string const& default_outfile_) |
---|
133 | : outputstrm(output_), tracestrm(tracestrm_), includestrm(includestrm_), |
---|
134 | level(0), flags(flags_), logging_flags(trace_nothing), |
---|
135 | enable_system_command(enable_system_command_), |
---|
136 | preserve_whitespace(preserve_whitespace_), |
---|
137 | generate_output(generate_output_), |
---|
138 | default_outfile(default_outfile_) |
---|
139 | { |
---|
140 | using namespace std; // some systems have time in namespace std |
---|
141 | time(&started_at); |
---|
142 | } |
---|
143 | ~trace_macro_expansion() |
---|
144 | { |
---|
145 | } |
---|
146 | |
---|
147 | /////////////////////////////////////////////////////////////////////////// |
---|
148 | // |
---|
149 | // The function 'expanding_function_like_macro' is called, whenever a |
---|
150 | // function-like macro is to be expanded. |
---|
151 | // |
---|
152 | // The 'macrodef' parameter marks the position, where the macro to expand |
---|
153 | // is defined. |
---|
154 | // The 'formal_args' parameter holds the formal arguments used during the |
---|
155 | // definition of the macro. |
---|
156 | // The 'definition' parameter holds the macro definition for the macro to |
---|
157 | // trace. |
---|
158 | // |
---|
159 | // The 'macrocall' parameter marks the position, where this macro invoked. |
---|
160 | // The 'arguments' parameter holds the macro arguments used during the |
---|
161 | // invocation of the macro |
---|
162 | // |
---|
163 | /////////////////////////////////////////////////////////////////////////// |
---|
164 | template <typename ContainerT> |
---|
165 | void expanding_function_like_macro( |
---|
166 | TokenT const ¯odef, std::vector<TokenT> const &formal_args, |
---|
167 | ContainerT const &definition, |
---|
168 | TokenT const ¯ocall, std::vector<ContainerT> const &arguments) |
---|
169 | { |
---|
170 | if (!enabled_macro_tracing()) return; |
---|
171 | |
---|
172 | if (0 == get_level()) { |
---|
173 | // output header line |
---|
174 | BOOST_WAVE_OSSTREAM stream; |
---|
175 | |
---|
176 | stream |
---|
177 | << macrocall.get_position() << ": " |
---|
178 | << macrocall.get_value() << "("; |
---|
179 | |
---|
180 | // argument list |
---|
181 | for (typename ContainerT::size_type i = 0; i < arguments.size(); ++i) { |
---|
182 | stream << boost::wave::util::impl::as_string(arguments[i]); |
---|
183 | if (i < arguments.size()-1) |
---|
184 | stream << ", "; |
---|
185 | } |
---|
186 | stream << ")" << std::endl; |
---|
187 | output(BOOST_WAVE_GETSTRING(stream)); |
---|
188 | increment_level(); |
---|
189 | } |
---|
190 | |
---|
191 | // output definition reference |
---|
192 | { |
---|
193 | BOOST_WAVE_OSSTREAM stream; |
---|
194 | |
---|
195 | stream |
---|
196 | << macrodef.get_position() << ": see macro definition: " |
---|
197 | << macrodef.get_value() << "("; |
---|
198 | |
---|
199 | // formal argument list |
---|
200 | for (typename std::vector<TokenT>::size_type i = 0; |
---|
201 | i < formal_args.size(); ++i) |
---|
202 | { |
---|
203 | stream << formal_args[i].get_value(); |
---|
204 | if (i < formal_args.size()-1) |
---|
205 | stream << ", "; |
---|
206 | } |
---|
207 | stream << ")" << std::endl; |
---|
208 | output(BOOST_WAVE_GETSTRING(stream)); |
---|
209 | } |
---|
210 | |
---|
211 | if (formal_args.size() > 0) { |
---|
212 | // map formal and real arguments |
---|
213 | open_trace_body("invoked with\n"); |
---|
214 | for (typename std::vector<TokenT>::size_type j = 0; |
---|
215 | j < formal_args.size(); ++j) |
---|
216 | { |
---|
217 | using namespace boost::wave; |
---|
218 | |
---|
219 | BOOST_WAVE_OSSTREAM stream; |
---|
220 | stream << formal_args[j].get_value() << " = "; |
---|
221 | #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 |
---|
222 | if (T_ELLIPSIS == token_id(formal_args[j])) { |
---|
223 | // ellipsis |
---|
224 | for (typename ContainerT::size_type k = j; |
---|
225 | k < arguments.size(); ++k) |
---|
226 | { |
---|
227 | stream << boost::wave::util::impl::as_string(arguments[k]); |
---|
228 | if (k < arguments.size()-1) |
---|
229 | stream << ", "; |
---|
230 | } |
---|
231 | } |
---|
232 | else |
---|
233 | #endif |
---|
234 | { |
---|
235 | stream << boost::wave::util::impl::as_string(arguments[j]); |
---|
236 | } |
---|
237 | stream << std::endl; |
---|
238 | output(BOOST_WAVE_GETSTRING(stream)); |
---|
239 | } |
---|
240 | close_trace_body(); |
---|
241 | } |
---|
242 | open_trace_body(); |
---|
243 | } |
---|
244 | |
---|
245 | /////////////////////////////////////////////////////////////////////////// |
---|
246 | // |
---|
247 | // The function 'expanding_object_like_macro' is called, whenever a |
---|
248 | // object-like macro is to be expanded . |
---|
249 | // |
---|
250 | // The 'macrodef' parameter marks the position, where the macro to expand |
---|
251 | // is defined. |
---|
252 | // The 'definition' parameter holds the macro definition for the macro to |
---|
253 | // trace. |
---|
254 | // |
---|
255 | // The 'macrocall' parameter marks the position, where this macro invoked. |
---|
256 | // |
---|
257 | /////////////////////////////////////////////////////////////////////////// |
---|
258 | template <typename ContainerT> |
---|
259 | void expanding_object_like_macro(TokenT const ¯odef, |
---|
260 | ContainerT const &definition, TokenT const ¯ocall) |
---|
261 | { |
---|
262 | if (!enabled_macro_tracing()) return; |
---|
263 | |
---|
264 | if (0 == get_level()) { |
---|
265 | // output header line |
---|
266 | BOOST_WAVE_OSSTREAM stream; |
---|
267 | |
---|
268 | stream |
---|
269 | << macrocall.get_position() << ": " |
---|
270 | << macrocall.get_value() << std::endl; |
---|
271 | output(BOOST_WAVE_GETSTRING(stream)); |
---|
272 | increment_level(); |
---|
273 | } |
---|
274 | |
---|
275 | // output definition reference |
---|
276 | { |
---|
277 | BOOST_WAVE_OSSTREAM stream; |
---|
278 | |
---|
279 | stream |
---|
280 | << macrodef.get_position() << ": see macro definition: " |
---|
281 | << macrodef.get_value() << std::endl; |
---|
282 | output(BOOST_WAVE_GETSTRING(stream)); |
---|
283 | } |
---|
284 | open_trace_body(); |
---|
285 | } |
---|
286 | |
---|
287 | /////////////////////////////////////////////////////////////////////////// |
---|
288 | // |
---|
289 | // The function 'expanded_macro' is called, whenever the expansion of a |
---|
290 | // macro is finished but before the rescanning process starts. |
---|
291 | // |
---|
292 | // The parameter 'result' contains the token sequence generated as the |
---|
293 | // result of the macro expansion. |
---|
294 | // |
---|
295 | /////////////////////////////////////////////////////////////////////////// |
---|
296 | template <typename ContainerT> |
---|
297 | void expanded_macro(ContainerT const &result) |
---|
298 | { |
---|
299 | if (!enabled_macro_tracing()) return; |
---|
300 | |
---|
301 | BOOST_WAVE_OSSTREAM stream; |
---|
302 | stream << boost::wave::util::impl::as_string(result) << std::endl; |
---|
303 | output(BOOST_WAVE_GETSTRING(stream)); |
---|
304 | |
---|
305 | open_trace_body("rescanning\n"); |
---|
306 | } |
---|
307 | |
---|
308 | /////////////////////////////////////////////////////////////////////////// |
---|
309 | // |
---|
310 | // The function 'rescanned_macro' is called, whenever the rescanning of a |
---|
311 | // macro is finished. |
---|
312 | // |
---|
313 | // The parameter 'result' contains the token sequence generated as the |
---|
314 | // result of the rescanning. |
---|
315 | // |
---|
316 | /////////////////////////////////////////////////////////////////////////// |
---|
317 | template <typename ContainerT> |
---|
318 | void rescanned_macro(ContainerT const &result) |
---|
319 | { |
---|
320 | if (!enabled_macro_tracing() || get_level() == 0) |
---|
321 | return; |
---|
322 | |
---|
323 | BOOST_WAVE_OSSTREAM stream; |
---|
324 | stream << boost::wave::util::impl::as_string(result) << std::endl; |
---|
325 | output(BOOST_WAVE_GETSTRING(stream)); |
---|
326 | close_trace_body(); |
---|
327 | close_trace_body(); |
---|
328 | |
---|
329 | if (1 == get_level()) |
---|
330 | decrement_level(); |
---|
331 | } |
---|
332 | |
---|
333 | /////////////////////////////////////////////////////////////////////////// |
---|
334 | // |
---|
335 | // The function 'interpret_pragma' is called, whenever a #pragma wave |
---|
336 | // directive is found, which isn't known to the core Wave library. |
---|
337 | // |
---|
338 | // The parameter 'ctx' is a reference to the context object used for |
---|
339 | // instantiating the preprocessing iterators by the user. |
---|
340 | // |
---|
341 | // The parameter 'pending' may be used to push tokens back into the input |
---|
342 | // stream, which are to be used as the replacement text for the whole |
---|
343 | // #pragma wave() directive. |
---|
344 | // |
---|
345 | // The parameter 'option' contains the name of the interpreted pragma. |
---|
346 | // |
---|
347 | // The parameter 'values' holds the values of the parameter provided to |
---|
348 | // the pragma operator. |
---|
349 | // |
---|
350 | // The parameter 'act_token' contains the actual #pragma token, which may |
---|
351 | // be used for error output. |
---|
352 | // |
---|
353 | // If the return value is 'false', the whole #pragma directive is |
---|
354 | // interpreted as unknown and a corresponding error message is issued. A |
---|
355 | // return value of 'true' signs a successful interpretation of the given |
---|
356 | // #pragma. |
---|
357 | // |
---|
358 | /////////////////////////////////////////////////////////////////////////// |
---|
359 | template <typename ContextT, typename ContainerT> |
---|
360 | bool |
---|
361 | interpret_pragma(ContextT &ctx, ContainerT &pending, |
---|
362 | typename ContextT::token_type const &option, ContainerT const &valuetokens, |
---|
363 | typename ContextT::token_type const &act_token) |
---|
364 | { |
---|
365 | typedef typename ContextT::token_type token_type; |
---|
366 | |
---|
367 | ContainerT values(valuetokens); |
---|
368 | boost::wave::util::impl::trim_sequence(values); // trim whitespace |
---|
369 | |
---|
370 | if (option.get_value() == "timer") { |
---|
371 | // #pragma wave timer(value) |
---|
372 | if (0 == values.size()) { |
---|
373 | // no value means '1' |
---|
374 | using namespace boost::wave; |
---|
375 | timer(token_type(T_INTLIT, "1", act_token.get_position())); |
---|
376 | } |
---|
377 | else { |
---|
378 | timer(values.front()); |
---|
379 | } |
---|
380 | return true; |
---|
381 | } |
---|
382 | if (option.get_value() == "trace") { |
---|
383 | // enable/disable tracing option |
---|
384 | return interpret_pragma_trace(ctx, values, act_token); |
---|
385 | } |
---|
386 | if (option.get_value() == "system") { |
---|
387 | if (!enable_system_command) { |
---|
388 | // if the #pragma wave system() directive is not enabled, throw |
---|
389 | // a corresponding error (actually its a remark), |
---|
390 | BOOST_WAVE_THROW(no_pragma_system_exception, |
---|
391 | pragma_system_not_enabled, |
---|
392 | boost::wave::util::impl::as_string(values).c_str(), |
---|
393 | act_token.get_position()); |
---|
394 | } |
---|
395 | |
---|
396 | // try to spawn the given argument as a system command and return the |
---|
397 | // std::cout of this process as the replacement of this _Pragma |
---|
398 | return interpret_pragma_system(ctx, pending, values, act_token); |
---|
399 | } |
---|
400 | if (option.get_value() == "stop") { |
---|
401 | // stop the execution and output the argument |
---|
402 | BOOST_WAVE_THROW(preprocess_exception, error_directive, |
---|
403 | boost::wave::util::impl::as_string(values).c_str(), |
---|
404 | act_token.get_position()); |
---|
405 | } |
---|
406 | if (option.get_value() == "option") { |
---|
407 | // handle different options |
---|
408 | return interpret_pragma_option(ctx, values, act_token); |
---|
409 | } |
---|
410 | return false; |
---|
411 | } |
---|
412 | |
---|
413 | /////////////////////////////////////////////////////////////////////////// |
---|
414 | // |
---|
415 | // The function 'opened_include_file' is called, whenever a file referred |
---|
416 | // by an #include directive was successfully located and opened. |
---|
417 | // |
---|
418 | // The parameter 'filename' contains the file system path of the |
---|
419 | // opened file (this is relative to the directory of the currently |
---|
420 | // processed file or a absolute path depending on the paths given as the |
---|
421 | // include search paths). |
---|
422 | // |
---|
423 | // The include_depth parameter contains the current include file depth. |
---|
424 | // |
---|
425 | // The is_system_include parameter denotes, whether the given file was |
---|
426 | // found as a result of a #include <...> directive. |
---|
427 | // |
---|
428 | /////////////////////////////////////////////////////////////////////////// |
---|
429 | void |
---|
430 | opened_include_file(std::string const &relname, std::string const &absname, |
---|
431 | std::size_t include_depth, bool is_system_include) |
---|
432 | { |
---|
433 | if (enabled_include_tracing()) { |
---|
434 | // print indented filename |
---|
435 | for (std::size_t i = 0; i < include_depth; ++i) |
---|
436 | includestrm << " "; |
---|
437 | |
---|
438 | if (is_system_include) |
---|
439 | includestrm << "<" << relname << "> (" << absname << ")"; |
---|
440 | else |
---|
441 | includestrm << "\"" << relname << "\" (" << absname << ")"; |
---|
442 | |
---|
443 | includestrm << std::endl; |
---|
444 | } |
---|
445 | } |
---|
446 | |
---|
447 | /////////////////////////////////////////////////////////////////////////// |
---|
448 | // |
---|
449 | // The function 'may_skip_whitespace' is called, will be called by the |
---|
450 | // library, whenever a token is about to be returned to the calling |
---|
451 | // application. |
---|
452 | // |
---|
453 | // The parameter 'ctx' is a reference to the context object used for |
---|
454 | // instantiating the preprocessing iterators by the user. |
---|
455 | // |
---|
456 | // The 'token' parameter holds a reference to the current token. The policy |
---|
457 | // is free to change this token if needed. |
---|
458 | // |
---|
459 | // The 'skipped_newline' parameter holds a reference to a boolean value |
---|
460 | // which should be set to true by the policy function whenever a newline |
---|
461 | // is going to be skipped. |
---|
462 | // |
---|
463 | // If the return value is true, the given token is skipped and the |
---|
464 | // preprocessing continues to the next token. If the return value is |
---|
465 | // false, the given token is returned to the calling application. |
---|
466 | // |
---|
467 | // ATTENTION! |
---|
468 | // Caution has to be used, because by returning true the policy function |
---|
469 | // is able to force skipping even significant tokens, not only whitespace. |
---|
470 | // |
---|
471 | /////////////////////////////////////////////////////////////////////////// |
---|
472 | template <typename ContextT> |
---|
473 | bool may_skip_whitespace(ContextT const &ctx, TokenT &token, bool &skipped_newline) |
---|
474 | { |
---|
475 | return this->base_type::may_skip_whitespace(ctx, token, skipped_newline) ? |
---|
476 | !preserve_whitespace : false; |
---|
477 | } |
---|
478 | |
---|
479 | protected: |
---|
480 | /////////////////////////////////////////////////////////////////////////// |
---|
481 | // Interpret the different Wave specific pragma directives/operators |
---|
482 | template <typename ContextT, typename ContainerT> |
---|
483 | bool |
---|
484 | interpret_pragma_trace(ContextT const &/*ctx*/, ContainerT const &values, |
---|
485 | typename ContextT::token_type const &act_token) |
---|
486 | { |
---|
487 | typedef typename ContextT::token_type token_type; |
---|
488 | typedef typename token_type::string_type string_type; |
---|
489 | |
---|
490 | bool valid_option = false; |
---|
491 | |
---|
492 | if (1 == values.size()) { |
---|
493 | token_type const &value = values.front(); |
---|
494 | |
---|
495 | if (value.get_value() == "enable" || |
---|
496 | value.get_value() == "on" || |
---|
497 | value.get_value() == "1") |
---|
498 | { |
---|
499 | // #pragma wave trace(enable) |
---|
500 | enable_tracing(static_cast<trace_flags>( |
---|
501 | tracing_enabled() | trace_macros)); |
---|
502 | valid_option = true; |
---|
503 | } |
---|
504 | else if (value.get_value() == "disable" || |
---|
505 | value.get_value() == "off" || |
---|
506 | value.get_value() == "0") |
---|
507 | { |
---|
508 | // #pragma wave trace(disable) |
---|
509 | enable_tracing(static_cast<trace_flags>( |
---|
510 | tracing_enabled() & ~trace_macros)); |
---|
511 | valid_option = true; |
---|
512 | } |
---|
513 | } |
---|
514 | if (!valid_option) { |
---|
515 | // unknown option value |
---|
516 | string_type option_str ("trace"); |
---|
517 | |
---|
518 | if (values.size() > 0) { |
---|
519 | option_str += "("; |
---|
520 | option_str += boost::wave::util::impl::as_string(values); |
---|
521 | option_str += ")"; |
---|
522 | } |
---|
523 | BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option, |
---|
524 | option_str.c_str(), act_token.get_position()); |
---|
525 | } |
---|
526 | return true; |
---|
527 | } |
---|
528 | |
---|
529 | /////////////////////////////////////////////////////////////////////////// |
---|
530 | // interpret the pragma wave option(preserve: [0|1|2]) directive |
---|
531 | template <typename ContextT, typename IteratorT> |
---|
532 | bool |
---|
533 | interpret_pragma_option_preserve(ContextT &ctx, IteratorT &it, |
---|
534 | IteratorT end, typename ContextT::token_type const &act_token) |
---|
535 | { |
---|
536 | using namespace boost::wave; |
---|
537 | |
---|
538 | token_id id = util::impl::skip_whitespace(it, end); |
---|
539 | if (T_COLON == id) |
---|
540 | id = util::impl::skip_whitespace(it, end); |
---|
541 | |
---|
542 | if (T_PP_NUMBER != id) |
---|
543 | return false; |
---|
544 | |
---|
545 | using namespace std; // some platforms have atoi in namespace std |
---|
546 | switch(atoi((*it).get_value().c_str())) { |
---|
547 | case 0: |
---|
548 | preserve_whitespace = false; |
---|
549 | ctx.set_language( |
---|
550 | enable_preserve_comments(ctx.get_language(), false), |
---|
551 | false); |
---|
552 | break; |
---|
553 | |
---|
554 | case 2: |
---|
555 | preserve_whitespace = true; |
---|
556 | /* fall through */ |
---|
557 | case 1: |
---|
558 | ctx.set_language( |
---|
559 | enable_preserve_comments(ctx.get_language()), |
---|
560 | false); |
---|
561 | break; |
---|
562 | |
---|
563 | default: |
---|
564 | return false; |
---|
565 | } |
---|
566 | return true; |
---|
567 | } |
---|
568 | |
---|
569 | // interpret the pragma wave option(line: [0|1]) directive |
---|
570 | template <typename ContextT, typename IteratorT> |
---|
571 | bool |
---|
572 | interpret_pragma_option_line(ContextT &ctx, IteratorT &it, |
---|
573 | IteratorT end, typename ContextT::token_type const &act_token) |
---|
574 | { |
---|
575 | using namespace boost::wave; |
---|
576 | |
---|
577 | token_id id = util::impl::skip_whitespace(it, end); |
---|
578 | if (T_COLON == id) |
---|
579 | id = util::impl::skip_whitespace(it, end); |
---|
580 | |
---|
581 | if (T_PP_NUMBER != id) |
---|
582 | return false; |
---|
583 | |
---|
584 | using namespace std; // some platforms have atoi in namespace std |
---|
585 | int emit_lines = atoi((*it).get_value().c_str()); |
---|
586 | if (0 == emit_lines || 1 == emit_lines) { |
---|
587 | // set the new emit #line directive mode |
---|
588 | ctx.set_language( |
---|
589 | enable_emit_line_directives(ctx.get_language(), emit_lines), |
---|
590 | false); |
---|
591 | return true; |
---|
592 | } |
---|
593 | return false; |
---|
594 | } |
---|
595 | |
---|
596 | // interpret the pragma wave option(output: ["filename"|null]) directive |
---|
597 | template <typename ContextT, typename IteratorT> |
---|
598 | bool |
---|
599 | interpret_pragma_option_output(ContextT &ctx, IteratorT &it, |
---|
600 | IteratorT end, typename ContextT::token_type const &act_token) |
---|
601 | { |
---|
602 | using namespace boost::wave; |
---|
603 | namespace fs = boost::filesystem; |
---|
604 | |
---|
605 | typedef typename ContextT::token_type token_type; |
---|
606 | typedef typename token_type::string_type string_type; |
---|
607 | |
---|
608 | token_id id = util::impl::skip_whitespace(it, end); |
---|
609 | if (T_COLON == id) |
---|
610 | id = util::impl::skip_whitespace(it, end); |
---|
611 | |
---|
612 | if (T_STRINGLIT == id) { |
---|
613 | namespace fs = boost::filesystem; |
---|
614 | |
---|
615 | string_type fname ((*it).get_value()); |
---|
616 | fs::path fpath ( |
---|
617 | util::impl::unescape_lit(fname.substr(1, fname.size()-2)).c_str(), |
---|
618 | fs::native); |
---|
619 | fpath = fs::complete(fpath, ctx.get_current_directory()); |
---|
620 | |
---|
621 | // close the current file |
---|
622 | if (outputstrm.is_open()) |
---|
623 | outputstrm.close(); |
---|
624 | |
---|
625 | // ensure all directories for this file do exist |
---|
626 | fs::create_directories(fpath.branch_path()); |
---|
627 | |
---|
628 | // figure out, whether the file to open was last accessed by us |
---|
629 | std::ios::openmode mode = std::ios::out; |
---|
630 | if (fs::exists(fpath) && fs::last_write_time(fpath) >= started_at) |
---|
631 | mode = (std::ios::openmode)(std::ios::out | std::ios::app); |
---|
632 | |
---|
633 | // open the new file |
---|
634 | outputstrm.open(fpath.string().c_str(), mode); |
---|
635 | if (!outputstrm.is_open()) { |
---|
636 | BOOST_WAVE_THROW(preprocess_exception, could_not_open_output_file, |
---|
637 | fpath.string().c_str(), act_token.get_position()); |
---|
638 | } |
---|
639 | generate_output = true; |
---|
640 | return true; |
---|
641 | } |
---|
642 | if (T_IDENTIFIER == id && (*it).get_value() == "null") { |
---|
643 | // suppress all output from this point on |
---|
644 | if (outputstrm.is_open()) |
---|
645 | outputstrm.close(); |
---|
646 | generate_output = false; |
---|
647 | return true; |
---|
648 | } |
---|
649 | if (T_DEFAULT == id) { |
---|
650 | // re-open the default output given on command line |
---|
651 | if (outputstrm.is_open()) |
---|
652 | outputstrm.close(); |
---|
653 | |
---|
654 | if (!default_outfile.empty()) { |
---|
655 | if (default_outfile == "-") { |
---|
656 | // the output was suppressed on the command line |
---|
657 | generate_output = false; |
---|
658 | } |
---|
659 | else { |
---|
660 | // there was a file name on the command line |
---|
661 | fs::path fpath(default_outfile, fs::native); |
---|
662 | |
---|
663 | // figure out, whether the file to open was last accessed by us |
---|
664 | std::ios::openmode mode = std::ios::out; |
---|
665 | if (fs::exists(fpath) && fs::last_write_time(fpath) >= started_at) |
---|
666 | mode = (std::ios::openmode)(std::ios::out | std::ios::app); |
---|
667 | |
---|
668 | // open the new file |
---|
669 | outputstrm.open(fpath.string().c_str(), mode); |
---|
670 | if (!outputstrm.is_open()) { |
---|
671 | BOOST_WAVE_THROW(preprocess_exception, |
---|
672 | could_not_open_output_file, fpath.string().c_str(), |
---|
673 | act_token.get_position()); |
---|
674 | } |
---|
675 | generate_output = true; |
---|
676 | } |
---|
677 | } |
---|
678 | else { |
---|
679 | // generate the output to std::cout |
---|
680 | generate_output = true; |
---|
681 | } |
---|
682 | return true; |
---|
683 | } |
---|
684 | return false; |
---|
685 | } |
---|
686 | |
---|
687 | /////////////////////////////////////////////////////////////////////////// |
---|
688 | // interpret the pragma wave option() directives |
---|
689 | template <typename ContextT, typename ContainerT> |
---|
690 | bool |
---|
691 | interpret_pragma_option(ContextT &ctx, ContainerT const &values, |
---|
692 | typename ContextT::token_type const &act_token) |
---|
693 | { |
---|
694 | using namespace boost::wave; |
---|
695 | |
---|
696 | typedef typename ContextT::token_type token_type; |
---|
697 | typedef typename token_type::string_type string_type; |
---|
698 | typedef typename ContainerT::const_iterator const_iterator; |
---|
699 | |
---|
700 | const_iterator end = values.end(); |
---|
701 | for (const_iterator it = values.begin(); it != end; /**/) { |
---|
702 | bool valid_option = false; |
---|
703 | |
---|
704 | token_type const &value = *it; |
---|
705 | if (value.get_value() == "preserve") { |
---|
706 | // #pragma wave option(preserve: [0|1|2]) |
---|
707 | valid_option = interpret_pragma_option_preserve(ctx, it, end, |
---|
708 | act_token); |
---|
709 | } |
---|
710 | else if (value.get_value() == "line") { |
---|
711 | // #pragma wave option(line: [0|1]) |
---|
712 | valid_option = interpret_pragma_option_line(ctx, it, end, |
---|
713 | act_token); |
---|
714 | } |
---|
715 | else if (value.get_value() == "output") { |
---|
716 | // #pragma wave option(output: ["filename"|null]) |
---|
717 | valid_option = interpret_pragma_option_output(ctx, it, end, |
---|
718 | act_token); |
---|
719 | } |
---|
720 | |
---|
721 | if (!valid_option) { |
---|
722 | // unknown option value |
---|
723 | string_type option_str ("option"); |
---|
724 | |
---|
725 | if (values.size() > 0) { |
---|
726 | option_str += "("; |
---|
727 | option_str += util::impl::as_string(values); |
---|
728 | option_str += ")"; |
---|
729 | } |
---|
730 | BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option, |
---|
731 | option_str.c_str(), act_token.get_position()); |
---|
732 | } |
---|
733 | |
---|
734 | token_id id = util::impl::skip_whitespace(it, end); |
---|
735 | if (id == T_COMMA) |
---|
736 | util::impl::skip_whitespace(it, end); |
---|
737 | } |
---|
738 | return true; |
---|
739 | } |
---|
740 | |
---|
741 | /////////////////////////////////////////////////////////////////////////// |
---|
742 | // interpret the #pragma wave system() directive |
---|
743 | template <typename ContextT, typename ContainerT> |
---|
744 | bool |
---|
745 | interpret_pragma_system(ContextT const &ctx, ContainerT &pending, |
---|
746 | ContainerT const &values, |
---|
747 | typename ContextT::token_type const &act_token) |
---|
748 | { |
---|
749 | typedef typename ContextT::token_type token_type; |
---|
750 | typedef typename token_type::string_type string_type; |
---|
751 | |
---|
752 | if (0 == values.size()) return false; // ill_formed_pragma_option |
---|
753 | |
---|
754 | string_type stdout_file(std::tmpnam(0)); |
---|
755 | string_type stderr_file(std::tmpnam(0)); |
---|
756 | string_type system_str(boost::wave::util::impl::as_string(values)); |
---|
757 | string_type native_cmd(system_str); |
---|
758 | |
---|
759 | system_str += " >" + stdout_file + " 2>" + stderr_file; |
---|
760 | if (0 != std::system(system_str.c_str())) { |
---|
761 | // unable to spawn the command |
---|
762 | string_type error_str("unable to spawn command: "); |
---|
763 | |
---|
764 | error_str += native_cmd; |
---|
765 | BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option, |
---|
766 | error_str.c_str(), act_token.get_position()); |
---|
767 | } |
---|
768 | |
---|
769 | // rescan the content of the stdout_file and insert it as the |
---|
770 | // _Pragma replacement |
---|
771 | typedef typename ContextT::lexer_type lexer_type; |
---|
772 | typedef typename ContextT::input_policy_type input_policy_type; |
---|
773 | typedef boost::wave::iteration_context<lexer_type, input_policy_type> |
---|
774 | iteration_context_type; |
---|
775 | |
---|
776 | iteration_context_type iter_ctx(stdout_file.c_str(), |
---|
777 | act_token.get_position(), ctx.get_language()); |
---|
778 | ContainerT pragma; |
---|
779 | |
---|
780 | for (/**/; iter_ctx.first != iter_ctx.last; ++iter_ctx.first) |
---|
781 | pragma.push_back(*iter_ctx.first); |
---|
782 | |
---|
783 | // prepend the newly generated token sequence to the 'pending' container |
---|
784 | pending.splice(pending.begin(), pragma); |
---|
785 | |
---|
786 | // erase the created tempfiles |
---|
787 | std::remove(stdout_file.c_str()); |
---|
788 | std::remove(stderr_file.c_str()); |
---|
789 | return true; |
---|
790 | } |
---|
791 | |
---|
792 | /////////////////////////////////////////////////////////////////////////// |
---|
793 | // The function enable_tracing is called, whenever the status of the |
---|
794 | // tracing was changed. |
---|
795 | // The parameter 'enable' is to be used as the new tracing status. |
---|
796 | void enable_tracing(trace_flags flags) |
---|
797 | { logging_flags = flags; } |
---|
798 | |
---|
799 | // The function tracing_enabled should return the current tracing status. |
---|
800 | trace_flags tracing_enabled() |
---|
801 | { return logging_flags; } |
---|
802 | |
---|
803 | // Helper functions for generating the trace output |
---|
804 | void open_trace_body(char const *label = 0) |
---|
805 | { |
---|
806 | if (label) |
---|
807 | output(label); |
---|
808 | output("[\n"); |
---|
809 | increment_level(); |
---|
810 | } |
---|
811 | void close_trace_body() |
---|
812 | { |
---|
813 | if (get_level() > 0) { |
---|
814 | decrement_level(); |
---|
815 | output("]\n"); |
---|
816 | tracestrm << std::flush; // flush the stream buffer |
---|
817 | } |
---|
818 | } |
---|
819 | |
---|
820 | template <typename StringT> |
---|
821 | void output(StringT const &outstr) const |
---|
822 | { |
---|
823 | indent(get_level()); |
---|
824 | tracestrm << outstr; // output the given string |
---|
825 | } |
---|
826 | |
---|
827 | void indent(int level) const |
---|
828 | { |
---|
829 | for (int i = 0; i < level; ++i) |
---|
830 | tracestrm << " "; // indent |
---|
831 | } |
---|
832 | |
---|
833 | int increment_level() { return ++level; } |
---|
834 | int decrement_level() { BOOST_ASSERT(level > 0); return --level; } |
---|
835 | int get_level() const { return level; } |
---|
836 | |
---|
837 | bool enabled_macro_tracing() const |
---|
838 | { |
---|
839 | return (flags & trace_macros) && (logging_flags & trace_macros); |
---|
840 | } |
---|
841 | bool enabled_include_tracing() const |
---|
842 | { |
---|
843 | return (flags & trace_includes); |
---|
844 | } |
---|
845 | |
---|
846 | void timer(TokenT const &value) |
---|
847 | { |
---|
848 | if (value.get_value() == "0" || value.get_value() == "restart") { |
---|
849 | // restart the timer |
---|
850 | elapsed_time.restart(); |
---|
851 | } |
---|
852 | else if (value.get_value() == "1") { |
---|
853 | // print out the current elapsed time |
---|
854 | std::cerr |
---|
855 | << value.get_position() << ": " |
---|
856 | << elapsed_time.format_elapsed_time() |
---|
857 | << std::endl; |
---|
858 | } |
---|
859 | else if (value.get_value() == "suspend") { |
---|
860 | // suspend the timer |
---|
861 | elapsed_time.suspend(); |
---|
862 | } |
---|
863 | else if (value.get_value() == "resume") { |
---|
864 | // resume the timer |
---|
865 | elapsed_time.resume(); |
---|
866 | } |
---|
867 | } |
---|
868 | |
---|
869 | private: |
---|
870 | std::ofstream &outputstrm; // main output stream |
---|
871 | std::ostream &tracestrm; // trace output stream |
---|
872 | std::ostream &includestrm; // included list output stream |
---|
873 | int level; // indentation level |
---|
874 | trace_flags flags; // enabled globally |
---|
875 | trace_flags logging_flags; // enabled by a #pragma |
---|
876 | bool enable_system_command; // enable #pragma wave system() command |
---|
877 | bool preserve_whitespace; // enable whitespace preservation |
---|
878 | bool& generate_output; // allow generated tokens to be streamed to output |
---|
879 | std::string const& default_outfile; // name of the output file given on command line |
---|
880 | |
---|
881 | stop_watch elapsed_time; // trace timings |
---|
882 | std::time_t started_at; // time, this process was started at |
---|
883 | }; |
---|
884 | |
---|
885 | #undef BOOST_WAVE_GETSTRING |
---|
886 | #undef BOOST_WAVE_OSSTREAM |
---|
887 | |
---|
888 | #endif // !defined(TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED) |
---|