Chris@16
|
1 /*=============================================================================
|
Chris@16
|
2 Boost.Wave: A Standard compliant C++ preprocessor library
|
Chris@16
|
3
|
Chris@16
|
4 http://www.boost.org/
|
Chris@16
|
5
|
Chris@16
|
6 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
|
Chris@16
|
7 Software License, Version 1.0. (See accompanying file
|
Chris@16
|
8 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 =============================================================================*/
|
Chris@16
|
10
|
Chris@16
|
11 #if !defined(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED)
|
Chris@16
|
12 #define INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED
|
Chris@16
|
13
|
Chris@16
|
14 #include <string>
|
Chris@16
|
15 #include <list>
|
Chris@16
|
16
|
Chris@16
|
17 #include <boost/spirit/include/classic_core.hpp>
|
Chris@16
|
18 #include <boost/spirit/include/classic_assign_actor.hpp>
|
Chris@16
|
19 #include <boost/spirit/include/classic_push_back_actor.hpp>
|
Chris@16
|
20 #include <boost/spirit/include/classic_confix.hpp>
|
Chris@16
|
21
|
Chris@16
|
22 #include <boost/wave/wave_config.hpp>
|
Chris@16
|
23
|
Chris@16
|
24 #include <boost/wave/util/pattern_parser.hpp>
|
Chris@16
|
25 #include <boost/wave/util/macro_helpers.hpp>
|
Chris@16
|
26
|
Chris@16
|
27 #include <boost/wave/token_ids.hpp>
|
Chris@16
|
28 #include <boost/wave/cpp_exceptions.hpp>
|
Chris@16
|
29 #include <boost/wave/cpp_iteration_context.hpp>
|
Chris@16
|
30 #include <boost/wave/language_support.hpp>
|
Chris@16
|
31
|
Chris@16
|
32 #if !defined(spirit_append_actor)
|
Chris@16
|
33 #define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor)
|
Chris@16
|
34 #define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor)
|
Chris@16
|
35 #endif // !defined(spirit_append_actor)
|
Chris@16
|
36
|
Chris@16
|
37 // this must occur after all of the includes and before any code appears
|
Chris@16
|
38 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
39 #include BOOST_ABI_PREFIX
|
Chris@16
|
40 #endif
|
Chris@16
|
41
|
Chris@16
|
42 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
43 namespace boost {
|
Chris@16
|
44 namespace wave {
|
Chris@16
|
45 namespace util {
|
Chris@16
|
46
|
Chris@16
|
47 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
48 //
|
Chris@16
|
49 // The function interpret_pragma interprets the given token sequence as the
|
Chris@16
|
50 // body of a #pragma directive (or parameter to the _Pragma operator) and
|
Chris@16
|
51 // executes the actions associated with recognized Wave specific options.
|
Chris@16
|
52 //
|
Chris@16
|
53 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
54 template <typename ContextT, typename IteratorT, typename ContainerT>
|
Chris@16
|
55 inline bool
|
Chris@16
|
56 interpret_pragma(ContextT &ctx, typename ContextT::token_type const &act_token,
|
Chris@16
|
57 IteratorT it, IteratorT const &end, ContainerT &pending)
|
Chris@16
|
58 {
|
Chris@16
|
59 typedef typename ContextT::token_type token_type;
|
Chris@16
|
60 typedef typename token_type::string_type string_type;
|
Chris@16
|
61
|
Chris@16
|
62 using namespace cpplexer;
|
Chris@16
|
63 if (T_IDENTIFIER == token_id(*it)) {
|
Chris@16
|
64 // check for pragma wave ...
|
Chris@16
|
65 if ((*it).get_value() == BOOST_WAVE_PRAGMA_KEYWORD)
|
Chris@16
|
66 {
|
Chris@16
|
67 // this is a wave specific option, it should have the form:
|
Chris@16
|
68 //
|
Chris@16
|
69 // #pragma command option(value)
|
Chris@16
|
70 //
|
Chris@16
|
71 // where
|
Chris@16
|
72 // 'command' is the value of the preprocessor constant
|
Chris@16
|
73 // BOOST_WAVE_PRAGMA_KEYWORD (defaults to "wave") and
|
Chris@16
|
74 // '(value)' is required only for some pragma directives (this is
|
Chris@16
|
75 // optional)
|
Chris@16
|
76 //
|
Chris@16
|
77 // All recognized #pragma operators are forwarded to the supplied
|
Chris@16
|
78 // preprocessing hook.
|
Chris@16
|
79 using namespace boost::spirit::classic;
|
Chris@16
|
80 token_type option;
|
Chris@16
|
81 ContainerT values;
|
Chris@16
|
82
|
Chris@16
|
83 if (!parse (++it, end,
|
Chris@16
|
84 ( ch_p(T_IDENTIFIER)
|
Chris@16
|
85 [
|
Chris@16
|
86 spirit_assign_actor(option)
|
Chris@16
|
87 ]
|
Chris@16
|
88 | pattern_p(KeywordTokenType,
|
Chris@16
|
89 TokenTypeMask|PPTokenFlag)
|
Chris@16
|
90 [
|
Chris@16
|
91 spirit_assign_actor(option)
|
Chris@16
|
92 ]
|
Chris@16
|
93 | pattern_p(OperatorTokenType|AltExtTokenType,
|
Chris@16
|
94 ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
|
Chris@16
|
95 [
|
Chris@16
|
96 spirit_assign_actor(option)
|
Chris@16
|
97 ]
|
Chris@16
|
98 | pattern_p(BoolLiteralTokenType,
|
Chris@16
|
99 TokenTypeMask|PPTokenFlag)
|
Chris@16
|
100 [
|
Chris@16
|
101 spirit_assign_actor(option)
|
Chris@16
|
102 ]
|
Chris@16
|
103 )
|
Chris@16
|
104 >> !comment_nest_p(
|
Chris@16
|
105 ch_p(T_LEFTPAREN),
|
Chris@16
|
106 ch_p(T_RIGHTPAREN)
|
Chris@16
|
107 )[spirit_assign_actor(values)],
|
Chris@16
|
108 pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag)).hit)
|
Chris@16
|
109 {
|
Chris@16
|
110 typename ContextT::string_type msg(
|
Chris@16
|
111 impl::as_string<string_type>(it, end));
|
Chris@16
|
112 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
|
Chris@16
|
113 ill_formed_pragma_option,
|
Chris@16
|
114 msg.c_str(), act_token.get_position());
|
Chris@16
|
115 return false;
|
Chris@16
|
116 }
|
Chris@16
|
117
|
Chris@16
|
118 // remove the falsely matched surrounding parenthesis's
|
Chris@16
|
119 if (values.size() >= 2) {
|
Chris@16
|
120 BOOST_ASSERT(T_LEFTPAREN == values.front() && T_RIGHTPAREN == values.back());
|
Chris@16
|
121 values.erase(values.begin());
|
Chris@16
|
122 typename ContainerT::reverse_iterator rit = values.rbegin();
|
Chris@16
|
123 values.erase((++rit).base());
|
Chris@16
|
124 }
|
Chris@16
|
125
|
Chris@16
|
126 // decode the option (call the context_policy hook)
|
Chris@16
|
127 if (!ctx.get_hooks().interpret_pragma(
|
Chris@16
|
128 ctx.derived(), pending, option, values, act_token))
|
Chris@16
|
129 {
|
Chris@16
|
130 // unknown #pragma option
|
Chris@16
|
131 string_type option_str ((*it).get_value());
|
Chris@16
|
132
|
Chris@16
|
133 option_str += option.get_value();
|
Chris@16
|
134 if (values.size() > 0) {
|
Chris@16
|
135 option_str += "(";
|
Chris@16
|
136 option_str += impl::as_string(values);
|
Chris@16
|
137 option_str += ")";
|
Chris@16
|
138 }
|
Chris@16
|
139 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
|
Chris@16
|
140 ill_formed_pragma_option,
|
Chris@16
|
141 option_str.c_str(), act_token.get_position());
|
Chris@16
|
142 return false;
|
Chris@16
|
143 }
|
Chris@16
|
144 return true;
|
Chris@16
|
145 }
|
Chris@16
|
146 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
|
Chris@16
|
147 else if ((*it).get_value() == "once") {
|
Chris@16
|
148 // #pragma once
|
Chris@16
|
149 return ctx.add_pragma_once_header(act_token, ctx.get_current_filename());
|
Chris@16
|
150 }
|
Chris@16
|
151 #endif
|
Chris@16
|
152 #if BOOST_WAVE_SUPPORT_PRAGMA_MESSAGE != 0
|
Chris@16
|
153 else if ((*it).get_value() == "message") {
|
Chris@16
|
154 // #pragma message(...) or #pragma message ...
|
Chris@16
|
155 using namespace boost::spirit::classic;
|
Chris@16
|
156 ContainerT values;
|
Chris@16
|
157
|
Chris@16
|
158 if (!parse (++it, end,
|
Chris@16
|
159 ( ( ch_p(T_LEFTPAREN)
|
Chris@16
|
160 >> lexeme_d[
|
Chris@16
|
161 *(anychar_p[spirit_append_actor(values)] - ch_p(T_RIGHTPAREN))
|
Chris@16
|
162 ]
|
Chris@16
|
163 >> ch_p(T_RIGHTPAREN)
|
Chris@16
|
164 )
|
Chris@16
|
165 | lexeme_d[
|
Chris@16
|
166 *(anychar_p[spirit_append_actor(values)] - ch_p(T_NEWLINE))
|
Chris@16
|
167 ]
|
Chris@16
|
168 ),
|
Chris@16
|
169 pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag)
|
Chris@16
|
170 ).hit
|
Chris@16
|
171 )
|
Chris@16
|
172 {
|
Chris@16
|
173 typename ContextT::string_type msg(
|
Chris@16
|
174 impl::as_string<string_type>(it, end));
|
Chris@16
|
175 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
|
Chris@16
|
176 ill_formed_pragma_message,
|
Chris@16
|
177 msg.c_str(), act_token.get_position());
|
Chris@16
|
178 return false;
|
Chris@16
|
179 }
|
Chris@16
|
180
|
Chris@16
|
181 // remove the falsely matched closing parenthesis/newline
|
Chris@16
|
182 if (values.size() > 0) {
|
Chris@16
|
183 BOOST_ASSERT(T_RIGHTPAREN == values.back() || T_NEWLINE == values.back());
|
Chris@16
|
184 typename ContainerT::reverse_iterator rit = values.rbegin();
|
Chris@16
|
185 values.erase((++rit).base());
|
Chris@16
|
186 }
|
Chris@16
|
187
|
Chris@16
|
188 // output the message itself
|
Chris@16
|
189 typename ContextT::string_type msg(impl::as_string(values));
|
Chris@16
|
190 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
|
Chris@16
|
191 pragma_message_directive,
|
Chris@16
|
192 msg.c_str(), act_token.get_position());
|
Chris@16
|
193 return false;
|
Chris@16
|
194 }
|
Chris@16
|
195 #endif
|
Chris@16
|
196 }
|
Chris@16
|
197 return false;
|
Chris@16
|
198 }
|
Chris@16
|
199
|
Chris@16
|
200 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
201 } // namespace util
|
Chris@16
|
202 } // namespace wave
|
Chris@16
|
203 } // namespace boost
|
Chris@16
|
204
|
Chris@16
|
205 // the suffix header occurs after all of the code
|
Chris@16
|
206 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
207 #include BOOST_ABI_SUFFIX
|
Chris@16
|
208 #endif
|
Chris@16
|
209
|
Chris@16
|
210 #endif // !defined(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED)
|