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