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(MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED)
|
Chris@16
|
12 #define MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED
|
Chris@16
|
13
|
Chris@16
|
14 #include <vector>
|
Chris@16
|
15
|
Chris@16
|
16 #include <boost/assert.hpp>
|
Chris@16
|
17 #include <boost/wave/wave_config.hpp>
|
Chris@16
|
18 #include <boost/wave/token_ids.hpp>
|
Chris@16
|
19 #include <boost/wave/cpplexer/validate_universal_char.hpp>
|
Chris@16
|
20 #include <boost/wave/util/unput_queue_iterator.hpp>
|
Chris@16
|
21
|
Chris@16
|
22 // this must occur after all of the includes and before any code appears
|
Chris@16
|
23 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
24 #include BOOST_ABI_PREFIX
|
Chris@16
|
25 #endif
|
Chris@16
|
26
|
Chris@16
|
27 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
28 namespace boost {
|
Chris@16
|
29 namespace wave {
|
Chris@16
|
30 namespace util {
|
Chris@16
|
31
|
Chris@16
|
32 namespace impl {
|
Chris@16
|
33
|
Chris@16
|
34 // escape a string literal (insert '\\' before every '\"', '?' and '\\')
|
Chris@16
|
35 template <typename StringT>
|
Chris@16
|
36 inline StringT
|
Chris@16
|
37 escape_lit(StringT const &value)
|
Chris@16
|
38 {
|
Chris@16
|
39 StringT result;
|
Chris@16
|
40 typename StringT::size_type pos = 0;
|
Chris@16
|
41 typename StringT::size_type pos1 = value.find_first_of ("\"\\?", 0);
|
Chris@16
|
42 if (StringT::npos != pos1) {
|
Chris@16
|
43 do {
|
Chris@16
|
44 result += value.substr(pos, pos1-pos)
|
Chris@16
|
45 + StringT("\\")
|
Chris@16
|
46 + StringT(1, value[pos1]);
|
Chris@16
|
47 pos1 = value.find_first_of ("\"\\?", pos = pos1+1);
|
Chris@16
|
48 } while (StringT::npos != pos1);
|
Chris@16
|
49 result += value.substr(pos);
|
Chris@16
|
50 }
|
Chris@16
|
51 else {
|
Chris@16
|
52 result = value;
|
Chris@16
|
53 }
|
Chris@16
|
54 return result;
|
Chris@16
|
55 }
|
Chris@16
|
56
|
Chris@16
|
57 // un-escape a string literal (remove '\\' just before '\\', '\"' or '?')
|
Chris@16
|
58 template <typename StringT>
|
Chris@16
|
59 inline StringT
|
Chris@16
|
60 unescape_lit(StringT const &value)
|
Chris@16
|
61 {
|
Chris@16
|
62 StringT result;
|
Chris@16
|
63 typename StringT::size_type pos = 0;
|
Chris@16
|
64 typename StringT::size_type pos1 = value.find_first_of ("\\", 0);
|
Chris@16
|
65 if (StringT::npos != pos1) {
|
Chris@16
|
66 do {
|
Chris@16
|
67 switch (value[pos1+1]) {
|
Chris@16
|
68 case '\\':
|
Chris@16
|
69 case '\"':
|
Chris@16
|
70 case '?':
|
Chris@16
|
71 result = result + value.substr(pos, pos1-pos);
|
Chris@16
|
72 pos1 = value.find_first_of ("\\", (pos = pos1+1)+1);
|
Chris@16
|
73 break;
|
Chris@16
|
74
|
Chris@16
|
75 case 'n':
|
Chris@16
|
76 result = result + value.substr(pos, pos1-pos) + "\n";
|
Chris@16
|
77 pos1 = value.find_first_of ("\\", pos = pos1+1);
|
Chris@16
|
78 ++pos;
|
Chris@16
|
79 break;
|
Chris@16
|
80
|
Chris@16
|
81 default:
|
Chris@16
|
82 result = result + value.substr(pos, pos1-pos+1);
|
Chris@16
|
83 pos1 = value.find_first_of ("\\", pos = pos1+1);
|
Chris@16
|
84 }
|
Chris@16
|
85
|
Chris@16
|
86 } while (pos1 != StringT::npos);
|
Chris@16
|
87 result = result + value.substr(pos);
|
Chris@16
|
88 }
|
Chris@16
|
89 else {
|
Chris@16
|
90 // the string doesn't contain any escaped character sequences
|
Chris@16
|
91 result = value;
|
Chris@16
|
92 }
|
Chris@16
|
93 return result;
|
Chris@16
|
94 }
|
Chris@16
|
95
|
Chris@16
|
96 // return the string representation of a token sequence
|
Chris@16
|
97 template <typename ContainerT, typename PositionT>
|
Chris@16
|
98 inline typename ContainerT::value_type::string_type
|
Chris@16
|
99 as_stringlit (ContainerT const &token_sequence, PositionT const &pos)
|
Chris@16
|
100 {
|
Chris@16
|
101 using namespace boost::wave;
|
Chris@16
|
102 typedef typename ContainerT::value_type::string_type string_type;
|
Chris@16
|
103
|
Chris@16
|
104 string_type result("\"");
|
Chris@16
|
105 bool was_whitespace = false;
|
Chris@16
|
106 typename ContainerT::const_iterator end = token_sequence.end();
|
Chris@16
|
107 for (typename ContainerT::const_iterator it = token_sequence.begin();
|
Chris@16
|
108 it != end; ++it)
|
Chris@16
|
109 {
|
Chris@16
|
110 token_id id = token_id(*it);
|
Chris@16
|
111
|
Chris@16
|
112 if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) {
|
Chris@16
|
113 if (!was_whitespace) {
|
Chris@16
|
114 // C++ standard 16.3.2.2 [cpp.stringize]
|
Chris@16
|
115 // Each occurrence of white space between the argument's
|
Chris@16
|
116 // preprocessing tokens becomes a single space character in the
|
Chris@16
|
117 // character string literal.
|
Chris@16
|
118 result += " ";
|
Chris@16
|
119 was_whitespace = true;
|
Chris@16
|
120 }
|
Chris@16
|
121 }
|
Chris@16
|
122 else if (T_STRINGLIT == id || T_CHARLIT == id) {
|
Chris@16
|
123 // string literals and character literals have to be escaped
|
Chris@16
|
124 result += impl::escape_lit((*it).get_value());
|
Chris@16
|
125 was_whitespace = false;
|
Chris@16
|
126 }
|
Chris@16
|
127 else
|
Chris@16
|
128 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
|
Chris@16
|
129 if (T_PLACEMARKER != id)
|
Chris@16
|
130 #endif
|
Chris@16
|
131 {
|
Chris@16
|
132 // now append this token to the string
|
Chris@16
|
133 result += (*it).get_value();
|
Chris@16
|
134 was_whitespace = false;
|
Chris@16
|
135 }
|
Chris@16
|
136 }
|
Chris@16
|
137 result += "\"";
|
Chris@16
|
138
|
Chris@16
|
139 // validate the resulting literal to contain no invalid universal character
|
Chris@16
|
140 // value (throws if invalid chars found)
|
Chris@16
|
141 boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(),
|
Chris@16
|
142 pos.get_column(), pos.get_file());
|
Chris@16
|
143 return result;
|
Chris@16
|
144 }
|
Chris@16
|
145
|
Chris@16
|
146 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
|
Chris@16
|
147 // return the string representation of a token sequence
|
Chris@16
|
148 template <typename ContainerT, typename PositionT>
|
Chris@16
|
149 inline typename ContainerT::value_type::string_type
|
Chris@16
|
150 as_stringlit (std::vector<ContainerT> const &arguments,
|
Chris@16
|
151 typename std::vector<ContainerT>::size_type i, PositionT const &pos)
|
Chris@16
|
152 {
|
Chris@16
|
153 using namespace boost::wave;
|
Chris@16
|
154 typedef typename ContainerT::value_type::string_type string_type;
|
Chris@16
|
155
|
Chris@16
|
156 BOOST_ASSERT(i < arguments.size());
|
Chris@16
|
157
|
Chris@16
|
158 string_type result("\"");
|
Chris@16
|
159 bool was_whitespace = false;
|
Chris@16
|
160
|
Chris@16
|
161 for (/**/; i < arguments.size(); ++i) {
|
Chris@16
|
162 // stringize all remaining arguments
|
Chris@16
|
163 typename ContainerT::const_iterator end = arguments[i].end();
|
Chris@16
|
164 for (typename ContainerT::const_iterator it = arguments[i].begin();
|
Chris@16
|
165 it != end; ++it)
|
Chris@16
|
166 {
|
Chris@16
|
167 token_id id = token_id(*it);
|
Chris@16
|
168
|
Chris@16
|
169 if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) {
|
Chris@16
|
170 if (!was_whitespace) {
|
Chris@16
|
171 // C++ standard 16.3.2.2 [cpp.stringize]
|
Chris@16
|
172 // Each occurrence of white space between the argument's
|
Chris@16
|
173 // preprocessing tokens becomes a single space character in the
|
Chris@16
|
174 // character string literal.
|
Chris@16
|
175 result += " ";
|
Chris@16
|
176 was_whitespace = true;
|
Chris@16
|
177 }
|
Chris@16
|
178 }
|
Chris@16
|
179 else if (T_STRINGLIT == id || T_CHARLIT == id) {
|
Chris@16
|
180 // string literals and character literals have to be escaped
|
Chris@16
|
181 result += impl::escape_lit((*it).get_value());
|
Chris@16
|
182 was_whitespace = false;
|
Chris@16
|
183 }
|
Chris@16
|
184 else if (T_PLACEMARKER != id) {
|
Chris@16
|
185 // now append this token to the string
|
Chris@16
|
186 result += (*it).get_value();
|
Chris@16
|
187 was_whitespace = false;
|
Chris@16
|
188 }
|
Chris@16
|
189 }
|
Chris@16
|
190
|
Chris@16
|
191 // append comma, if not last argument
|
Chris@16
|
192 if (i < arguments.size()-1) {
|
Chris@16
|
193 result += ",";
|
Chris@16
|
194 was_whitespace = false;
|
Chris@16
|
195 }
|
Chris@16
|
196 }
|
Chris@16
|
197 result += "\"";
|
Chris@16
|
198
|
Chris@16
|
199 // validate the resulting literal to contain no invalid universal character
|
Chris@16
|
200 // value (throws if invalid chars found)
|
Chris@16
|
201 boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(),
|
Chris@16
|
202 pos.get_column(), pos.get_file());
|
Chris@16
|
203 return result;
|
Chris@16
|
204 }
|
Chris@16
|
205 #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
|
Chris@16
|
206
|
Chris@16
|
207 // return the string representation of a token sequence
|
Chris@16
|
208 template <typename StringT, typename IteratorT>
|
Chris@16
|
209 inline StringT
|
Chris@16
|
210 as_string(IteratorT it, IteratorT const& end)
|
Chris@16
|
211 {
|
Chris@16
|
212 StringT result;
|
Chris@16
|
213 for (/**/; it != end; ++it)
|
Chris@16
|
214 {
|
Chris@16
|
215 result += (*it).get_value();
|
Chris@16
|
216 }
|
Chris@16
|
217 return result;
|
Chris@16
|
218 }
|
Chris@16
|
219
|
Chris@16
|
220 // return the string representation of a token sequence
|
Chris@16
|
221 template <typename ContainerT>
|
Chris@16
|
222 inline typename ContainerT::value_type::string_type
|
Chris@16
|
223 as_string (ContainerT const &token_sequence)
|
Chris@16
|
224 {
|
Chris@16
|
225 typedef typename ContainerT::value_type::string_type string_type;
|
Chris@16
|
226 return as_string<string_type>(token_sequence.begin(),
|
Chris@16
|
227 token_sequence.end());
|
Chris@16
|
228 }
|
Chris@16
|
229
|
Chris@16
|
230 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
|
Chris@16
|
231 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
232 //
|
Chris@16
|
233 // Copies all arguments beginning with the given index to the output
|
Chris@16
|
234 // sequence. The arguments are separated by commas.
|
Chris@16
|
235 //
|
Chris@16
|
236 template <typename ContainerT, typename PositionT>
|
Chris@16
|
237 void replace_ellipsis (std::vector<ContainerT> const &arguments,
|
Chris@16
|
238 typename ContainerT::size_type index,
|
Chris@16
|
239 ContainerT &expanded, PositionT const &pos)
|
Chris@16
|
240 {
|
Chris@16
|
241 using namespace cpplexer;
|
Chris@16
|
242 typedef typename ContainerT::value_type token_type;
|
Chris@16
|
243
|
Chris@16
|
244 token_type comma(T_COMMA, ",", pos);
|
Chris@16
|
245 for (/**/; index < arguments.size(); ++index) {
|
Chris@16
|
246 ContainerT const &arg = arguments[index];
|
Chris@16
|
247
|
Chris@16
|
248 std::copy(arg.begin(), arg.end(),
|
Chris@16
|
249 std::inserter(expanded, expanded.end()));
|
Chris@16
|
250
|
Chris@16
|
251 if (index < arguments.size()-1)
|
Chris@16
|
252 expanded.push_back(comma);
|
Chris@16
|
253 }
|
Chris@16
|
254 }
|
Chris@16
|
255 #endif
|
Chris@16
|
256
|
Chris@16
|
257 // Skip all whitespace characters and queue the skipped characters into the
|
Chris@16
|
258 // given container
|
Chris@16
|
259 template <typename IteratorT>
|
Chris@16
|
260 inline boost::wave::token_id
|
Chris@16
|
261 skip_whitespace(IteratorT &first, IteratorT const &last)
|
Chris@16
|
262 {
|
Chris@16
|
263 token_id id = util::impl::next_token<IteratorT>::peek(first, last, false);
|
Chris@16
|
264 if (IS_CATEGORY(id, WhiteSpaceTokenType)) {
|
Chris@16
|
265 do {
|
Chris@16
|
266 ++first;
|
Chris@16
|
267 id = util::impl::next_token<IteratorT>::peek(first, last, false);
|
Chris@16
|
268 } while (IS_CATEGORY(id, WhiteSpaceTokenType));
|
Chris@16
|
269 }
|
Chris@16
|
270 ++first;
|
Chris@16
|
271 return id;
|
Chris@16
|
272 }
|
Chris@16
|
273
|
Chris@16
|
274 template <typename IteratorT, typename ContainerT>
|
Chris@16
|
275 inline boost::wave::token_id
|
Chris@16
|
276 skip_whitespace(IteratorT &first, IteratorT const &last, ContainerT &queue)
|
Chris@16
|
277 {
|
Chris@16
|
278 queue.push_back (*first); // queue up the current token
|
Chris@16
|
279
|
Chris@16
|
280 token_id id = util::impl::next_token<IteratorT>::peek(first, last, false);
|
Chris@16
|
281 if (IS_CATEGORY(id, WhiteSpaceTokenType)) {
|
Chris@16
|
282 do {
|
Chris@16
|
283 queue.push_back(*++first); // queue up the next whitespace
|
Chris@16
|
284 id = util::impl::next_token<IteratorT>::peek(first, last, false);
|
Chris@16
|
285 } while (IS_CATEGORY(id, WhiteSpaceTokenType));
|
Chris@16
|
286 }
|
Chris@16
|
287 ++first;
|
Chris@16
|
288 return id;
|
Chris@16
|
289 }
|
Chris@16
|
290
|
Chris@16
|
291 } // namespace impl
|
Chris@16
|
292
|
Chris@16
|
293 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
294 } // namespace util
|
Chris@16
|
295 } // namespace wave
|
Chris@16
|
296 } // namespace boost
|
Chris@16
|
297
|
Chris@16
|
298 // the suffix header occurs after all of the code
|
Chris@16
|
299 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
300 #include BOOST_ABI_SUFFIX
|
Chris@16
|
301 #endif
|
Chris@16
|
302
|
Chris@16
|
303 #endif // !defined(MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED)
|