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;