Mercurial > projects > qtd
comparison generator/parser/rpp/pp-macro-expander.h @ 1:e78566595089
initial import
author | mandel |
---|---|
date | Mon, 11 May 2009 16:01:50 +0000 |
parents | |
children | 09a0f1d048f2 |
comparison
equal
deleted
inserted
replaced
0:36fb74dc547d | 1:e78566595089 |
---|---|
1 /**************************************************************************** | |
2 ** | |
3 ** Copyright (C) 1992-2008 Nokia. All rights reserved. | |
4 ** Copyright 2005 Roberto Raggi <roberto@kdevelop.org> | |
5 ** | |
6 ** This file is part of Qt Jambi. | |
7 ** | |
8 ** * Commercial Usage | |
9 * Licensees holding valid Qt Commercial licenses may use this file in | |
10 * accordance with the Qt Commercial License Agreement provided with the | |
11 * Software or, alternatively, in accordance with the terms contained in | |
12 * a written agreement between you and Nokia. | |
13 * | |
14 * | |
15 * GNU General Public License Usage | |
16 * Alternatively, this file may be used under the terms of the GNU | |
17 * General Public License versions 2.0 or 3.0 as published by the Free | |
18 * Software Foundation and appearing in the file LICENSE.GPL included in | |
19 * the packaging of this file. Please review the following information | |
20 * to ensure GNU General Public Licensing requirements will be met: | |
21 * http://www.fsf.org/licensing/licenses/info/GPLv2.html and | |
22 * http://www.gnu.org/copyleft/gpl.html. In addition, as a special | |
23 * exception, Nokia gives you certain additional rights. These rights | |
24 * are described in the Nokia Qt GPL Exception version 1.2, included in | |
25 * the file GPL_EXCEPTION.txt in this package. | |
26 * | |
27 * Qt for Windows(R) Licensees | |
28 * As a special exception, Nokia, as the sole copyright holder for Qt | |
29 * Designer, grants users of the Qt/Eclipse Integration plug-in the | |
30 * right for the Qt/Eclipse Integration to link to functionality | |
31 * provided by Qt Designer and its related libraries. | |
32 * | |
33 * | |
34 * If you are unsure which license is appropriate for your use, please | |
35 * contact the sales department at qt-sales@nokia.com. | |
36 | |
37 ** | |
38 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | |
39 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
40 ** | |
41 ****************************************************************************/ | |
42 | |
43 #ifndef PP_MACRO_EXPANDER_H | |
44 #define PP_MACRO_EXPANDER_H | |
45 | |
46 namespace rpp { | |
47 | |
48 struct pp_frame | |
49 { | |
50 pp_macro *expanding_macro; | |
51 std::vector<std::string> *actuals; | |
52 | |
53 pp_frame (pp_macro *__expanding_macro, std::vector<std::string> *__actuals): | |
54 expanding_macro (__expanding_macro), actuals (__actuals) {} | |
55 }; | |
56 | |
57 class pp_macro_expander | |
58 { | |
59 pp_environment &env; | |
60 pp_frame *frame; | |
61 | |
62 pp_skip_number skip_number; | |
63 pp_skip_identifier skip_identifier; | |
64 pp_skip_string_literal skip_string_literal; | |
65 pp_skip_char_literal skip_char_literal; | |
66 pp_skip_argument skip_argument; | |
67 pp_skip_comment_or_divop skip_comment_or_divop; | |
68 pp_skip_blanks skip_blanks; | |
69 pp_skip_whitespaces skip_whitespaces; | |
70 | |
71 std::string const *resolve_formal (pp_fast_string const *__name) | |
72 { | |
73 assert (__name != 0); | |
74 | |
75 if (! frame) | |
76 return 0; | |
77 | |
78 assert (frame->expanding_macro != 0); | |
79 | |
80 std::vector<pp_fast_string const *> const formals = frame->expanding_macro->formals; | |
81 for (std::size_t index = 0; index < formals.size(); ++index) | |
82 { | |
83 pp_fast_string const *formal = formals[index]; | |
84 | |
85 if (*formal != *__name) | |
86 continue; | |
87 | |
88 else if (frame->actuals && index < frame->actuals->size()) | |
89 return &(*frame->actuals)[index]; | |
90 | |
91 else | |
92 assert (0); // internal error? | |
93 } | |
94 | |
95 return 0; | |
96 } | |
97 | |
98 public: // attributes | |
99 int lines; | |
100 int generated_lines; | |
101 | |
102 public: | |
103 pp_macro_expander (pp_environment &__env, pp_frame *__frame = 0): | |
104 env (__env), frame (__frame), lines (0), generated_lines (0) {} | |
105 | |
106 template <typename _InputIterator, typename _OutputIterator> | |
107 _InputIterator operator () (_InputIterator __first, _InputIterator __last, _OutputIterator __result) | |
108 { | |
109 generated_lines = 0; | |
110 __first = skip_blanks (__first, __last); | |
111 lines = skip_blanks.lines; | |
112 | |
113 while (__first != __last) | |
114 { | |
115 if (*__first == '\n') | |
116 { | |
117 *__result++ = *__first; | |
118 ++lines; | |
119 | |
120 __first = skip_blanks (++__first, __last); | |
121 lines += skip_blanks.lines; | |
122 | |
123 if (__first != __last && *__first == '#') | |
124 break; | |
125 } | |
126 else if (*__first == '#') | |
127 { | |
128 __first = skip_blanks (++__first, __last); | |
129 lines += skip_blanks.lines; | |
130 | |
131 _InputIterator end_id = skip_identifier (__first, __last); | |
132 | |
133 // ### rewrite: not safe | |
134 char name_buffer[512], *cp = name_buffer; | |
135 std::copy (__first, end_id, cp); | |
136 std::size_t name_size = end_id - __first; | |
137 name_buffer[name_size] = '\0'; | |
138 | |
139 pp_fast_string fast_name (name_buffer, name_size); | |
140 | |
141 if (std::string const *actual = resolve_formal (&fast_name)) | |
142 { | |
143 *__result++ = '\"'; | |
144 | |
145 for (std::string::const_iterator it = skip_whitespaces (actual->begin (), actual->end ()); | |
146 it != actual->end (); ++it) | |
147 { | |
148 if (*it == '"') | |
149 { | |
150 *__result++ = '\\'; | |
151 *__result++ = *it; | |
152 } | |
153 | |
154 else if (*it == '\n') | |
155 { | |
156 *__result++ = '"'; | |
157 *__result++ = '\n'; | |
158 *__result++ = '"'; | |
159 } | |
160 | |
161 else | |
162 *__result++ = *it; | |
163 } | |
164 | |
165 *__result++ = '\"'; | |
166 __first = end_id; | |
167 } | |
168 else | |
169 *__result++ = '#'; // ### warning message? | |
170 } | |
171 else if (*__first == '\"') | |
172 { | |
173 _InputIterator next_pos = skip_string_literal (__first, __last); | |
174 lines += skip_string_literal.lines; | |
175 std::copy (__first, next_pos, __result); | |
176 __first = next_pos; | |
177 } | |
178 else if (*__first == '\'') | |
179 { | |
180 _InputIterator next_pos = skip_char_literal (__first, __last); | |
181 lines += skip_char_literal.lines; | |
182 std::copy (__first, next_pos, __result); | |
183 __first = next_pos; | |
184 } | |
185 else if (_PP_internal::comment_p (__first, __last)) | |
186 { | |
187 __first = skip_comment_or_divop (__first, __last); | |
188 int n = skip_comment_or_divop.lines; | |
189 lines += n; | |
190 | |
191 while (n-- > 0) | |
192 *__result++ = '\n'; | |
193 } | |
194 else if (pp_isspace (*__first)) | |
195 { | |
196 for (; __first != __last; ++__first) | |
197 { | |
198 if (*__first == '\n' || !pp_isspace (*__first)) | |
199 break; | |
200 } | |
201 | |
202 *__result = ' '; | |
203 } | |
204 else if (pp_isdigit (*__first)) | |
205 { | |
206 _InputIterator next_pos = skip_number (__first, __last); | |
207 lines += skip_number.lines; | |
208 std::copy (__first, next_pos, __result); | |
209 __first = next_pos; | |
210 } | |
211 else if (pp_isalpha (*__first) || *__first == '_') | |
212 { | |
213 _InputIterator name_begin = __first; | |
214 _InputIterator name_end = skip_identifier (__first, __last); | |
215 __first = name_end; // advance | |
216 | |
217 // search for the paste token | |
218 _InputIterator next = skip_blanks (__first, __last); | |
219 if (next != __last && *next == '#') | |
220 { | |
221 ++next; | |
222 if (next != __last && *next == '#') | |
223 __first = skip_blanks(++next, __last); | |
224 } | |
225 | |
226 // ### rewrite: not safe | |
227 | |
228 std::ptrdiff_t name_size; | |
229 #if defined(__SUNPRO_CC) | |
230 std::distance (name_begin, name_end, name_size); | |
231 #else | |
232 name_size = std::distance (name_begin, name_end); | |
233 #endif | |
234 assert (name_size >= 0 && name_size < 512); | |
235 | |
236 char name_buffer[512], *cp = name_buffer; | |
237 std::size_t __size = name_end - name_begin; | |
238 std::copy (name_begin, name_end, cp); | |
239 name_buffer[__size] = '\0'; | |
240 | |
241 pp_fast_string fast_name (name_buffer, name_size); | |
242 | |
243 if (std::string const *actual = resolve_formal (&fast_name)) | |
244 { | |
245 std::copy (actual->begin (), actual->end (), __result); | |
246 continue; | |
247 } | |
248 | |
249 static bool hide_next = false; // ### remove me | |
250 | |
251 pp_macro *macro = env.resolve (name_buffer, name_size); | |
252 if (! macro || macro->hidden || hide_next) | |
253 { | |
254 hide_next = ! strcmp (name_buffer, "defined"); | |
255 | |
256 if (__size == 8 && name_buffer [0] == '_' && name_buffer [1] == '_') | |
257 { | |
258 if (! strcmp (name_buffer, "__LINE__")) | |
259 { | |
260 char buf [16]; | |
261 char *end = buf + pp_snprintf (buf, 16, "%d", env.current_line + lines); | |
262 | |
263 std::copy (&buf [0], end, __result); | |
264 continue; | |
265 } | |
266 | |
267 else if (! strcmp (name_buffer, "__FILE__")) | |
268 { | |
269 __result++ = '"'; | |
270 std::copy (env.current_file.begin (), env.current_file.end (), __result); // ### quote | |
271 __result++ = '"'; | |
272 continue; | |
273 } | |
274 } | |
275 | |
276 std::copy (name_begin, name_end, __result); | |
277 continue; | |
278 } | |
279 | |
280 if (! macro->function_like) | |
281 { | |
282 pp_macro *m = 0; | |
283 | |
284 if (macro->definition) | |
285 { | |
286 macro->hidden = true; | |
287 | |
288 std::string __tmp; | |
289 __tmp.reserve (256); | |
290 | |
291 pp_macro_expander expand_macro (env); | |
292 expand_macro (macro->definition->begin (), macro->definition->end (), std::back_inserter (__tmp)); | |
293 generated_lines += expand_macro.lines; | |
294 | |
295 if (! __tmp.empty ()) | |
296 { | |
297 std::string::iterator __begin_id = skip_whitespaces (__tmp.begin (), __tmp.end ()); | |
298 std::string::iterator __end_id = skip_identifier (__begin_id, __tmp.end ()); | |
299 | |
300 if (__end_id == __tmp.end ()) | |
301 { | |
302 std::string __id; | |
303 __id.assign (__begin_id, __end_id); | |
304 | |
305 std::size_t x; | |
306 #if defined(__SUNPRO_CC) | |
307 std::distance (__begin_id, __end_id, x); | |
308 #else | |
309 x = std::distance (__begin_id, __end_id); | |
310 #endif | |
311 m = env.resolve (__id.c_str (), x); | |
312 } | |
313 | |
314 if (! m) | |
315 std::copy (__tmp.begin (), __tmp.end (), __result); | |
316 } | |
317 | |
318 macro->hidden = false; | |
319 } | |
320 | |
321 if (! m) | |
322 continue; | |
323 | |
324 macro = m; | |
325 } | |
326 | |
327 // function like macro | |
328 _InputIterator arg_it = skip_whitespaces (__first, __last); | |
329 | |
330 if (arg_it == __last || *arg_it != '(') | |
331 { | |
332 std::copy (name_begin, name_end, __result); | |
333 lines += skip_whitespaces.lines; | |
334 __first = arg_it; | |
335 continue; | |
336 } | |
337 | |
338 std::vector<std::string> actuals; | |
339 actuals.reserve (5); | |
340 ++arg_it; // skip '(' | |
341 | |
342 pp_macro_expander expand_actual (env, frame); | |
343 | |
344 _InputIterator arg_end = skip_argument_variadics (actuals, macro, arg_it, __last); | |
345 if (arg_it != arg_end) | |
346 { | |
347 std::string actual (arg_it, arg_end); | |
348 actuals.resize (actuals.size() + 1); | |
349 actuals.back ().reserve (255); | |
350 expand_actual (actual.begin (), actual.end(), std::back_inserter (actuals.back())); | |
351 arg_it = arg_end; | |
352 } | |
353 | |
354 while (arg_it != __last && *arg_end == ',') | |
355 { | |
356 ++arg_it; // skip ',' | |
357 | |
358 arg_end = skip_argument_variadics (actuals, macro, arg_it, __last); | |
359 std::string actual (arg_it, arg_end); | |
360 actuals.resize (actuals.size() + 1); | |
361 actuals.back ().reserve (255); | |
362 expand_actual (actual.begin (), actual.end(), std::back_inserter (actuals.back())); | |
363 arg_it = arg_end; | |
364 } | |
365 | |
366 assert (arg_it != __last && *arg_it == ')'); | |
367 | |
368 ++arg_it; // skip ')' | |
369 __first = arg_it; | |
370 | |
371 #if 0 // ### enable me | |
372 assert ((macro->variadics && macro->formals.size () >= actuals.size ()) | |
373 || macro->formals.size() == actuals.size()); | |
374 #endif | |
375 | |
376 pp_frame frame (macro, &actuals); | |
377 pp_macro_expander expand_macro (env, &frame); | |
378 macro->hidden = true; | |
379 expand_macro (macro->definition->begin (), macro->definition->end (), __result); | |
380 macro->hidden = false; | |
381 generated_lines += expand_macro.lines; | |
382 } | |
383 else | |
384 *__result++ = *__first++; | |
385 } | |
386 | |
387 return __first; | |
388 } | |
389 | |
390 template <typename _InputIterator> | |
391 _InputIterator skip_argument_variadics (std::vector<std::string> const &__actuals, pp_macro *__macro, | |
392 _InputIterator __first, _InputIterator __last) | |
393 { | |
394 _InputIterator arg_end = skip_argument (__first, __last); | |
395 | |
396 while (__macro->variadics && __first != arg_end && arg_end != __last && *arg_end == ',' | |
397 && (__actuals.size () + 1) == __macro->formals.size ()) | |
398 { | |
399 arg_end = skip_argument (++arg_end, __last); | |
400 } | |
401 | |
402 return arg_end; | |
403 } | |
404 }; | |
405 | |
406 } // namespace rpp | |
407 | |
408 #endif // PP_MACRO_EXPANDER_H | |
409 | |
410 // kate: space-indent on; indent-width 2; replace-tabs on; |