]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Boost.Wave: A Standard compliant C++ preprocessor library | |
3 | ||
4 | http://www.boost.org/ | |
5 | ||
6 | Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost | |
7 | Software License, Version 1.0. (See accompanying file | |
8 | LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
9 | =============================================================================*/ | |
10 | ||
20effc67 TL |
11 | #if !defined(BOOST_MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED) |
12 | #define BOOST_MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED | |
7c673cae FG |
13 | |
14 | #include <vector> | |
15 | ||
16 | #include <boost/assert.hpp> | |
17 | #include <boost/wave/wave_config.hpp> | |
18 | #include <boost/wave/token_ids.hpp> | |
19 | #include <boost/wave/cpplexer/validate_universal_char.hpp> | |
20 | #include <boost/wave/util/unput_queue_iterator.hpp> | |
21 | ||
22 | // this must occur after all of the includes and before any code appears | |
23 | #ifdef BOOST_HAS_ABI_HEADERS | |
24 | #include BOOST_ABI_PREFIX | |
25 | #endif | |
26 | ||
27 | /////////////////////////////////////////////////////////////////////////////// | |
28 | namespace boost { | |
29 | namespace wave { | |
30 | namespace util { | |
31 | ||
32 | namespace impl { | |
33 | ||
34 | // escape a string literal (insert '\\' before every '\"', '?' and '\\') | |
35 | template <typename StringT> | |
36 | inline StringT | |
37 | escape_lit(StringT const &value) | |
38 | { | |
39 | StringT result; | |
40 | typename StringT::size_type pos = 0; | |
41 | typename StringT::size_type pos1 = value.find_first_of ("\"\\?", 0); | |
42 | if (StringT::npos != pos1) { | |
43 | do { | |
b32b8144 FG |
44 | result += value.substr(pos, pos1-pos) |
45 | + StringT("\\") | |
7c673cae FG |
46 | + StringT(1, value[pos1]); |
47 | pos1 = value.find_first_of ("\"\\?", pos = pos1+1); | |
48 | } while (StringT::npos != pos1); | |
49 | result += value.substr(pos); | |
50 | } | |
51 | else { | |
52 | result = value; | |
53 | } | |
54 | return result; | |
55 | } | |
56 | ||
57 | // un-escape a string literal (remove '\\' just before '\\', '\"' or '?') | |
58 | template <typename StringT> | |
59 | inline StringT | |
60 | unescape_lit(StringT const &value) | |
61 | { | |
62 | StringT result; | |
63 | typename StringT::size_type pos = 0; | |
64 | typename StringT::size_type pos1 = value.find_first_of ("\\", 0); | |
65 | if (StringT::npos != pos1) { | |
66 | do { | |
67 | switch (value[pos1+1]) { | |
68 | case '\\': | |
69 | case '\"': | |
70 | case '?': | |
71 | result = result + value.substr(pos, pos1-pos); | |
72 | pos1 = value.find_first_of ("\\", (pos = pos1+1)+1); | |
73 | break; | |
74 | ||
75 | case 'n': | |
76 | result = result + value.substr(pos, pos1-pos) + "\n"; | |
77 | pos1 = value.find_first_of ("\\", pos = pos1+1); | |
78 | ++pos; | |
79 | break; | |
80 | ||
81 | default: | |
82 | result = result + value.substr(pos, pos1-pos+1); | |
83 | pos1 = value.find_first_of ("\\", pos = pos1+1); | |
84 | } | |
85 | ||
86 | } while (pos1 != StringT::npos); | |
87 | result = result + value.substr(pos); | |
88 | } | |
89 | else { | |
90 | // the string doesn't contain any escaped character sequences | |
91 | result = value; | |
92 | } | |
93 | return result; | |
94 | } | |
95 | ||
96 | // return the string representation of a token sequence | |
97 | template <typename ContainerT, typename PositionT> | |
98 | inline typename ContainerT::value_type::string_type | |
99 | as_stringlit (ContainerT const &token_sequence, PositionT const &pos) | |
100 | { | |
101 | using namespace boost::wave; | |
102 | typedef typename ContainerT::value_type::string_type string_type; | |
103 | ||
104 | string_type result("\""); | |
105 | bool was_whitespace = false; | |
106 | typename ContainerT::const_iterator end = token_sequence.end(); | |
b32b8144 FG |
107 | for (typename ContainerT::const_iterator it = token_sequence.begin(); |
108 | it != end; ++it) | |
7c673cae FG |
109 | { |
110 | token_id id = token_id(*it); | |
111 | ||
112 | if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) { | |
113 | if (!was_whitespace) { | |
114 | // C++ standard 16.3.2.2 [cpp.stringize] | |
b32b8144 FG |
115 | // Each occurrence of white space between the argument's |
116 | // preprocessing tokens becomes a single space character in the | |
7c673cae FG |
117 | // character string literal. |
118 | result += " "; | |
119 | was_whitespace = true; | |
120 | } | |
121 | } | |
122 | else if (T_STRINGLIT == id || T_CHARLIT == id) { | |
123 | // string literals and character literals have to be escaped | |
124 | result += impl::escape_lit((*it).get_value()); | |
125 | was_whitespace = false; | |
126 | } | |
b32b8144 | 127 | else |
7c673cae | 128 | #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 |
b32b8144 FG |
129 | if (T_PLACEMARKER != id) |
130 | #endif | |
7c673cae FG |
131 | { |
132 | // now append this token to the string | |
133 | result += (*it).get_value(); | |
134 | was_whitespace = false; | |
135 | } | |
136 | } | |
137 | result += "\""; | |
138 | ||
139 | // validate the resulting literal to contain no invalid universal character | |
140 | // value (throws if invalid chars found) | |
b32b8144 FG |
141 | boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(), |
142 | pos.get_column(), pos.get_file()); | |
7c673cae FG |
143 | return result; |
144 | } | |
145 | ||
146 | #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 | |
147 | // return the string representation of a token sequence | |
148 | template <typename ContainerT, typename PositionT> | |
149 | inline typename ContainerT::value_type::string_type | |
b32b8144 | 150 | as_stringlit (std::vector<ContainerT> const &arguments, |
7c673cae FG |
151 | typename std::vector<ContainerT>::size_type i, PositionT const &pos) |
152 | { | |
153 | using namespace boost::wave; | |
154 | typedef typename ContainerT::value_type::string_type string_type; | |
155 | ||
156 | BOOST_ASSERT(i < arguments.size()); | |
157 | ||
158 | string_type result("\""); | |
159 | bool was_whitespace = false; | |
160 | ||
161 | for (/**/; i < arguments.size(); ++i) { | |
162 | // stringize all remaining arguments | |
163 | typename ContainerT::const_iterator end = arguments[i].end(); | |
b32b8144 FG |
164 | for (typename ContainerT::const_iterator it = arguments[i].begin(); |
165 | it != end; ++it) | |
7c673cae FG |
166 | { |
167 | token_id id = token_id(*it); | |
b32b8144 | 168 | |
7c673cae FG |
169 | if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) { |
170 | if (!was_whitespace) { | |
171 | // C++ standard 16.3.2.2 [cpp.stringize] | |
b32b8144 FG |
172 | // Each occurrence of white space between the argument's |
173 | // preprocessing tokens becomes a single space character in the | |
7c673cae FG |
174 | // character string literal. |
175 | result += " "; | |
176 | was_whitespace = true; | |
177 | } | |
178 | } | |
179 | else if (T_STRINGLIT == id || T_CHARLIT == id) { | |
180 | // string literals and character literals have to be escaped | |
181 | result += impl::escape_lit((*it).get_value()); | |
182 | was_whitespace = false; | |
183 | } | |
184 | else if (T_PLACEMARKER != id) { | |
185 | // now append this token to the string | |
186 | result += (*it).get_value(); | |
187 | was_whitespace = false; | |
188 | } | |
189 | } | |
190 | ||
191 | // append comma, if not last argument | |
192 | if (i < arguments.size()-1) { | |
193 | result += ","; | |
194 | was_whitespace = false; | |
195 | } | |
196 | } | |
197 | result += "\""; | |
198 | ||
199 | // validate the resulting literal to contain no invalid universal character | |
200 | // value (throws if invalid chars found) | |
b32b8144 FG |
201 | boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(), |
202 | pos.get_column(), pos.get_file()); | |
7c673cae FG |
203 | return result; |
204 | } | |
205 | #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 | |
206 | ||
207 | // return the string representation of a token sequence | |
208 | template <typename StringT, typename IteratorT> | |
209 | inline StringT | |
210 | as_string(IteratorT it, IteratorT const& end) | |
211 | { | |
212 | StringT result; | |
b32b8144 | 213 | for (/**/; it != end; ++it) |
7c673cae FG |
214 | { |
215 | result += (*it).get_value(); | |
216 | } | |
217 | return result; | |
218 | } | |
219 | ||
220 | // return the string representation of a token sequence | |
221 | template <typename ContainerT> | |
222 | inline typename ContainerT::value_type::string_type | |
223 | as_string (ContainerT const &token_sequence) | |
224 | { | |
225 | typedef typename ContainerT::value_type::string_type string_type; | |
b32b8144 | 226 | return as_string<string_type>(token_sequence.begin(), |
7c673cae FG |
227 | token_sequence.end()); |
228 | } | |
229 | ||
230 | #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 | |
231 | /////////////////////////////////////////////////////////////////////////// | |
232 | // | |
b32b8144 | 233 | // Copies all arguments beginning with the given index to the output |
7c673cae FG |
234 | // sequence. The arguments are separated by commas. |
235 | // | |
236 | template <typename ContainerT, typename PositionT> | |
237 | void replace_ellipsis (std::vector<ContainerT> const &arguments, | |
b32b8144 | 238 | typename ContainerT::size_type index, |
7c673cae FG |
239 | ContainerT &expanded, PositionT const &pos) |
240 | { | |
241 | using namespace cpplexer; | |
242 | typedef typename ContainerT::value_type token_type; | |
b32b8144 | 243 | |
7c673cae FG |
244 | token_type comma(T_COMMA, ",", pos); |
245 | for (/**/; index < arguments.size(); ++index) { | |
246 | ContainerT const &arg = arguments[index]; | |
247 | ||
b32b8144 | 248 | std::copy(arg.begin(), arg.end(), |
7c673cae | 249 | std::inserter(expanded, expanded.end())); |
b32b8144 FG |
250 | |
251 | if (index < arguments.size()-1) | |
7c673cae FG |
252 | expanded.push_back(comma); |
253 | } | |
254 | } | |
20effc67 TL |
255 | |
256 | #if BOOST_WAVE_SUPPORT_VA_OPT != 0 | |
257 | /////////////////////////////////////////////////////////////////////////// | |
258 | // | |
259 | // Finds the token range inside __VA_OPT__. | |
260 | // Updates mdit to the position of the final rparen. | |
261 | // If the parenthesis do not match up, or there are none, returns false | |
262 | // and leaves mdit unchanged. | |
263 | // | |
264 | template <typename MDefIterT> | |
265 | bool find_va_opt_args ( | |
266 | MDefIterT & mdit, // VA_OPT | |
267 | MDefIterT mdend) | |
268 | { | |
269 | if ((std::distance(mdit, mdend) < 3) || | |
270 | (T_LEFTPAREN != next_token<MDefIterT>::peek(mdit, mdend))) { | |
271 | return false; | |
272 | } | |
273 | ||
274 | MDefIterT mdstart_it = mdit; | |
275 | ++mdit; // skip to lparen | |
276 | std::size_t scope = 0; | |
277 | // search for final rparen, leaving iterator there | |
278 | for (; (mdit != mdend) && !((scope == 1) && (T_RIGHTPAREN == token_id(*mdit))); | |
279 | ++mdit) { | |
280 | // count balanced parens | |
281 | if (T_RIGHTPAREN == token_id(*mdit)) { | |
282 | scope--; | |
283 | } else if (T_LEFTPAREN == token_id(*mdit)) { | |
284 | scope++; | |
285 | } | |
286 | } | |
287 | if ((mdit == mdend) && ((scope != 1) || (T_RIGHTPAREN != token_id(*mdit)))) { | |
288 | // arrived at end without matching rparen | |
289 | mdit = mdstart_it; | |
290 | return false; | |
291 | } | |
292 | ||
293 | return true; | |
294 | } | |
295 | ||
296 | #endif | |
7c673cae FG |
297 | #endif |
298 | ||
299 | // Skip all whitespace characters and queue the skipped characters into the | |
300 | // given container | |
301 | template <typename IteratorT> | |
b32b8144 | 302 | inline boost::wave::token_id |
7c673cae FG |
303 | skip_whitespace(IteratorT &first, IteratorT const &last) |
304 | { | |
305 | token_id id = util::impl::next_token<IteratorT>::peek(first, last, false); | |
306 | if (IS_CATEGORY(id, WhiteSpaceTokenType)) { | |
307 | do { | |
308 | ++first; | |
309 | id = util::impl::next_token<IteratorT>::peek(first, last, false); | |
310 | } while (IS_CATEGORY(id, WhiteSpaceTokenType)); | |
311 | } | |
312 | ++first; | |
313 | return id; | |
314 | } | |
315 | ||
316 | template <typename IteratorT, typename ContainerT> | |
b32b8144 | 317 | inline boost::wave::token_id |
7c673cae FG |
318 | skip_whitespace(IteratorT &first, IteratorT const &last, ContainerT &queue) |
319 | { | |
320 | queue.push_back (*first); // queue up the current token | |
321 | ||
322 | token_id id = util::impl::next_token<IteratorT>::peek(first, last, false); | |
323 | if (IS_CATEGORY(id, WhiteSpaceTokenType)) { | |
324 | do { | |
b32b8144 | 325 | queue.push_back(*++first); // queue up the next whitespace |
7c673cae FG |
326 | id = util::impl::next_token<IteratorT>::peek(first, last, false); |
327 | } while (IS_CATEGORY(id, WhiteSpaceTokenType)); | |
328 | } | |
329 | ++first; | |
330 | return id; | |
331 | } | |
332 | ||
20effc67 TL |
333 | // trim all whitespace from the beginning and the end of the given string |
334 | template <typename StringT> | |
335 | inline StringT | |
336 | trim_whitespace(StringT const &s) | |
337 | { | |
338 | typedef typename StringT::size_type size_type; | |
339 | ||
340 | size_type first = s.find_first_not_of(" \t\v\f"); | |
341 | if (StringT::npos == first) | |
342 | return StringT(); | |
343 | size_type last = s.find_last_not_of(" \t\v\f"); | |
344 | return s.substr(first, last-first+1); | |
345 | } | |
346 | ||
7c673cae FG |
347 | } // namespace impl |
348 | ||
349 | /////////////////////////////////////////////////////////////////////////////// | |
350 | } // namespace util | |
351 | } // namespace wave | |
352 | } // namespace boost | |
353 | ||
354 | // the suffix header occurs after all of the code | |
355 | #ifdef BOOST_HAS_ABI_HEADERS | |
356 | #include BOOST_ABI_SUFFIX | |
357 | #endif | |
358 | ||
20effc67 | 359 | #endif // !defined(BOOST_MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED) |