1 /****************************************************************************
3 ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
4 ** Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
6 ** This file is part of $PRODUCT$.
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
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
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
)
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
)
60 else if (frame
->actuals
&& index
< frame
->actuals
->size())
61 return &(*frame
->actuals
)[index
];
64 assert (0); // internal error?
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
)
82 __first
= skip_blanks (__first
, __last
);
83 lines
= skip_blanks
.lines
;
85 while (__first
!= __last
)
89 *__result
++ = *__first
;
92 __first
= skip_blanks (++__first
, __last
);
93 lines
+= skip_blanks
.lines
;
95 if (__first
!= __last
&& *__first
== '#')
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
))
117 for (std::string::const_iterator it
= skip_whitespaces (actual
->begin (), actual
->end ());
118 it
!= actual
->end (); ++it
)
126 else if (*it
== '\n')
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
);
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
);
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
;
166 else if (pp_isspace (*__first
))
168 for (; __first
!= __last
; ++__first
)
170 if (*__first
== '\n' || !pp_isspace (*__first
))
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
);
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
== '#')
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
);
204 name_size
= std::distance (name_begin
, name_end
);
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
);
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__"))
233 char *end
= buf
+ pp_snprintf (buf
, 16, "%d", env
.current_line
+ lines
);
235 std::copy (&buf
[0], end
, __result
);
239 else if (! strcmp (name_buffer
, "__FILE__"))
242 std::copy (env
.current_file
.begin (), env
.current_file
.end (), __result
); // ### quote
248 std::copy (name_begin
, name_end
, __result
);
252 if (! macro
->f
.function_like
)
256 if (macro
->definition
)
258 macro
->f
.hidden
= true;
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 ())
275 __id
.assign (__begin_id
, __end_id
);
278 #if defined(__SUNPRO_CC)
279 std::distance (__begin_id
, __end_id
, x
);
281 x
= std::distance (__begin_id
, __end_id
);
283 m
= env
.resolve (__id
.c_str (), x
);
287 std::copy (__tmp
.begin (), __tmp
.end (), __result
);
290 macro
->f
.hidden
= false;
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
;
310 std::vector
<std::string
> actuals
;
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()));
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()));
338 assert (arg_it
!= __last
&& *arg_it
== ')');
340 ++arg_it
; // skip ')'
343 #if 0 // ### enable me
344 assert ((macro
->variadics
&& macro
->formals
.size () >= actuals
.size ())
345 || macro
->formals
.size() == actuals
.size());
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
;
356 *__result
++ = *__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
);
380 #endif // PP_MACRO_EXPANDER_H
382 // kate: space-indent on; indent-width 2; replace-tabs on;