Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/tools/wave/trace_macro_expansion.hpp @ 12

Last change on this file since 12 was 12, checked in by landauf, 18 years ago

added boost

File size: 19.5 KB
Line 
1/*=============================================================================
2    Boost.Wave: A Standard compliant C++ preprocessor library
3    http://www.boost.org/
4
5    Copyright (c) 2001-2005 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 <ostream>
15#include <string>
16
17#include <boost/assert.hpp>
18#include <boost/config.hpp>
19
20#include <boost/wave/token_ids.hpp>
21#include <boost/wave/util/macro_helpers.hpp>
22#include <boost/wave/preprocessing_hooks.hpp>
23#include <boost/wave/language_support.hpp>
24
25#include "stop_watch.hpp"
26
27#ifdef BOOST_NO_STRINGSTREAM
28#include <strstream>
29#define BOOST_WAVE_OSSTREAM std::ostrstream
30std::string BOOST_WAVE_GETSTRING(std::ostrstream& ss)
31{
32    ss << ends;
33    std::string rval = ss.str();
34    ss.freeze(false);
35    return rval;
36}
37#else
38#include <sstream>
39#define BOOST_WAVE_GETSTRING(ss) ss.str()
40#define BOOST_WAVE_OSSTREAM std::ostringstream
41#endif
42
43//  trace_flags:  enable single tracing functionality
44enum trace_flags {
45    trace_nothing = 0,      // disable tracing
46    trace_macros = 1,       // enable macro tracing
47    trace_includes = 2      // enable include file tracing
48};
49
50///////////////////////////////////////////////////////////////////////////////
51// 
52//  The trace_macro_expansion policy is used to trace the macro expansion of
53//  macros whenever it is requested from inside the input stream to preprocess
54//  through the '#pragma wave_option(trace: enable)' directive. The macro
55//  tracing is disabled with the help of a '#pragma wave_option(trace: disable)'
56//  directive.
57//
58//  This policy type is used as a template parameter to the boost::wave::context<>
59//  object.
60//
61///////////////////////////////////////////////////////////////////////////////
62class trace_macro_expansion
63:   public boost::wave::context_policies::default_preprocessing_hooks
64{
65public:
66    trace_macro_expansion(std::ostream &tracestrm_, std::ostream &includestrm_, 
67            trace_flags flags_)
68    :   tracestrm(tracestrm_), includestrm(includestrm_), level(0), 
69        flags(flags_), logging_flags(trace_nothing)
70    {
71    }
72    ~trace_macro_expansion()
73    {
74    }
75   
76    ///////////////////////////////////////////////////////////////////////////
77    // 
78    //  The function 'expanding_function_like_macro' is called, whenever a
79    //  function-like macro is to be expanded.
80    //
81    //  The 'macrodef' parameter marks the position, where the macro to expand
82    //  is defined.
83    //  The 'formal_args' parameter holds the formal arguments used during the
84    //  definition of the macro.
85    //  The 'definition' parameter holds the macro definition for the macro to
86    //  trace.
87    //
88    //  The 'macrocall' parameter marks the position, where this macro invoked.
89    //  The 'arguments' parameter holds the macro arguments used during the
90    //  invocation of the macro
91    //
92    ///////////////////////////////////////////////////////////////////////////
93    template <typename TokenT, typename ContainerT>
94    void expanding_function_like_macro(
95        TokenT const &macrodef, std::vector<TokenT> const &formal_args, 
96        ContainerT const &definition,
97        TokenT const &macrocall, std::vector<ContainerT> const &arguments) 
98    {
99        if (!enabled_macro_tracing()) return;
100       
101        if (0 == get_level()) {
102        // output header line
103        BOOST_WAVE_OSSTREAM stream;
104
105            stream
106                << macrocall.get_position() << ": "
107                << macrocall.get_value() << "(";
108
109        // argument list
110            for (typename ContainerT::size_type i = 0; i < arguments.size(); ++i) {
111                stream << boost::wave::util::impl::as_string(arguments[i]);
112                if (i < arguments.size()-1)
113                    stream << ", ";
114            }
115            stream << ")" << std::endl; 
116            output(BOOST_WAVE_GETSTRING(stream));
117            increment_level();
118        }       
119       
120    // output definition reference
121        {
122        BOOST_WAVE_OSSTREAM stream;
123
124            stream
125                << macrodef.get_position() << ": see macro definition: "
126                << macrodef.get_value() << "(";
127
128        // formal argument list
129            for (typename std::vector<TokenT>::size_type i = 0; 
130                i < formal_args.size(); ++i) 
131            {
132                stream << formal_args[i].get_value();
133                if (i < formal_args.size()-1)
134                    stream << ", ";
135            }
136            stream << ")" << std::endl; 
137            output(BOOST_WAVE_GETSTRING(stream));
138        }
139
140        if (formal_args.size() > 0) {
141        // map formal and real arguments
142            open_trace_body("invoked with\n");
143            for (typename std::vector<TokenT>::size_type j = 0; 
144                j < formal_args.size(); ++j) 
145            {
146                using namespace boost::wave;
147
148                BOOST_WAVE_OSSTREAM stream;
149                stream << formal_args[j].get_value() << " = ";
150#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
151                if (T_ELLIPSIS == token_id(formal_args[j])) {
152                // ellipsis
153                    for (typename ContainerT::size_type k = j; 
154                        k < arguments.size(); ++k) 
155                    {
156                        stream << boost::wave::util::impl::as_string(arguments[k]);
157                        if (k < arguments.size()-1)
158                            stream << ", ";
159                    }
160                } 
161                else 
162#endif
163                {
164                    stream << boost::wave::util::impl::as_string(arguments[j]);
165                }
166                stream << std::endl;
167                output(BOOST_WAVE_GETSTRING(stream));
168            }
169            close_trace_body();
170        }
171        open_trace_body();
172    }
173
174    ///////////////////////////////////////////////////////////////////////////
175    // 
176    //  The function 'expanding_object_like_macro' is called, whenever a
177    //  object-like macro is to be expanded .
178    //
179    //  The 'macrodef' parameter marks the position, where the macro to expand
180    //  is defined.
181    //  The 'definition' parameter holds the macro definition for the macro to
182    //  trace.
183    //
184    //  The 'macrocall' parameter marks the position, where this macro invoked.
185    //
186    ///////////////////////////////////////////////////////////////////////////
187    template <typename TokenT, typename ContainerT>
188    void expanding_object_like_macro(TokenT const &macrodef, 
189        ContainerT const &definition, TokenT const &macrocall)
190    {
191        if (!enabled_macro_tracing()) return;
192       
193        if (0 == get_level()) {
194        // output header line
195        BOOST_WAVE_OSSTREAM stream;
196
197            stream
198                << macrocall.get_position() << ": "
199                << macrocall.get_value() << std::endl;
200            output(BOOST_WAVE_GETSTRING(stream));
201            increment_level();
202        }
203       
204    // output definition reference
205        {
206        BOOST_WAVE_OSSTREAM stream;
207
208            stream
209                << macrodef.get_position() << ": see macro definition: "
210                << macrodef.get_value() << std::endl;
211            output(BOOST_WAVE_GETSTRING(stream));
212        }
213        open_trace_body();
214    }
215   
216    ///////////////////////////////////////////////////////////////////////////
217    // 
218    //  The function 'expanded_macro' is called, whenever the expansion of a
219    //  macro is finished but before the rescanning process starts.
220    //
221    //  The parameter 'result' contains the token sequence generated as the
222    //  result of the macro expansion.
223    //
224    ///////////////////////////////////////////////////////////////////////////
225    template <typename ContainerT>
226    void expanded_macro(ContainerT const &result)
227    {
228        if (!enabled_macro_tracing()) return;
229       
230        BOOST_WAVE_OSSTREAM stream;
231        stream << boost::wave::util::impl::as_string(result) << std::endl;
232        output(BOOST_WAVE_GETSTRING(stream));
233
234        open_trace_body("rescanning\n");
235    }
236
237    ///////////////////////////////////////////////////////////////////////////
238    // 
239    //  The function 'rescanned_macro' is called, whenever the rescanning of a
240    //  macro is finished.
241    //
242    //  The parameter 'result' contains the token sequence generated as the
243    //  result of the rescanning.
244    //
245    ///////////////////////////////////////////////////////////////////////////
246    template <typename ContainerT>
247    void rescanned_macro(ContainerT const &result)
248    {
249        if (!enabled_macro_tracing() || get_level() == 0) 
250            return;
251
252        BOOST_WAVE_OSSTREAM stream;
253        stream << boost::wave::util::impl::as_string(result) << std::endl;
254        output(BOOST_WAVE_GETSTRING(stream));
255        close_trace_body();
256        close_trace_body();
257       
258        if (1 == get_level())
259            decrement_level();
260    }
261
262    ///////////////////////////////////////////////////////////////////////////
263    // 
264    //  The function 'interpret_pragma' is called, whenever a #pragma wave
265    //  directive is found, which isn't known to the core Wave library.
266    //
267    //  The parameter 'ctx' is a reference to the context object used for
268    //  instantiating the preprocessing iterators by the user.
269    //
270    //  The parameter 'pending' may be used to push tokens back into the input
271    //  stream, which are to be used as the replacement text for the whole
272    //  #pragma wave() directive.
273    //
274    //  The parameter 'option' contains the name of the interpreted pragma.
275    //
276    //  The parameter 'values' holds the values of the parameter provided to
277    //  the pragma operator.
278    //
279    //  The parameter 'act_token' contains the actual #pragma token, which may
280    //  be used for error output.
281    //
282    //  If the return value is 'false', the whole #pragma directive is
283    //  interpreted as unknown and a corresponding error message is issued. A
284    //  return value of 'true' signs a successful interpretation of the given
285    //  #pragma.
286    //
287    ///////////////////////////////////////////////////////////////////////////
288    template <typename ContextT, typename ContainerT>
289    bool 
290    interpret_pragma(ContextT const &ctx, ContainerT &pending, 
291        typename ContextT::token_type const &option, ContainerT const &values, 
292        typename ContextT::token_type const &act_token)
293    {
294        typedef typename ContextT::token_type token_type;
295       
296        if (option.get_value() == "timer") {
297        // #pragma wave timer(value)
298            if (0 == values.size()) {
299            // no value means '1'
300                using namespace boost::wave;
301                timer(token_type(T_INTLIT, "1", act_token.get_position()));
302            }
303            else {
304                timer(values.front());
305            }
306            return true;
307        }
308        else if (option.get_value() == "trace") {
309        // enable/disable tracing option
310            return interpret_pragma_trace(ctx, values, act_token);
311        }
312        else if (option.get_value() == "system") {
313        // try to spawn the given argument as a system command and return the
314        // std::cout of this process as the replacement of this _Pragma
315            return interpret_pragma_system(ctx, pending, values, act_token);
316        }
317        if (option.get_value() == "stop") {
318        // stop the execution and output the argument
319            BOOST_WAVE_THROW(preprocess_exception, error_directive,
320                boost::wave::util::impl::as_string(values).c_str(), 
321                act_token.get_position());
322        }
323        return false;
324    }
325       
326    ///////////////////////////////////////////////////////////////////////////
327    // 
328    //  The function 'opened_include_file' is called, whenever a file referred
329    //  by an #include directive was successfully located and opened.
330    //
331    //  The parameter 'filename' contains the file system path of the
332    //  opened file (this is relative to the directory of the currently
333    //  processed file or a absolute path depending on the paths given as the
334    //  include search paths).
335    //
336    //  The include_depth parameter contains the current include file depth.
337    //
338    //  The is_system_include parameter denotes, whether the given file was
339    //  found as a result of a #include <...> directive.
340    // 
341    ///////////////////////////////////////////////////////////////////////////
342    void 
343    opened_include_file(std::string const &relname, std::string const &absname, 
344        std::size_t include_depth, bool is_system_include) 
345    {
346        if (enabled_include_tracing()) {
347            // print indented filename
348            for (std::size_t i = 0; i < include_depth; ++i)
349                includestrm << " ";
350               
351            if (is_system_include)
352                includestrm << "<" << relname << "> (" << absname << ")";
353            else
354                includestrm << "\"" << relname << "\" (" << absname << ")";
355
356            includestrm << std::endl;
357        }
358    }
359
360protected:
361    //  Interpret the different Wave specific pragma directives/operators
362    template <typename ContextT, typename ContainerT>
363    bool 
364    interpret_pragma_trace(ContextT const &/*ctx*/, ContainerT const &values, 
365        typename ContextT::token_type const &act_token)
366    {
367        typedef typename ContextT::token_type token_type;
368        typedef typename token_type::string_type string_type;
369
370    bool valid_option = false;
371
372        if (1 == values.size()) {
373        token_type const &value = values.front();
374       
375            if (value.get_value() == "enable" ||
376                value.get_value() == "on" || 
377                value.get_value() == "1") 
378            {
379            // #pragma wave trace(enable)
380                enable_tracing(static_cast<trace_flags>(
381                    tracing_enabled() | trace_macros));
382                valid_option = true;
383            }
384            else if (value.get_value() == "disable" ||
385                value.get_value() == "off" || 
386                value.get_value() == "0") 
387            {
388            // #pragma wave trace(disable)
389                enable_tracing(static_cast<trace_flags>(
390                    tracing_enabled() & ~trace_macros));
391                valid_option = true;
392            }
393        }
394        if (!valid_option) {
395        // unknown option value
396        string_type option_str ("trace");
397
398            if (values.size() > 0) {
399                option_str += "(";
400                option_str += boost::wave::util::impl::as_string(values);
401                option_str += ")";
402            }
403            BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option,
404                option_str.c_str(), act_token.get_position());
405        }
406        return true;
407    }
408
409    template <typename ContextT, typename ContainerT>
410    bool
411    interpret_pragma_system(ContextT const &ctx, ContainerT &pending, 
412        ContainerT const &values, 
413        typename ContextT::token_type const &act_token)
414    {
415        typedef typename ContextT::token_type token_type;
416        typedef typename token_type::string_type string_type;
417
418        if (0 == values.size()) return false;   // ill_formed_pragma_option
419       
420    string_type stdout_file(std::tmpnam(0));
421    string_type stderr_file(std::tmpnam(0));
422    string_type system_str(boost::wave::util::impl::as_string(values));
423    string_type native_cmd(system_str);
424
425        system_str += " >" + stdout_file + " 2>" + stderr_file;
426        if (0 != std::system(system_str.c_str())) {
427        // unable to spawn the command
428        string_type error_str("unable to spawn command: ");
429       
430            error_str += native_cmd;
431            BOOST_WAVE_THROW(preprocess_exception, ill_formed_pragma_option,
432                error_str.c_str(), act_token.get_position());
433        }
434       
435    // rescan the content of the stdout_file and insert it as the
436    // _Pragma replacement
437        typedef typename ContextT::lexer_type lexer_type;
438        typedef typename ContextT::input_policy_type input_policy_type;
439        typedef boost::wave::iteration_context<lexer_type, input_policy_type> 
440            iteration_context_type;
441
442    iteration_context_type iter_ctx(stdout_file.c_str(), 
443        act_token.get_position(), ctx.get_language());
444    ContainerT pragma;
445
446        for (/**/; iter_ctx.first != iter_ctx.last; ++iter_ctx.first) 
447            pragma.push_back(*iter_ctx.first);
448
449    // prepend the newly generated token sequence to the 'pending' container
450        pending.splice(pending.begin(), pragma);
451
452    // erase the created tempfiles
453        std::remove(stdout_file.c_str());
454        std::remove(stderr_file.c_str());
455        return true;
456    }
457
458    //  The function enable_tracing is called, whenever the status of the
459    //  tracing was changed.
460    //  The parameter 'enable' is to be used as the new tracing status.
461    void enable_tracing(trace_flags flags) 
462        { logging_flags = flags; }
463
464    //  The function tracing_enabled should return the current tracing status.
465    trace_flags tracing_enabled() 
466        { return logging_flags; }
467
468    //  Helper functions for generating the trace output
469    void open_trace_body(char const *label = 0)
470    {
471        if (label)
472            output(label);
473        output("[\n");
474        increment_level();
475    }
476    void close_trace_body()
477    {
478        if (get_level() > 0) {
479            decrement_level();
480            output("]\n");
481            tracestrm << std::flush;      // flush the stream buffer
482        }
483    }
484
485    template <typename StringT>
486    void output(StringT const &outstr) const
487    {
488        indent(get_level());
489        tracestrm << outstr;          // output the given string
490    }
491
492    void indent(int level) const
493    {
494        for (int i = 0; i < level; ++i)
495            tracestrm << "  ";        // indent
496    }
497
498    int increment_level() { return ++level; }
499    int decrement_level() { BOOST_ASSERT(level > 0); return --level; }
500    int get_level() const { return level; }
501   
502    bool enabled_macro_tracing() const 
503    { 
504        return (flags & trace_macros) && (logging_flags & trace_macros); 
505    }
506    bool enabled_include_tracing() const 
507    { 
508        return (flags & trace_includes); 
509    }
510   
511    template <typename TokenT>
512    void timer(TokenT const &value)
513    {
514        if (value.get_value() == "0" || value.get_value() == "restart") {
515        // restart the timer
516            elapsed_time.restart();
517        }
518        else if (value.get_value() == "1") {
519        // print out the current elapsed time
520            std::cerr
521                << value.get_position() << ": " 
522                << elapsed_time.format_elapsed_time()
523                << std::endl;
524        }
525        else if (value.get_value() == "suspend") {
526        // suspend the timer
527            elapsed_time.suspend();
528        }
529        else if (value.get_value() == "resume") {
530        // resume the timer
531            elapsed_time.resume();
532        }
533    }
534
535private:
536    std::ostream &tracestrm;        // trace output stream
537    std::ostream &includestrm;      // included list output stream
538    int level;                      // indentation level
539    trace_flags flags;              // enabled globally
540    trace_flags logging_flags;      // enabled by a #pragma
541   
542    stop_watch elapsed_time;        // trace timings
543};
544
545#undef BOOST_WAVE_GETSTRING
546#undef BOOST_WAVE_OSSTREAM
547
548#endif // !defined(TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED)
Note: See TracBrowser for help on using the repository browser.