Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/tools/wave/trace_macro_expansion.hpp @ 35

Last change on this file since 35 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 32.6 KB
Line 
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
37std::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
51enum 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///////////////////////////////////////////////////////////////////////////////
63class no_pragma_system_exception :
64    public boost::wave::preprocess_exception
65{
66public:
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///////////////////////////////////////////////////////////////////////////////
121template <typename TokenT>
122class 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   
127public:
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 &macrodef, std::vector<TokenT> const &formal_args, 
167        ContainerT const &definition,
168        TokenT const &macrocall, 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 &macrodef, 
260        ContainerT const &definition, TokenT const &macrocall)
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
479protected:
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
869private:
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)
Note: See TracBrowser for help on using the repository browser.