summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/wave/samples/preprocess_pragma_output/preprocess_pragma_output.hpp
blob: 9c2415bdadbd9da1067551ffbf510a2f54f8348e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*=============================================================================
    Boost.Wave: A Standard compliant C++ preprocessor library
    Example demonstrating how to preprocess the token stream generated by a
    #pragma directive
    
    http://www.boost.org/

    Copyright (c) 2001-2010 Hartmut Kaiser. Distributed under the Boost
    Software License, Version 1.0. (See accompanying file
    LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/

#if !defined(BOOST_WAVE_SAMPLE_PREPROCESS_PRAGMA_OUTPUT_APR_03_2008_0813AM)
#define BOOST_WAVE_SAMPLE_PREPROCESS_PRAGMA_OUTPUT_APR_03_2008_0813AM

template <typename String, typename Iterator>
inline String
as_unescaped_string(Iterator it, Iterator const& end)
{
    using namespace boost::wave;
    
    String result;
    for (/**/; it != end; ++it) 
    {
        switch (token_id(*it)) {
        case T_STRINGLIT:
            {
                String val (util::impl::unescape_lit((*it).get_value()).c_str());
                val.erase(val.size()-1);
                val.erase(0, 1);
                result += val;
            }
            break;

        default:    // just skip everything else (hey it's a sample)
            break;
        }
    }
    return result;
}

// return the string representation of a token sequence
template <typename String, typename Container>
inline String
as_unescaped_string(Container const &token_sequence)
{
    return as_unescaped_string<String>(token_sequence.begin(), 
        token_sequence.end());
}

///////////////////////////////////////////////////////////////////////////////
//  
//  The preprocess_pragma_output_hooks policy class is used implement a special
//  #pragma wave pp("some C++ code") directive allowing to insert preprocessed
//  code into the output sequence generated by the tool.
//
//  This policy type is used as a template parameter to the boost::wave::context<>
//  object.
//
///////////////////////////////////////////////////////////////////////////////
class preprocess_pragma_output_hooks
:   public boost::wave::context_policies::default_preprocessing_hooks
{
public:
    preprocess_pragma_output_hooks() {}
    
    template <typename Context>
    struct reset_language_support
    {
        reset_language_support(Context& ctx)
          : ctx_(ctx), lang_(ctx.get_language())
        {
            ctx.set_language(boost::wave::enable_single_line(lang_), false);
        }
        ~reset_language_support()
        {
            ctx_.set_language(lang_, false);
        }
        
        Context& ctx_;
        boost::wave::language_support lang_;
    };
    
    ///////////////////////////////////////////////////////////////////////////
    //  
    //  The function 'interpret_pragma' is called, whenever a #pragma command 
    //  directive is found which isn't known to the core Wave library, where
    //  command is the value defined as the BOOST_WAVE_PRAGMA_KEYWORD constant
    //  which defaults to "wave".
    //
    //  The parameter 'ctx' is a reference to the context object used for 
    //  instantiating the preprocessing iterators by the user.
    //
    //  The parameter 'pending' may be used to push tokens back into the input 
    //  stream, which are to be used as the replacement text for the whole 
    //  #pragma directive.
    //
    //  The parameter 'option' contains the name of the interpreted pragma.
    //
    //  The parameter 'values' holds the values of the parameter provided to 
    //  the pragma operator.
    //
    //  The parameter 'act_token' contains the actual #pragma token, which may 
    //  be used for error output.
    //
    //  If the return value is 'false', the whole #pragma directive is 
    //  interpreted as unknown and a corresponding error message is issued. A
    //  return value of 'true' signs a successful interpretation of the given 
    //  #pragma.
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename Context, typename Container>
    bool 
    interpret_pragma(Context& ctx, Container &pending, 
        typename Context::token_type const& option, 
        Container const& values, typename Context::token_type const& act_token)
    {
        typedef typename Context::token_type token_type;
        typedef typename Context::iterator_type iterator_type;

        if (option.get_value() == "pp")  {
        // Concatenate the string(s) passed as the options to this pragma, 
        // preprocess the result using the current context and insert the 
        // generated token sequence in place of the pragma directive into the 
        // output stream.
         
            try {
            //  We're explicitly using a std::string here since the type of the
            //  iterators passed to the ctx.begin() below must match the types
            //  of the iterator the original context instance has been created 
            //  with.
                std::string s (as_unescaped_string<std::string>(values)); 
                reset_language_support<Context> lang(ctx);
                
                using namespace boost::wave;

            // The expanded token sequence is stored in the 'pragma' container
            // to ensure consistency in the output in the case of an error 
            // while preprocessing the pragma option strings.
                Container pragma;
                iterator_type end = ctx.end();
                for (iterator_type it = ctx.begin(s.begin(), s.end()); 
                     it != end && token_id(*it) != T_EOF; ++it) 
                {
                    pragma.push_back(*it);
                    it++;
                }

            // prepend the newly generated token sequence to the 'pending' 
            // container
                pending.splice(pending.begin(), pragma);
            }
            catch (boost::wave::preprocess_exception const& /*e*/) {
            // the library will report an 'ill_formed_pragma_option' for us
                return false;
            }
            return true;
        }

        // we don't know anything about this #pragma wave directive
        return false;   
    }
};


#endif