• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Boost.Wave: A Standard compliant C++ preprocessor library
3     Example demonstrating how to preprocess the token stream generated by a
4     #pragma directive
5 
6     http://www.boost.org/
7 
8     Copyright (c) 2001-2010 Hartmut Kaiser. Distributed under the Boost
9     Software License, Version 1.0. (See accompanying file
10     LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 =============================================================================*/
12 
13 #if !defined(BOOST_WAVE_SAMPLE_PREPROCESS_PRAGMA_OUTPUT_APR_03_2008_0813AM)
14 #define BOOST_WAVE_SAMPLE_PREPROCESS_PRAGMA_OUTPUT_APR_03_2008_0813AM
15 
16 template <typename String, typename Iterator>
17 inline String
as_unescaped_string(Iterator it,Iterator const & end)18 as_unescaped_string(Iterator it, Iterator const& end)
19 {
20     using namespace boost::wave;
21 
22     String result;
23     for (/**/; it != end; ++it)
24     {
25         switch (token_id(*it)) {
26         case T_STRINGLIT:
27             {
28                 String val (util::impl::unescape_lit((*it).get_value()).c_str());
29                 val.erase(val.size()-1);
30                 val.erase(0, 1);
31                 result += val;
32             }
33             break;
34 
35         default:    // just skip everything else (hey it's a sample)
36             break;
37         }
38     }
39     return result;
40 }
41 
42 // return the string representation of a token sequence
43 template <typename String, typename Container>
44 inline String
as_unescaped_string(Container const & token_sequence)45 as_unescaped_string(Container const &token_sequence)
46 {
47     return as_unescaped_string<String>(token_sequence.begin(),
48         token_sequence.end());
49 }
50 
51 ///////////////////////////////////////////////////////////////////////////////
52 //
53 //  The preprocess_pragma_output_hooks policy class is used implement a special
54 //  #pragma wave pp("some C++ code") directive allowing to insert preprocessed
55 //  code into the output sequence generated by the tool.
56 //
57 //  This policy type is used as a template parameter to the boost::wave::context<>
58 //  object.
59 //
60 ///////////////////////////////////////////////////////////////////////////////
61 class preprocess_pragma_output_hooks
62 :   public boost::wave::context_policies::default_preprocessing_hooks
63 {
64 public:
preprocess_pragma_output_hooks()65     preprocess_pragma_output_hooks() {}
66 
67     template <typename Context>
68     struct reset_language_support
69     {
reset_language_supportpreprocess_pragma_output_hooks::reset_language_support70         reset_language_support(Context& ctx)
71           : ctx_(ctx), lang_(ctx.get_language())
72         {
73             ctx.set_language(boost::wave::enable_single_line(lang_), false);
74         }
~reset_language_supportpreprocess_pragma_output_hooks::reset_language_support75         ~reset_language_support()
76         {
77             ctx_.set_language(lang_, false);
78         }
79 
80         Context& ctx_;
81         boost::wave::language_support lang_;
82     };
83 
84     ///////////////////////////////////////////////////////////////////////////
85     //
86     //  The function 'interpret_pragma' is called, whenever a #pragma command
87     //  directive is found which isn't known to the core Wave library, where
88     //  command is the value defined as the BOOST_WAVE_PRAGMA_KEYWORD constant
89     //  which defaults to "wave".
90     //
91     //  The parameter 'ctx' is a reference to the context object used for
92     //  instantiating the preprocessing iterators by the user.
93     //
94     //  The parameter 'pending' may be used to push tokens back into the input
95     //  stream, which are to be used as the replacement text for the whole
96     //  #pragma directive.
97     //
98     //  The parameter 'option' contains the name of the interpreted pragma.
99     //
100     //  The parameter 'values' holds the values of the parameter provided to
101     //  the pragma operator.
102     //
103     //  The parameter 'act_token' contains the actual #pragma token, which may
104     //  be used for error output.
105     //
106     //  If the return value is 'false', the whole #pragma directive is
107     //  interpreted as unknown and a corresponding error message is issued. A
108     //  return value of 'true' signs a successful interpretation of the given
109     //  #pragma.
110     //
111     ///////////////////////////////////////////////////////////////////////////
112     template <typename Context, typename Container>
113     bool
interpret_pragma(Context & ctx,Container & pending,typename Context::token_type const & option,Container const & values,typename Context::token_type const & act_token)114     interpret_pragma(Context& ctx, Container &pending,
115         typename Context::token_type const& option,
116         Container const& values, typename Context::token_type const& act_token)
117     {
118         typedef typename Context::token_type token_type;
119         typedef typename Context::iterator_type iterator_type;
120 
121         if (option.get_value() == "pp")  {
122         // Concatenate the string(s) passed as the options to this pragma,
123         // preprocess the result using the current context and insert the
124         // generated token sequence in place of the pragma directive into the
125         // output stream.
126 
127             try {
128             //  We're explicitly using a std::string here since the type of the
129             //  iterators passed to the ctx.begin() below must match the types
130             //  of the iterator the original context instance has been created
131             //  with.
132                 std::string s (as_unescaped_string<std::string>(values));
133                 reset_language_support<Context> lang(ctx);
134 
135                 using namespace boost::wave;
136 
137             // The expanded token sequence is stored in the 'pragma' container
138             // to ensure consistency in the output in the case of an error
139             // while preprocessing the pragma option strings.
140                 Container pragma;
141                 iterator_type end = ctx.end();
142                 for (iterator_type it = ctx.begin(s.begin(), s.end());
143                      it != end && token_id(*it) != T_EOF; ++it)
144                 {
145                     pragma.push_back(*it);
146                     it++;
147                 }
148 
149             // prepend the newly generated token sequence to the 'pending'
150             // container
151                 pending.splice(pending.begin(), pragma);
152             }
153             catch (boost::wave::preprocess_exception const& /*e*/) {
154             // the library will report an 'ill_formed_pragma_option' for us
155                 return false;
156             }
157             return true;
158         }
159 
160         // we don't know anything about this #pragma wave directive
161         return false;
162     }
163 };
164 
165 
166 #endif
167 
168