]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/wave/tool/trace_macro_expansion.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / wave / tool / trace_macro_expansion.hpp
1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
3 http://www.boost.org/
4
5 Copyright (c) 2001-2012 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 #include <stack>
20 #include <set>
21
22 #include <boost/assert.hpp>
23 #include <boost/config.hpp>
24 #include <boost/filesystem/path.hpp>
25 #include <boost/filesystem/operations.hpp>
26 #include <boost/filesystem/convenience.hpp>
27
28 #include <boost/wave/token_ids.hpp>
29 #include <boost/wave/util/macro_helpers.hpp>
30 #include <boost/wave/util/filesystem_compatibility.hpp>
31 #include <boost/wave/preprocessing_hooks.hpp>
32 #include <boost/wave/whitespace_handling.hpp>
33 #include <boost/wave/language_support.hpp>
34 #include <boost/wave/cpp_exceptions.hpp>
35
36 #include "stop_watch.hpp"
37
38 #ifdef BOOST_NO_STRINGSTREAM
39 #include <strstream>
40 #define BOOST_WAVE_OSSTREAM std::ostrstream
41 std::string BOOST_WAVE_GETSTRING(std::ostrstream& ss)
42 {
43 ss << std::ends;
44 std::string rval = ss.str();
45 ss.freeze(false);
46 return rval;
47 }
48 #else
49 #include <sstream>
50 #define BOOST_WAVE_GETSTRING(ss) ss.str()
51 #define BOOST_WAVE_OSSTREAM std::ostringstream
52 #endif
53
54 // trace_flags: enable single tracing functionality
55 enum trace_flags {
56 trace_nothing = 0, // disable tracing
57 trace_macros = 1, // enable macro tracing
58 trace_macro_counts = 2, // enable invocation counting
59 trace_includes = 4, // enable include file tracing
60 trace_guards = 8 // enable include guard tracing
61 };
62
63 ///////////////////////////////////////////////////////////////////////////////
64 //
65 // Special error thrown whenever the #pragma wave system() directive is
66 // disabled
67 //
68 ///////////////////////////////////////////////////////////////////////////////
69 class bad_pragma_exception :
70 public boost::wave::preprocess_exception
71 {
72 public:
73 enum error_code {
74 pragma_system_not_enabled =
75 boost::wave::preprocess_exception::last_error_number + 1,
76 pragma_mismatched_push_pop,
77 };
78
79 bad_pragma_exception(char const *what_, error_code code, std::size_t line_,
80 std::size_t column_, char const *filename_) throw()
81 : boost::wave::preprocess_exception(what_,
82 (boost::wave::preprocess_exception::error_code)code, line_,
83 column_, filename_)
84 {
85 }
86 ~bad_pragma_exception() throw() {}
87
88 virtual char const *what() const throw()
89 {
90 return "boost::wave::bad_pragma_exception";
91 }
92 virtual bool is_recoverable() const throw()
93 {
94 return true;
95 }
96 virtual int get_severity() const throw()
97 {
98 return boost::wave::util::severity_remark;
99 }
100
101 static char const *error_text(int code)
102 {
103 switch(code) {
104 case pragma_system_not_enabled:
105 return "the directive '#pragma wave system()' was not enabled, use the "
106 "-x command line argument to enable the execution of";
107
108 case pragma_mismatched_push_pop:
109 return "unbalanced #pragma push/pop in input file(s) for option";
110 }
111 return "Unknown exception";
112 }
113 static boost::wave::util::severity severity_level(int code)
114 {
115 switch(code) {
116 case pragma_system_not_enabled:
117 return boost::wave::util::severity_remark;
118
119 case pragma_mismatched_push_pop:
120 return boost::wave::util::severity_error;
121 }
122 return boost::wave::util::severity_fatal;
123 }
124 static char const *severity_text(int code)
125 {
126 return boost::wave::util::get_severity(boost::wave::util::severity_remark);
127 }
128 };
129
130 ///////////////////////////////////////////////////////////////////////////////
131 //
132 // The trace_macro_expansion policy is used to trace the macro expansion of
133 // macros whenever it is requested from inside the input stream to preprocess
134 // through the '#pragma wave_option(trace: enable)' directive. The macro
135 // tracing is disabled with the help of a '#pragma wave_option(trace: disable)'
136 // directive.
137 //
138 // This policy type is used as a template parameter to the boost::wave::context<>
139 // object.
140 //
141 ///////////////////////////////////////////////////////////////////////////////
142 template <typename TokenT>
143 class trace_macro_expansion
144 : public boost::wave::context_policies::eat_whitespace<TokenT>
145 {
146 typedef boost::wave::context_policies::eat_whitespace<TokenT> base_type;
147
148 public:
149 trace_macro_expansion(
150 bool preserve_whitespace_, bool preserve_bol_whitespace_,
151 std::ofstream &output_, std::ostream &tracestrm_,
152 std::ostream &includestrm_, std::ostream &guardstrm_,
153 trace_flags flags_, bool enable_system_command_,
154 bool& generate_output_, std::string const& default_outfile_)
155 : outputstrm(output_), tracestrm(tracestrm_),
156 includestrm(includestrm_), guardstrm(guardstrm_),
157 level(0), flags(flags_), logging_flags(trace_nothing),
158 enable_system_command(enable_system_command_),
159 preserve_whitespace(preserve_whitespace_),
160 preserve_bol_whitespace(preserve_bol_whitespace_),
161 generate_output(generate_output_),
162 default_outfile(default_outfile_),
163 emit_relative_filenames(false)
164 {
165 }
166 ~trace_macro_expansion()
167 {
168 }
169
170 void enable_macro_counting()
171 {
172 logging_flags = trace_flags(logging_flags | trace_macro_counts);
173 }
174 std::map<std::string, std::size_t> const& get_macro_counts() const
175 {
176 return counts;
177 }
178
179 void enable_relative_names_in_line_directives(bool flag)
180 {
181 emit_relative_filenames = flag;
182 }
183 bool enable_relative_names_in_line_directives() const
184 {
185 return emit_relative_filenames;
186 }
187
188 // add a macro name, which should not be expanded at all (left untouched)
189 void add_noexpandmacro(std::string const& name)
190 {
191 noexpandmacros.insert(name);
192 }
193
194 void set_license_info(std::string const& info)
195 {
196 license_info = info;
197 }
198
199 ///////////////////////////////////////////////////////////////////////////
200 //
201 // The function 'expanding_function_like_macro' is called whenever a
202 // function-like macro is to be expanded.
203 //
204 // The parameter 'ctx' is a reference to the context object used for
205 // instantiating the preprocessing iterators by the user.
206 //
207 // The parameter 'macrodef' marks the position, where the macro to expand
208 // is defined.
209 //
210 // The parameter 'formal_args' holds the formal arguments used during the
211 // definition of the macro.
212 //
213 // The parameter 'definition' holds the macro definition for the macro to
214 // trace.
215 //
216 // The parameter 'macro_call' marks the position, where this macro invoked.
217 //
218 // The parameter 'arguments' holds the macro arguments used during the
219 // invocation of the macro
220 //
221 // The parameters 'seqstart' and 'seqend' point into the input token
222 // stream allowing to access the whole token sequence comprising the macro
223 // invocation (starting with the opening parenthesis and ending after the
224 // closing one).
225 //
226 // The return value defines whether the corresponding macro will be
227 // expanded (return false) or will be copied to the output (return true).
228 // Note: the whole argument list is copied unchanged to the output as well
229 // without any further processing.
230 //
231 ///////////////////////////////////////////////////////////////////////////
232 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
233 // old signature
234 template <typename ContainerT>
235 void expanding_function_like_macro(
236 TokenT const &macrodef, std::vector<TokenT> const &formal_args,
237 ContainerT const &definition,
238 TokenT const &macrocall, std::vector<ContainerT> const &arguments)
239 {
240 if (enabled_macro_counting())
241 count_invocation(macrodef.get_value().c_str());
242
243 if (!enabled_macro_tracing())
244 return;
245 #else
246 // new signature
247 template <typename ContextT, typename ContainerT, typename IteratorT>
248 bool
249 expanding_function_like_macro(ContextT const& ctx,
250 TokenT const &macrodef, std::vector<TokenT> const &formal_args,
251 ContainerT const &definition,
252 TokenT const &macrocall, std::vector<ContainerT> const &arguments,
253 IteratorT const& seqstart, IteratorT const& seqend)
254 {
255 if (enabled_macro_counting() || !noexpandmacros.empty()) {
256 std::string name (macrodef.get_value().c_str());
257
258 if (noexpandmacros.find(name.c_str()) != noexpandmacros.end())
259 return true; // do not expand this macro
260
261 if (enabled_macro_counting())
262 count_invocation(name.c_str());
263 }
264
265 if (!enabled_macro_tracing())
266 return false;
267 #endif
268 if (0 == get_level()) {
269 // output header line
270 BOOST_WAVE_OSSTREAM stream;
271
272 stream
273 << macrocall.get_position() << ": "
274 << macrocall.get_value() << "(";
275
276 // argument list
277 for (typename ContainerT::size_type i = 0; i < arguments.size(); ++i) {
278 stream << boost::wave::util::impl::as_string(arguments[i]);
279 if (i < arguments.size()-1)
280 stream << ", ";
281 }
282 stream << ")" << std::endl;
283 output(BOOST_WAVE_GETSTRING(stream));
284 increment_level();
285 }
286
287 // output definition reference
288 {
289 BOOST_WAVE_OSSTREAM stream;
290
291 stream
292 << macrodef.get_position() << ": see macro definition: "
293 << macrodef.get_value() << "(";
294
295 // formal argument list
296 for (typename std::vector<TokenT>::size_type i = 0;
297 i < formal_args.size(); ++i)
298 {
299 stream << formal_args[i].get_value();
300 if (i < formal_args.size()-1)
301 stream << ", ";
302 }
303 stream << ")" << std::endl;
304 output(BOOST_WAVE_GETSTRING(stream));
305 }
306
307 if (formal_args.size() > 0) {
308 // map formal and real arguments
309 open_trace_body("invoked with\n");
310 for (typename std::vector<TokenT>::size_type j = 0;
311 j < formal_args.size(); ++j)
312 {
313 using namespace boost::wave;
314
315 BOOST_WAVE_OSSTREAM stream;
316 stream << formal_args[j].get_value() << " = ";
317 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
318 if (T_ELLIPSIS == token_id(formal_args[j])) {
319 // ellipsis
320 for (typename ContainerT::size_type k = j;
321 k < arguments.size(); ++k)
322 {
323 stream << boost::wave::util::impl::as_string(arguments[k]);
324 if (k < arguments.size()-1)
325 stream << ", ";
326 }
327 }
328 else
329 #endif
330 {
331 stream << boost::wave::util::impl::as_string(arguments[j]);
332 }
333 stream << std::endl;
334 output(BOOST_WAVE_GETSTRING(stream));
335 }
336 close_trace_body();
337 }
338 open_trace_body();
339
340 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
341 return false;
342 #endif
343 }
344
345 ///////////////////////////////////////////////////////////////////////////
346 //
347 // The function 'expanding_object_like_macro' is called whenever a
348 // object-like macro is to be expanded .
349 //
350 // The parameter 'ctx' is a reference to the context object used for
351 // instantiating the preprocessing iterators by the user.
352 //
353 // The parameter 'macrodef' marks the position, where the macro to expand
354 // is defined.
355 //
356 // The definition 'definition' holds the macro definition for the macro to
357 // trace.
358 //
359 // The parameter 'macrocall' marks the position, where this macro invoked.
360 //
361 ///////////////////////////////////////////////////////////////////////////
362 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
363 // old signature
364 template <typename ContainerT>
365 void expanding_object_like_macro(TokenT const &macrodef,
366 ContainerT const &definition, TokenT const &macrocall)
367 {
368 if (enabled_macro_counting())
369 count_invocation(macrodef.get_value().c_str());
370
371 if (!enabled_macro_tracing())
372 return;
373 #else
374 // new signature
375 template <typename ContextT, typename ContainerT>
376 bool
377 expanding_object_like_macro(ContextT const& ctx,
378 TokenT const &macrodef, ContainerT const &definition,
379 TokenT const &macrocall)
380 {
381 if (enabled_macro_counting() || !noexpandmacros.empty()) {
382 std::string name (macrodef.get_value().c_str());
383
384 if (noexpandmacros.find(name.c_str()) != noexpandmacros.end())
385 return true; // do not expand this macro
386
387 if (enabled_macro_counting())
388 count_invocation(name.c_str());
389 }
390
391 if (!enabled_macro_tracing())
392 return false;
393 #endif
394 if (0 == get_level()) {
395 // output header line
396 BOOST_WAVE_OSSTREAM stream;
397
398 stream
399 << macrocall.get_position() << ": "
400 << macrocall.get_value() << std::endl;
401 output(BOOST_WAVE_GETSTRING(stream));
402 increment_level();
403 }
404
405 // output definition reference
406 {
407 BOOST_WAVE_OSSTREAM stream;
408
409 stream
410 << macrodef.get_position() << ": see macro definition: "
411 << macrodef.get_value() << std::endl;
412 output(BOOST_WAVE_GETSTRING(stream));
413 }
414 open_trace_body();
415
416 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
417 return false;
418 #endif
419 }
420
421 ///////////////////////////////////////////////////////////////////////////
422 //
423 // The function 'expanded_macro' is called whenever the expansion of a
424 // macro is finished but before the rescanning process starts.
425 //
426 // The parameter 'ctx' is a reference to the context object used for
427 // instantiating the preprocessing iterators by the user.
428 //
429 // The parameter 'result' contains the token sequence generated as the
430 // result of the macro expansion.
431 //
432 ///////////////////////////////////////////////////////////////////////////
433 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
434 // old signature
435 template <typename ContainerT>
436 void expanded_macro(ContainerT const &result)
437 #else
438 // new signature
439 template <typename ContextT, typename ContainerT>
440 void expanded_macro(ContextT const& ctx,ContainerT const &result)
441 #endif
442 {
443 if (!enabled_macro_tracing()) return;
444
445 BOOST_WAVE_OSSTREAM stream;
446 stream << boost::wave::util::impl::as_string(result) << std::endl;
447 output(BOOST_WAVE_GETSTRING(stream));
448
449 open_trace_body("rescanning\n");
450 }
451
452 ///////////////////////////////////////////////////////////////////////////
453 //
454 // The function 'rescanned_macro' is called whenever the rescanning of a
455 // macro is finished.
456 //
457 // The parameter 'ctx' is a reference to the context object used for
458 // instantiating the preprocessing iterators by the user.
459 //
460 // The parameter 'result' contains the token sequence generated as the
461 // result of the rescanning.
462 //
463 ///////////////////////////////////////////////////////////////////////////
464 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
465 // old signature
466 template <typename ContainerT>
467 void rescanned_macro(ContainerT const &result)
468 #else
469 // new signature
470 template <typename ContextT, typename ContainerT>
471 void rescanned_macro(ContextT const& ctx,ContainerT const &result)
472 #endif
473 {
474 if (!enabled_macro_tracing() || get_level() == 0)
475 return;
476
477 BOOST_WAVE_OSSTREAM stream;
478 stream << boost::wave::util::impl::as_string(result) << std::endl;
479 output(BOOST_WAVE_GETSTRING(stream));
480 close_trace_body();
481 close_trace_body();
482
483 if (1 == get_level())
484 decrement_level();
485 }
486
487 ///////////////////////////////////////////////////////////////////////////
488 //
489 // The function 'interpret_pragma' is called whenever a #pragma command
490 // directive is found which isn't known to the core Wave library, where
491 // command is the value defined as the BOOST_WAVE_PRAGMA_KEYWORD constant
492 // which defaults to "wave".
493 //
494 // The parameter 'ctx' is a reference to the context object used for
495 // instantiating the preprocessing iterators by the user.
496 //
497 // The parameter 'pending' may be used to push tokens back into the input
498 // stream, which are to be used as the replacement text for the whole
499 // #pragma directive.
500 //
501 // The parameter 'option' contains the name of the interpreted pragma.
502 //
503 // The parameter 'values' holds the values of the parameter provided to
504 // the pragma operator.
505 //
506 // The parameter 'act_token' contains the actual #pragma token, which may
507 // be used for error output.
508 //
509 // If the return value is 'false', the whole #pragma directive is
510 // interpreted as unknown and a corresponding error message is issued. A
511 // return value of 'true' signs a successful interpretation of the given
512 // #pragma.
513 //
514 ///////////////////////////////////////////////////////////////////////////
515 template <typename ContextT, typename ContainerT>
516 bool
517 interpret_pragma(ContextT &ctx, ContainerT &pending,
518 typename ContextT::token_type const &option, ContainerT const &valuetokens,
519 typename ContextT::token_type const &act_token)
520 {
521 typedef typename ContextT::token_type token_type;
522
523 ContainerT values(valuetokens);
524 boost::wave::util::impl::trim_sequence(values); // trim whitespace
525
526 if (option.get_value() == "timer") {
527 // #pragma wave timer(value)
528 if (0 == values.size()) {
529 // no value means '1'
530 using namespace boost::wave;
531 timer(token_type(T_INTLIT, "1", act_token.get_position()));
532 }
533 else {
534 timer(values.front());
535 }
536 return true;
537 }
538 if (option.get_value() == "trace") {
539 // enable/disable tracing option
540 return interpret_pragma_trace(ctx, values, act_token);
541 }
542 if (option.get_value() == "system") {
543 if (!enable_system_command) {
544 // if the #pragma wave system() directive is not enabled, throw
545 // a corresponding error (actually its a remark),
546 typename ContextT::string_type msg(
547 boost::wave::util::impl::as_string(values));
548 BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
549 pragma_system_not_enabled,
550 msg.c_str(), act_token.get_position());
551 return false;
552 }
553
554 // try to spawn the given argument as a system command and return the
555 // std::cout of this process as the replacement of this _Pragma
556 return interpret_pragma_system(ctx, pending, values, act_token);
557 }
558 if (option.get_value() == "stop") {
559 // stop the execution and output the argument
560 typename ContextT::string_type msg(
561 boost::wave::util::impl::as_string(values));
562 BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
563 error_directive, msg.c_str(), act_token.get_position());
564 return false;
565 }
566 if (option.get_value() == "option") {
567 // handle different options
568 return interpret_pragma_option(ctx, values, act_token);
569 }
570 return false;
571 }
572
573 ///////////////////////////////////////////////////////////////////////////
574 //
575 // The function 'emit_line_directive' is called whenever a #line directive
576 // has to be emitted into the generated output.
577 //
578 // The parameter 'ctx' is a reference to the context object used for
579 // instantiating the preprocessing iterators by the user.
580 //
581 // The parameter 'pending' may be used to push tokens back into the input
582 // stream, which are to be used instead of the default output generated
583 // for the #line directive.
584 //
585 // The parameter 'act_token' contains the actual #pragma token, which may
586 // be used for error output. The line number stored in this token can be
587 // used as the line number emitted as part of the #line directive.
588 //
589 // If the return value is 'false', a default #line directive is emitted
590 // by the library. A return value of 'true' will inhibit any further
591 // actions, the tokens contained in 'pending' will be copied verbatim
592 // to the output.
593 //
594 ///////////////////////////////////////////////////////////////////////////
595 template <typename ContextT, typename ContainerT>
596 bool
597 emit_line_directive(ContextT const& ctx, ContainerT &pending,
598 typename ContextT::token_type const& act_token)
599 {
600 if (!need_emit_line_directives(ctx.get_language()) ||
601 !enable_relative_names_in_line_directives())
602 {
603 return false;
604 }
605
606 // emit a #line directive showing the relative filename instead
607 typename ContextT::position_type pos = act_token.get_position();
608 unsigned int column = 6;
609
610 typedef typename ContextT::token_type result_type;
611 using namespace boost::wave;
612
613 pos.set_column(1);
614 pending.push_back(result_type(T_PP_LINE, "#line", pos));
615
616 pos.set_column(column); // account for '#line'
617 pending.push_back(result_type(T_SPACE, " ", pos));
618
619 // 21 is the max required size for a 64 bit integer represented as a
620 // string
621 char buffer[22];
622
623 using namespace std; // for some systems sprintf is in namespace std
624 sprintf (buffer, "%ld", pos.get_line());
625
626 pos.set_column(++column); // account for ' '
627 pending.push_back(result_type(T_INTLIT, buffer, pos));
628 pos.set_column(column += (unsigned int)strlen(buffer)); // account for <number>
629 pending.push_back(result_type(T_SPACE, " ", pos));
630 pos.set_column(++column); // account for ' '
631
632 std::string file("\"");
633 boost::filesystem::path filename(
634 boost::wave::util::create_path(ctx.get_current_relative_filename().c_str()));
635
636 using boost::wave::util::impl::escape_lit;
637 file += escape_lit(boost::wave::util::native_file_string(filename)) + "\"";
638
639 pending.push_back(result_type(T_STRINGLIT, file.c_str(), pos));
640 pos.set_column(column += (unsigned int)file.size()); // account for filename
641 pending.push_back(result_type(T_GENERATEDNEWLINE, "\n", pos));
642
643 return true;
644 }
645
646 ///////////////////////////////////////////////////////////////////////////
647 //
648 // The function 'opened_include_file' is called whenever a file referred
649 // by an #include directive was successfully located and opened.
650 //
651 // The parameter 'ctx' is a reference to the context object used for
652 // instantiating the preprocessing iterators by the user.
653 //
654 // The parameter 'filename' contains the file system path of the
655 // opened file (this is relative to the directory of the currently
656 // processed file or a absolute path depending on the paths given as the
657 // include search paths).
658 //
659 // The include_depth parameter contains the current include file depth.
660 //
661 // The is_system_include parameter denotes, whether the given file was
662 // found as a result of a #include <...> directive.
663 //
664 ///////////////////////////////////////////////////////////////////////////
665 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
666 // old signature
667 void
668 opened_include_file(std::string const &relname, std::string const &absname,
669 std::size_t include_depth, bool is_system_include)
670 {
671 #else
672 // new signature
673 template <typename ContextT>
674 void
675 opened_include_file(ContextT const& ctx, std::string const &relname,
676 std::string const &absname, bool is_system_include)
677 {
678 std::size_t include_depth = ctx.get_iteration_depth();
679 #endif
680 if (enabled_include_tracing()) {
681 // print indented filename
682 for (std::size_t i = 0; i < include_depth; ++i)
683 includestrm << " ";
684
685 if (is_system_include)
686 includestrm << "<" << relname << "> (" << absname << ")";
687 else
688 includestrm << "\"" << relname << "\" (" << absname << ")";
689
690 includestrm << std::endl;
691 }
692 }
693
694 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
695 ///////////////////////////////////////////////////////////////////////////
696 //
697 // The function 'detected_include_guard' is called whenever either a
698 // include file is about to be added to the list of #pragma once headers.
699 // That means this header file will not be opened and parsed again even
700 // if it is specified in a later #include directive.
701 // This function is called as the result of a detected include guard
702 // scheme.
703 //
704 // The implemented heuristics for include guards detects two forms of
705 // include guards:
706 //
707 // #ifndef INCLUDE_GUARD_MACRO
708 // #define INCLUDE_GUARD_MACRO
709 // ...
710 // #endif
711 //
712 // or
713 //
714 // if !defined(INCLUDE_GUARD_MACRO)
715 // #define INCLUDE_GUARD_MACRO
716 // ...
717 // #endif
718 //
719 // note, that the parenthesis are optional (i.e. !defined INCLUDE_GUARD_MACRO
720 // will work as well). The code allows for any whitespace, newline and single
721 // '#' tokens before the #if/#ifndef and after the final #endif.
722 //
723 // The parameter 'ctx' is a reference to the context object used for
724 // instantiating the preprocessing iterators by the user.
725 //
726 // The parameter 'filename' contains the file system path of the
727 // opened file (this is relative to the directory of the currently
728 // processed file or a absolute path depending on the paths given as the
729 // include search paths).
730 //
731 // The parameter contains the name of the detected include guard.
732 //
733 ///////////////////////////////////////////////////////////////////////////
734 template <typename ContextT>
735 void
736 detected_include_guard(ContextT const& ctx, std::string const& filename,
737 std::string const& include_guard)
738 {
739 if (enabled_guard_tracing()) {
740 guardstrm << include_guard << ":" << std::endl
741 << " " << filename << std::endl;
742 }
743 }
744 #endif
745
746 ///////////////////////////////////////////////////////////////////////////
747 //
748 // The function 'may_skip_whitespace' will be called by the
749 // library whenever a token is about to be returned to the calling
750 // application.
751 //
752 // The parameter 'ctx' is a reference to the context object used for
753 // instantiating the preprocessing iterators by the user.
754 //
755 // The 'token' parameter holds a reference to the current token. The policy
756 // is free to change this token if needed.
757 //
758 // The 'skipped_newline' parameter holds a reference to a boolean value
759 // which should be set to true by the policy function whenever a newline
760 // is going to be skipped.
761 //
762 // If the return value is true, the given token is skipped and the
763 // preprocessing continues to the next token. If the return value is
764 // false, the given token is returned to the calling application.
765 //
766 // ATTENTION!
767 // Caution has to be used, because by returning true the policy function
768 // is able to force skipping even significant tokens, not only whitespace.
769 //
770 ///////////////////////////////////////////////////////////////////////////
771 template <typename ContextT>
772 bool may_skip_whitespace(ContextT const &ctx, TokenT &token,
773 bool &skipped_newline)
774 {
775 return this->base_type::may_skip_whitespace(
776 ctx, token, need_preserve_comments(ctx.get_language()),
777 preserve_bol_whitespace, skipped_newline) ?
778 !preserve_whitespace : false;
779 }
780
781 ///////////////////////////////////////////////////////////////////////////
782 //
783 // The function 'throw_exception' will be called by the library whenever a
784 // preprocessing exception occurs.
785 //
786 // The parameter 'ctx' is a reference to the context object used for
787 // instantiating the preprocessing iterators by the user.
788 //
789 // The parameter 'e' is the exception object containing detailed error
790 // information.
791 //
792 // The default behavior is to call the function boost::throw_exception.
793 //
794 ///////////////////////////////////////////////////////////////////////////
795 template <typename ContextT>
796 void
797 throw_exception(ContextT const& ctx, boost::wave::preprocess_exception const& e)
798 {
799 #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
800 if (!is_import_directive_error(e))
801 boost::throw_exception(e);
802 #else
803 boost::throw_exception(e);
804 #endif
805 }
806 using base_type::throw_exception;
807
808 protected:
809 #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
810 ///////////////////////////////////////////////////////////////////////////
811 // Avoid throwing an error from a #import directive
812 bool is_import_directive_error(boost::wave::preprocess_exception const& e)
813 {
814 using namespace boost::wave;
815 if (e.get_errorcode() != preprocess_exception::ill_formed_directive)
816 return false;
817
818 // the error string is formatted as 'severity: error: directive'
819 std::string error(e.description());
820 std::string::size_type p = error.find_last_of(":");
821 return p != std::string::npos && error.substr(p+2) == "import";
822 }
823 #endif
824
825 ///////////////////////////////////////////////////////////////////////////
826 // Interpret the different Wave specific pragma directives/operators
827 template <typename ContextT, typename ContainerT>
828 bool
829 interpret_pragma_trace(ContextT& ctx, ContainerT const &values,
830 typename ContextT::token_type const &act_token)
831 {
832 typedef typename ContextT::token_type token_type;
833 typedef typename token_type::string_type string_type;
834
835 bool valid_option = false;
836
837 if (1 == values.size()) {
838 token_type const &value = values.front();
839
840 if (value.get_value() == "enable" ||
841 value.get_value() == "on" ||
842 value.get_value() == "1")
843 {
844 // #pragma wave trace(enable)
845 enable_tracing(static_cast<trace_flags>(
846 tracing_enabled() | trace_macros));
847 valid_option = true;
848 }
849 else if (value.get_value() == "disable" ||
850 value.get_value() == "off" ||
851 value.get_value() == "0")
852 {
853 // #pragma wave trace(disable)
854 enable_tracing(static_cast<trace_flags>(
855 tracing_enabled() & ~trace_macros));
856 valid_option = true;
857 }
858 }
859 if (!valid_option) {
860 // unknown option value
861 string_type option_str ("trace");
862
863 if (values.size() > 0) {
864 option_str += "(";
865 option_str += boost::wave::util::impl::as_string(values);
866 option_str += ")";
867 }
868 BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
869 ill_formed_pragma_option, option_str.c_str(),
870 act_token.get_position());
871 return false;
872 }
873 return true;
874 }
875
876 ///////////////////////////////////////////////////////////////////////////
877 // interpret the pragma wave option(preserve: [0|1|2|3|push|pop]) directive
878 template <typename ContextT>
879 static bool
880 interpret_pragma_option_preserve_set(int mode, bool &preserve_whitespace,
881 bool& preserve_bol_whitespace, ContextT &ctx)
882 {
883 switch(mode) {
884 // preserve no whitespace
885 case 0:
886 preserve_whitespace = false;
887 preserve_bol_whitespace = false;
888 ctx.set_language(
889 enable_preserve_comments(ctx.get_language(), false),
890 false);
891 break;
892
893 // preserve BOL whitespace only
894 case 1:
895 preserve_whitespace = false;
896 preserve_bol_whitespace = true;
897 ctx.set_language(
898 enable_preserve_comments(ctx.get_language(), false),
899 false);
900 break;
901
902 // preserve comments and BOL whitespace only
903 case 2:
904 preserve_whitespace = false;
905 preserve_bol_whitespace = true;
906 ctx.set_language(
907 enable_preserve_comments(ctx.get_language()),
908 false);
909 break;
910
911 // preserve all whitespace
912 case 3:
913 preserve_whitespace = true;
914 preserve_bol_whitespace = true;
915 ctx.set_language(
916 enable_preserve_comments(ctx.get_language()),
917 false);
918 break;
919
920 default:
921 return false;
922 }
923 return true;
924 }
925
926 template <typename ContextT, typename IteratorT>
927 bool
928 interpret_pragma_option_preserve(ContextT &ctx, IteratorT &it,
929 IteratorT end, typename ContextT::token_type const &act_token)
930 {
931 using namespace boost::wave;
932
933 token_id id = util::impl::skip_whitespace(it, end);
934 if (T_COLON == id)
935 id = util::impl::skip_whitespace(it, end);
936
937 // implement push/pop
938 if (T_IDENTIFIER == id) {
939 if ((*it).get_value() == "push") {
940 // push current preserve option onto the internal option stack
941 if (need_preserve_comments(ctx.get_language())) {
942 if (preserve_whitespace)
943 preserve_options.push(3);
944 else
945 preserve_options.push(2);
946 }
947 else if (preserve_bol_whitespace) {
948 preserve_options.push(1);
949 }
950 else {
951 preserve_options.push(0);
952 }
953 return true;
954 }
955 else if ((*it).get_value() == "pop") {
956 // test for mismatched push/pop #pragmas
957 if (preserve_options.empty()) {
958 BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
959 pragma_mismatched_push_pop, "preserve",
960 act_token.get_position());
961 }
962
963 // pop output preserve from the internal option stack
964 bool result = interpret_pragma_option_preserve_set(
965 preserve_options.top(), preserve_whitespace,
966 preserve_bol_whitespace, ctx);
967 preserve_options.pop();
968 return result;
969 }
970 return false;
971 }
972
973 if (T_PP_NUMBER != id)
974 return false;
975
976 using namespace std; // some platforms have atoi in namespace std
977 return interpret_pragma_option_preserve_set(
978 atoi((*it).get_value().c_str()), preserve_whitespace,
979 preserve_bol_whitespace, ctx);
980 }
981
982 // interpret the pragma wave option(line: [0|1|2|push|pop]) directive
983 template <typename ContextT, typename IteratorT>
984 bool
985 interpret_pragma_option_line(ContextT &ctx, IteratorT &it,
986 IteratorT end, typename ContextT::token_type const &act_token)
987 {
988 using namespace boost::wave;
989
990 token_id id = util::impl::skip_whitespace(it, end);
991 if (T_COLON == id)
992 id = util::impl::skip_whitespace(it, end);
993
994 // implement push/pop
995 if (T_IDENTIFIER == id) {
996 if ((*it).get_value() == "push") {
997 // push current line option onto the internal option stack
998 int mode = 0;
999 if (need_emit_line_directives(ctx.get_language())) {
1000 mode = 1;
1001 if (enable_relative_names_in_line_directives())
1002 mode = 2;
1003 }
1004 line_options.push(mode);
1005 return true;
1006 }
1007 else if ((*it).get_value() == "pop") {
1008 // test for mismatched push/pop #pragmas
1009 if (line_options.empty()) {
1010 BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
1011 pragma_mismatched_push_pop, "line",
1012 act_token.get_position());
1013 }
1014
1015 // pop output line from the internal option stack
1016 ctx.set_language(
1017 enable_emit_line_directives(ctx.get_language(), 0 != line_options.top()),
1018 false);
1019 enable_relative_names_in_line_directives(2 == line_options.top());
1020 line_options.pop();
1021 return true;
1022 }
1023 return false;
1024 }
1025
1026 if (T_PP_NUMBER != id)
1027 return false;
1028
1029 using namespace std; // some platforms have atoi in namespace std
1030 int emit_lines = atoi((*it).get_value().c_str());
1031 if (0 == emit_lines || 1 == emit_lines || 2 == emit_lines) {
1032 // set the new emit #line directive mode
1033 ctx.set_language(
1034 enable_emit_line_directives(ctx.get_language(), emit_lines),
1035 false);
1036 return true;
1037 }
1038 return false;
1039 }
1040
1041 // interpret the pragma wave option(output: ["filename"|null|default|push|pop])
1042 // directive
1043 template <typename ContextT>
1044 bool
1045 interpret_pragma_option_output_open(boost::filesystem::path &fpath,
1046 ContextT& ctx, typename ContextT::token_type const &act_token)
1047 {
1048 namespace fs = boost::filesystem;
1049
1050 // ensure all directories for this file do exist
1051 boost::wave::util::create_directories(
1052 boost::wave::util::branch_path(fpath));
1053
1054 // figure out, whether the file has been written to by us, if yes, we
1055 // append any output to this file, otherwise we overwrite it
1056 std::ios::openmode mode = std::ios::out;
1057 if (fs::exists(fpath) && written_by_us.find(fpath) != written_by_us.end())
1058 mode = (std::ios::openmode)(std::ios::out | std::ios::app);
1059
1060 written_by_us.insert(fpath);
1061
1062 // close the current file
1063 if (outputstrm.is_open())
1064 outputstrm.close();
1065
1066 // open the new file
1067 outputstrm.open(fpath.string().c_str(), mode);
1068 if (!outputstrm.is_open()) {
1069 BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
1070 could_not_open_output_file,
1071 fpath.string().c_str(), act_token.get_position());
1072 return false;
1073 }
1074
1075 // write license text, if file was created and if requested
1076 if (mode == std::ios::out && !license_info.empty())
1077 outputstrm << license_info;
1078
1079 generate_output = true;
1080 current_outfile = fpath;
1081 return true;
1082 }
1083
1084 bool interpret_pragma_option_output_close(bool generate)
1085 {
1086 if (outputstrm.is_open())
1087 outputstrm.close();
1088 current_outfile = boost::filesystem::path();
1089 generate_output = generate;
1090 return true;
1091 }
1092
1093 template <typename ContextT, typename IteratorT>
1094 bool
1095 interpret_pragma_option_output(ContextT &ctx, IteratorT &it,
1096 IteratorT end, typename ContextT::token_type const &act_token)
1097 {
1098 using namespace boost::wave;
1099 namespace fs = boost::filesystem;
1100
1101 typedef typename ContextT::token_type token_type;
1102 typedef typename token_type::string_type string_type;
1103
1104 token_id id = util::impl::skip_whitespace(it, end);
1105 if (T_COLON == id)
1106 id = util::impl::skip_whitespace(it, end);
1107
1108 bool result = false;
1109 if (T_STRINGLIT == id) {
1110 namespace fs = boost::filesystem;
1111
1112 string_type fname ((*it).get_value());
1113 fs::path fpath (boost::wave::util::create_path(
1114 util::impl::unescape_lit(fname.substr(1, fname.size()-2)).c_str()));
1115 fpath = boost::wave::util::complete_path(fpath, ctx.get_current_directory());
1116 result = interpret_pragma_option_output_open(fpath, ctx, act_token);
1117 }
1118 else if (T_IDENTIFIER == id) {
1119 if ((*it).get_value() == "null") {
1120 // suppress all output from this point on
1121 result = interpret_pragma_option_output_close(false);
1122 }
1123 else if ((*it).get_value() == "push") {
1124 // initialize the current_outfile, if appropriate
1125 if (output_options.empty() && current_outfile.empty() &&
1126 !default_outfile.empty() && default_outfile != "-")
1127 {
1128 current_outfile = boost::wave::util::complete_path(
1129 default_outfile, ctx.get_current_directory());
1130 }
1131
1132 // push current output option onto the internal option stack
1133 output_options.push(
1134 output_option_type(generate_output, current_outfile));
1135 result = true;
1136 }
1137 else if ((*it).get_value() == "pop") {
1138 // test for mismatched push/pop #pragmas
1139 if (output_options.empty()) {
1140 BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
1141 pragma_mismatched_push_pop, "output",
1142 act_token.get_position());
1143 return false;
1144 }
1145
1146 // pop output option from the internal option stack
1147 output_option_type const& opts = output_options.top();
1148 generate_output = opts.first;
1149 current_outfile = opts.second;
1150 if (!current_outfile.empty()) {
1151 // re-open the last file
1152 result = interpret_pragma_option_output_open(current_outfile,
1153 ctx, act_token);
1154 }
1155 else {
1156 // either no output or generate to std::cout
1157 result = interpret_pragma_option_output_close(generate_output);
1158 }
1159 output_options.pop();
1160 }
1161 }
1162 else if (T_DEFAULT == id) {
1163 // re-open the default output given on command line
1164 if (!default_outfile.empty()) {
1165 if (default_outfile == "-") {
1166 // the output was suppressed on the command line
1167 result = interpret_pragma_option_output_close(false);
1168 }
1169 else {
1170 // there was a file name on the command line
1171 fs::path fpath(boost::wave::util::create_path(default_outfile));
1172 result = interpret_pragma_option_output_open(fpath, ctx,
1173 act_token);
1174 }
1175 }
1176 else {
1177 // generate the output to std::cout
1178 result = interpret_pragma_option_output_close(true);
1179 }
1180 }
1181 return result;
1182 }
1183
1184 ///////////////////////////////////////////////////////////////////////////
1185 // join all adjacent string tokens into the first one
1186 template <typename StringT>
1187 StringT unlit(StringT const& str)
1188 {
1189 return str.substr(1, str.size()-2);
1190 }
1191
1192 template <typename StringT>
1193 StringT merge_string_lits(StringT const& lhs, StringT const& rhs)
1194 {
1195 StringT result ("\"");
1196
1197 result += unlit(lhs);
1198 result += unlit(rhs);
1199 result += "\"";
1200 return result;
1201 }
1202
1203 template <typename ContextT, typename ContainerT>
1204 void join_adjacent_string_tokens(ContextT &ctx, ContainerT const& values,
1205 ContainerT& joined_values)
1206 {
1207 using namespace boost::wave;
1208
1209 typedef typename ContextT::token_type token_type;
1210 typedef typename token_type::string_type string_type;
1211 typedef typename ContainerT::const_iterator const_iterator;
1212 typedef typename ContainerT::iterator iterator;
1213
1214 token_type* current = 0;
1215
1216 const_iterator end = values.end();
1217 for (const_iterator it = values.begin(); it != end; ++it) {
1218 token_id id(*it);
1219
1220 if (id == T_STRINGLIT) {
1221 if (!current) {
1222 joined_values.push_back(*it);
1223 current = &joined_values.back();
1224 }
1225 else {
1226 current->set_value(merge_string_lits(
1227 current->get_value(), (*it).get_value()));
1228 }
1229 }
1230 else if (current) {
1231 typedef util::impl::next_token<const_iterator> next_token_type;
1232 token_id next_id (next_token_type::peek(it, end, true));
1233
1234 if (next_id != T_STRINGLIT) {
1235 current = 0;
1236 joined_values.push_back(*it);
1237 }
1238 }
1239 else {
1240 joined_values.push_back(*it);
1241 }
1242 }
1243 }
1244
1245 ///////////////////////////////////////////////////////////////////////////
1246 // interpret the pragma wave option() directives
1247 template <typename ContextT, typename ContainerT>
1248 bool
1249 interpret_pragma_option(ContextT &ctx, ContainerT const &cvalues,
1250 typename ContextT::token_type const &act_token)
1251 {
1252 using namespace boost::wave;
1253
1254 typedef typename ContextT::token_type token_type;
1255 typedef typename token_type::string_type string_type;
1256 typedef typename ContainerT::const_iterator const_iterator;
1257
1258 ContainerT values;
1259 join_adjacent_string_tokens(ctx, cvalues, values);
1260
1261 const_iterator end = values.end();
1262 for (const_iterator it = values.begin(); it != end; /**/) {
1263 bool valid_option = false;
1264
1265 token_type const &value = *it;
1266 if (value.get_value() == "preserve") {
1267 // #pragma wave option(preserve: [0|1|2|3|push|pop])
1268 valid_option = interpret_pragma_option_preserve(ctx, it, end,
1269 act_token);
1270 }
1271 else if (value.get_value() == "line") {
1272 // #pragma wave option(line: [0|1|2|push|pop])
1273 valid_option = interpret_pragma_option_line(ctx, it, end,
1274 act_token);
1275 }
1276 else if (value.get_value() == "output") {
1277 // #pragma wave option(output: ["filename"|null|default|push|pop])
1278 valid_option = interpret_pragma_option_output(ctx, it, end,
1279 act_token);
1280 }
1281
1282 if (!valid_option) {
1283 // unknown option value
1284 string_type option_str ("option");
1285
1286 if (values.size() > 0) {
1287 option_str += "(";
1288 option_str += util::impl::as_string(values);
1289 option_str += ")";
1290 }
1291 BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
1292 ill_formed_pragma_option,
1293 option_str.c_str(), act_token.get_position());
1294 return false;
1295 }
1296
1297 token_id id = util::impl::skip_whitespace(it, end);
1298 if (id == T_COMMA)
1299 util::impl::skip_whitespace(it, end);
1300 }
1301 return true;
1302 }
1303
1304 ///////////////////////////////////////////////////////////////////////////
1305 // interpret the #pragma wave system() directive
1306 template <typename ContextT, typename ContainerT>
1307 bool
1308 interpret_pragma_system(ContextT& ctx, ContainerT &pending,
1309 ContainerT const &values,
1310 typename ContextT::token_type const &act_token)
1311 {
1312 typedef typename ContextT::token_type token_type;
1313 typedef typename token_type::string_type string_type;
1314
1315 if (0 == values.size()) return false; // ill_formed_pragma_option
1316
1317 string_type stdout_file(std::tmpnam(0));
1318 string_type stderr_file(std::tmpnam(0));
1319 string_type system_str(boost::wave::util::impl::as_string(values));
1320 string_type native_cmd(system_str);
1321
1322 system_str += " >" + stdout_file + " 2>" + stderr_file;
1323 if (0 != std::system(system_str.c_str())) {
1324 // unable to spawn the command
1325 string_type error_str("unable to spawn command: ");
1326
1327 error_str += native_cmd;
1328 BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
1329 ill_formed_pragma_option,
1330 error_str.c_str(), act_token.get_position());
1331 return false;
1332 }
1333
1334 // rescan the content of the stdout_file and insert it as the
1335 // _Pragma replacement
1336 typedef typename ContextT::lexer_type lexer_type;
1337 typedef typename ContextT::input_policy_type input_policy_type;
1338 typedef boost::wave::iteration_context<
1339 ContextT, lexer_type, input_policy_type>
1340 iteration_context_type;
1341
1342 iteration_context_type iter_ctx(ctx, stdout_file.c_str(),
1343 act_token.get_position(), ctx.get_language());
1344 ContainerT pragma;
1345
1346 for (/**/; iter_ctx.first != iter_ctx.last; ++iter_ctx.first)
1347 pragma.push_back(*iter_ctx.first);
1348
1349 // prepend the newly generated token sequence to the 'pending' container
1350 pending.splice(pending.begin(), pragma);
1351
1352 // erase the created tempfiles
1353 std::remove(stdout_file.c_str());
1354 std::remove(stderr_file.c_str());
1355 return true;
1356 }
1357
1358 ///////////////////////////////////////////////////////////////////////////
1359 // The function enable_tracing is called, whenever the status of the
1360 // tracing was changed.
1361 // The parameter 'enable' is to be used as the new tracing status.
1362 void enable_tracing(trace_flags flags)
1363 { logging_flags = flags; }
1364
1365 // The function tracing_enabled should return the current tracing status.
1366 trace_flags tracing_enabled()
1367 { return logging_flags; }
1368
1369 // Helper functions for generating the trace output
1370 void open_trace_body(char const *label = 0)
1371 {
1372 if (label)
1373 output(label);
1374 output("[\n");
1375 increment_level();
1376 }
1377 void close_trace_body()
1378 {
1379 if (get_level() > 0) {
1380 decrement_level();
1381 output("]\n");
1382 tracestrm << std::flush; // flush the stream buffer
1383 }
1384 }
1385
1386 template <typename StringT>
1387 void output(StringT const &outstr) const
1388 {
1389 indent(get_level());
1390 tracestrm << outstr; // output the given string
1391 }
1392
1393 void indent(int level) const
1394 {
1395 for (int i = 0; i < level; ++i)
1396 tracestrm << " "; // indent
1397 }
1398
1399 int increment_level() { return ++level; }
1400 int decrement_level() { BOOST_ASSERT(level > 0); return --level; }
1401 int get_level() const { return level; }
1402
1403 bool enabled_macro_tracing() const
1404 {
1405 return (flags & trace_macros) && (logging_flags & trace_macros);
1406 }
1407 bool enabled_include_tracing() const
1408 {
1409 return (flags & trace_includes);
1410 }
1411 bool enabled_guard_tracing() const
1412 {
1413 return (flags & trace_guards);
1414 }
1415 bool enabled_macro_counting() const
1416 {
1417 return logging_flags & trace_macro_counts;
1418 }
1419
1420 void count_invocation(std::string const& name)
1421 {
1422 typedef std::map<std::string, std::size_t>::iterator iterator;
1423 typedef std::map<std::string, std::size_t>::value_type value_type;
1424
1425 iterator it = counts.find(name);
1426 if (it == counts.end())
1427 {
1428 std::pair<iterator, bool> p = counts.insert(value_type(name, 0));
1429 if (p.second)
1430 it = p.first;
1431 }
1432
1433 if (it != counts.end())
1434 ++(*it).second;
1435 }
1436
1437 void timer(TokenT const &value)
1438 {
1439 if (value.get_value() == "0" || value.get_value() == "restart") {
1440 // restart the timer
1441 elapsed_time.restart();
1442 }
1443 else if (value.get_value() == "1") {
1444 // print out the current elapsed time
1445 std::cerr
1446 << value.get_position() << ": "
1447 << elapsed_time.format_elapsed_time()
1448 << std::endl;
1449 }
1450 else if (value.get_value() == "suspend") {
1451 // suspend the timer
1452 elapsed_time.suspend();
1453 }
1454 else if (value.get_value() == "resume") {
1455 // resume the timer
1456 elapsed_time.resume();
1457 }
1458 }
1459
1460 private:
1461 std::ofstream &outputstrm; // main output stream
1462 std::ostream &tracestrm; // trace output stream
1463 std::ostream &includestrm; // included list output stream
1464 std::ostream &guardstrm; // include guard output stream
1465 int level; // indentation level
1466 trace_flags flags; // enabled globally
1467 trace_flags logging_flags; // enabled by a #pragma
1468 bool enable_system_command; // enable #pragma wave system() command
1469 bool preserve_whitespace; // enable whitespace preservation
1470 bool preserve_bol_whitespace; // enable begin of line whitespace preservation
1471 bool& generate_output; // allow generated tokens to be streamed to output
1472 std::string const& default_outfile; // name of the output file given on command line
1473 boost::filesystem::path current_outfile; // name of the current output file
1474
1475 stop_watch elapsed_time; // trace timings
1476 std::set<boost::filesystem::path> written_by_us; // all files we have written to
1477
1478 typedef std::pair<bool, boost::filesystem::path> output_option_type;
1479 std::stack<output_option_type> output_options; // output option stack
1480 std::stack<int> line_options; // line option stack
1481 std::stack<int> preserve_options; // preserve option stack
1482
1483 std::map<std::string, std::size_t> counts; // macro invocation counts
1484 bool emit_relative_filenames; // emit relative names in #line directives
1485
1486 std::set<std::string> noexpandmacros; // list of macros not to expand
1487
1488 std::string license_info; // text to pre-pend to all generated output files
1489 };
1490
1491 #undef BOOST_WAVE_GETSTRING
1492 #undef BOOST_WAVE_OSSTREAM
1493
1494 #endif // !defined(TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED)