support for creating template instance classes
[lqt/mk.git] / cpptoxml / parser / rpp / pp-macro-expander.h
blob3f5ff7ea090e1d454541f2df8b8512b4dc3d52a3
1 /****************************************************************************
2 **
3 ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
4 ** Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
5 **
6 ** This file is part of $PRODUCT$.
7 **
8 ** $CPP_LICENSE$
9 **
10 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
11 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 ****************************************************************************/
15 #ifndef PP_MACRO_EXPANDER_H
16 #define PP_MACRO_EXPANDER_H
18 namespace rpp {
20 struct pp_frame
22 pp_macro *expanding_macro;
23 std::vector<std::string> *actuals;
25 pp_frame (pp_macro *__expanding_macro, std::vector<std::string> *__actuals):
26 expanding_macro (__expanding_macro), actuals (__actuals) {}
29 class pp_macro_expander
31 pp_environment &env;
32 pp_frame *frame;
34 pp_skip_number skip_number;
35 pp_skip_identifier skip_identifier;
36 pp_skip_string_literal skip_string_literal;
37 pp_skip_char_literal skip_char_literal;
38 pp_skip_argument skip_argument;
39 pp_skip_comment_or_divop skip_comment_or_divop;
40 pp_skip_blanks skip_blanks;
41 pp_skip_whitespaces skip_whitespaces;
43 std::string const *resolve_formal (pp_fast_string const *__name)
45 assert (__name != 0);
47 if (! frame)
48 return 0;
50 assert (frame->expanding_macro != 0);
52 std::vector<pp_fast_string const *> const formals = frame->expanding_macro->formals;
53 for (std::size_t index = 0; index < formals.size(); ++index)
55 pp_fast_string const *formal = formals[index];
57 if (*formal != *__name)
58 continue;
60 else if (frame->actuals && index < frame->actuals->size())
61 return &(*frame->actuals)[index];
63 else
64 assert (0); // internal error?
67 return 0;
70 public: // attributes
71 int lines;
72 int generated_lines;
74 public:
75 pp_macro_expander (pp_environment &__env, pp_frame *__frame = 0):
76 env (__env), frame (__frame), lines (0), generated_lines (0) {}
78 template <typename _InputIterator, typename _OutputIterator>
79 _InputIterator operator () (_InputIterator __first, _InputIterator __last, _OutputIterator __result)
81 generated_lines = 0;
82 __first = skip_blanks (__first, __last);
83 lines = skip_blanks.lines;
85 while (__first != __last)
87 if (*__first == '\n')
89 *__result++ = *__first;
90 ++lines;
92 __first = skip_blanks (++__first, __last);
93 lines += skip_blanks.lines;
95 if (__first != __last && *__first == '#')
96 break;
98 else if (*__first == '#')
100 __first = skip_blanks (++__first, __last);
101 lines += skip_blanks.lines;
103 _InputIterator end_id = skip_identifier (__first, __last);
105 // ### rewrite: not safe
106 char name_buffer[512], *cp = name_buffer;
107 std::copy (__first, end_id, cp);
108 std::size_t name_size = end_id - __first;
109 name_buffer[name_size] = '\0';
111 pp_fast_string fast_name (name_buffer, name_size);
113 if (std::string const *actual = resolve_formal (&fast_name))
115 *__result++ = '\"';
117 for (std::string::const_iterator it = skip_whitespaces (actual->begin (), actual->end ());
118 it != actual->end (); ++it)
120 if (*it == '"')
122 *__result++ = '\\';
123 *__result++ = *it;
126 else if (*it == '\n')
128 *__result++ = '"';
129 *__result++ = '\n';
130 *__result++ = '"';
133 else
134 *__result++ = *it;
137 *__result++ = '\"';
138 __first = end_id;
140 else
141 *__result++ = '#'; // ### warning message?
143 else if (*__first == '\"')
145 _InputIterator next_pos = skip_string_literal (__first, __last);
146 lines += skip_string_literal.lines;
147 std::copy (__first, next_pos, __result);
148 __first = next_pos;
150 else if (*__first == '\'')
152 _InputIterator next_pos = skip_char_literal (__first, __last);
153 lines += skip_char_literal.lines;
154 std::copy (__first, next_pos, __result);
155 __first = next_pos;
157 else if (_PP_internal::comment_p (__first, __last))
159 __first = skip_comment_or_divop (__first, __last);
160 int n = skip_comment_or_divop.lines;
161 lines += n;
163 while (n-- > 0)
164 *__result++ = '\n';
166 else if (pp_isspace (*__first))
168 for (; __first != __last; ++__first)
170 if (*__first == '\n' || !pp_isspace (*__first))
171 break;
174 *__result = ' ';
176 else if (pp_isdigit (*__first))
178 _InputIterator next_pos = skip_number (__first, __last);
179 lines += skip_number.lines;
180 std::copy (__first, next_pos, __result);
181 __first = next_pos;
183 else if (pp_isalpha (*__first) || *__first == '_')
185 _InputIterator name_begin = __first;
186 _InputIterator name_end = skip_identifier (__first, __last);
187 __first = name_end; // advance
189 // search for the paste token
190 _InputIterator next = skip_blanks (__first, __last);
191 if (next != __last && *next == '#')
193 ++next;
194 if (next != __last && *next == '#')
195 __first = skip_blanks(++next, __last);
198 // ### rewrite: not safe
200 std::ptrdiff_t name_size;
201 #if defined(__SUNPRO_CC)
202 std::distance (name_begin, name_end, name_size);
203 #else
204 name_size = std::distance (name_begin, name_end);
205 #endif
206 assert (name_size >= 0 && name_size < 512);
208 char name_buffer[512], *cp = name_buffer;
209 std::size_t __size = name_end - name_begin;
210 std::copy (name_begin, name_end, cp);
211 name_buffer[__size] = '\0';
213 pp_fast_string fast_name (name_buffer, name_size);
215 if (std::string const *actual = resolve_formal (&fast_name))
217 std::copy (actual->begin (), actual->end (), __result);
218 continue;
221 static bool hide_next = false; // ### remove me
223 pp_macro *macro = env.resolve (name_buffer, name_size);
224 if (! macro || macro->f.hidden || hide_next)
226 hide_next = ! strcmp (name_buffer, "defined");
228 if (__size == 8 && name_buffer [0] == '_' && name_buffer [1] == '_')
230 if (! strcmp (name_buffer, "__LINE__"))
232 char buf [16];
233 char *end = buf + pp_snprintf (buf, 16, "%d", env.current_line + lines);
235 std::copy (&buf [0], end, __result);
236 continue;
239 else if (! strcmp (name_buffer, "__FILE__"))
241 __result++ = '"';
242 std::copy (env.current_file.begin (), env.current_file.end (), __result); // ### quote
243 __result++ = '"';
244 continue;
248 std::copy (name_begin, name_end, __result);
249 continue;
252 if (! macro->f.function_like)
254 pp_macro *m = 0;
256 if (macro->definition)
258 macro->f.hidden = true;
260 std::string __tmp;
261 __tmp.reserve (256);
263 pp_macro_expander expand_macro (env);
264 expand_macro (macro->definition->begin (), macro->definition->end (), std::back_inserter (__tmp));
265 generated_lines += expand_macro.lines;
267 if (! __tmp.empty ())
269 std::string::iterator __begin_id = skip_whitespaces (__tmp.begin (), __tmp.end ());
270 std::string::iterator __end_id = skip_identifier (__begin_id, __tmp.end ());
272 if (__end_id == __tmp.end ())
274 std::string __id;
275 __id.assign (__begin_id, __end_id);
277 std::size_t x;
278 #if defined(__SUNPRO_CC)
279 std::distance (__begin_id, __end_id, x);
280 #else
281 x = std::distance (__begin_id, __end_id);
282 #endif
283 m = env.resolve (__id.c_str (), x);
286 if (! m)
287 std::copy (__tmp.begin (), __tmp.end (), __result);
290 macro->f.hidden = false;
293 if (! m)
294 continue;
296 macro = m;
299 // function like macro
300 _InputIterator arg_it = skip_whitespaces (__first, __last);
302 if (arg_it == __last || *arg_it != '(')
304 std::copy (name_begin, name_end, __result);
305 lines += skip_whitespaces.lines;
306 __first = arg_it;
307 continue;
310 std::vector<std::string> actuals;
311 actuals.reserve (5);
312 ++arg_it; // skip '('
314 pp_macro_expander expand_actual (env, frame);
316 _InputIterator arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
317 if (arg_it != arg_end)
319 std::string actual (arg_it, arg_end);
320 actuals.resize (actuals.size() + 1);
321 actuals.back ().reserve (255);
322 expand_actual (actual.begin (), actual.end(), std::back_inserter (actuals.back()));
323 arg_it = arg_end;
326 while (arg_it != __last && *arg_end == ',')
328 ++arg_it; // skip ','
330 arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
331 std::string actual (arg_it, arg_end);
332 actuals.resize (actuals.size() + 1);
333 actuals.back ().reserve (255);
334 expand_actual (actual.begin (), actual.end(), std::back_inserter (actuals.back()));
335 arg_it = arg_end;
338 assert (arg_it != __last && *arg_it == ')');
340 ++arg_it; // skip ')'
341 __first = arg_it;
343 #if 0 // ### enable me
344 assert ((macro->variadics && macro->formals.size () >= actuals.size ())
345 || macro->formals.size() == actuals.size());
346 #endif
348 pp_frame frame (macro, &actuals);
349 pp_macro_expander expand_macro (env, &frame);
350 macro->f.hidden = true;
351 expand_macro (macro->definition->begin (), macro->definition->end (), __result);
352 macro->f.hidden = false;
353 generated_lines += expand_macro.lines;
355 else
356 *__result++ = *__first++;
359 return __first;
362 template <typename _InputIterator>
363 _InputIterator skip_argument_variadics (std::vector<std::string> const &__actuals, pp_macro *__macro,
364 _InputIterator __first, _InputIterator __last)
366 _InputIterator arg_end = skip_argument (__first, __last);
368 while (__macro->f.variadics && __first != arg_end && arg_end != __last && *arg_end == ','
369 && (__actuals.size () + 1) == __macro->formals.size ())
371 arg_end = skip_argument (++arg_end, __last);
374 return arg_end;
378 } // namespace rpp
380 #endif // PP_MACRO_EXPANDER_H
382 // kate: space-indent on; indent-width 2; replace-tabs on;