~ubuntu-branches/ubuntu/precise/qtscriptgenerator/precise

« back to all changes in this revision

Viewing changes to generator/parser/rpp/pp-macro-expander.h

  • Committer: Bazaar Package Importer
  • Author(s): Modestas Vainius
  • Date: 2009-04-25 16:16:02 UTC
  • Revision ID: james.westby@ubuntu.com-20090425161602-vrlxapa3fbo2k3x7
Tags: upstream-0.1.0
ImportĀ upstreamĀ versionĀ 0.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
12
**
 
13
****************************************************************************/
 
14
 
 
15
#ifndef PP_MACRO_EXPANDER_H
 
16
#define PP_MACRO_EXPANDER_H
 
17
 
 
18
namespace rpp {
 
19
 
 
20
struct pp_frame
 
21
{
 
22
  pp_macro *expanding_macro;
 
23
  std::vector<std::string> *actuals;
 
24
 
 
25
  pp_frame (pp_macro *__expanding_macro, std::vector<std::string> *__actuals):
 
26
    expanding_macro (__expanding_macro), actuals (__actuals) {}
 
27
};
 
28
 
 
29
class pp_macro_expander
 
30
{
 
31
  pp_environment &env;
 
32
  pp_frame *frame;
 
33
 
 
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;
 
42
 
 
43
  std::string const *resolve_formal (pp_fast_string const *__name)
 
44
  {
 
45
    assert (__name != 0);
 
46
 
 
47
    if (! frame)
 
48
      return 0;
 
49
 
 
50
    assert (frame->expanding_macro != 0);
 
51
 
 
52
    std::vector<pp_fast_string const *> const formals = frame->expanding_macro->formals;
 
53
    for (std::size_t index = 0; index < formals.size(); ++index)
 
54
      {
 
55
        pp_fast_string const *formal = formals[index];
 
56
 
 
57
        if (*formal != *__name)
 
58
          continue;
 
59
 
 
60
        else if (frame->actuals && index < frame->actuals->size())
 
61
          return &(*frame->actuals)[index];
 
62
 
 
63
        else
 
64
          assert (0); // internal error?
 
65
      }
 
66
 
 
67
    return 0;
 
68
  }
 
69
 
 
70
public: // attributes
 
71
  int lines;
 
72
  int generated_lines;
 
73
 
 
74
public:
 
75
  pp_macro_expander (pp_environment &__env, pp_frame *__frame = 0):
 
76
    env (__env), frame (__frame), lines (0), generated_lines (0) {}
 
77
 
 
78
  template <typename _InputIterator, typename _OutputIterator>
 
79
  _InputIterator operator () (_InputIterator __first, _InputIterator __last, _OutputIterator __result)
 
80
  {
 
81
    generated_lines = 0;
 
82
    __first = skip_blanks (__first, __last);
 
83
    lines = skip_blanks.lines;
 
84
 
 
85
    while (__first != __last)
 
86
      {
 
87
        if (*__first == '\n')
 
88
          {
 
89
            *__result++ = *__first;
 
90
            ++lines;
 
91
 
 
92
            __first = skip_blanks (++__first, __last);
 
93
            lines += skip_blanks.lines;
 
94
 
 
95
            if (__first != __last && *__first == '#')
 
96
              break;
 
97
          }
 
98
        else if (*__first == '#')
 
99
          {
 
100
            __first = skip_blanks (++__first, __last);
 
101
            lines += skip_blanks.lines;
 
102
 
 
103
            _InputIterator end_id = skip_identifier (__first, __last);
 
104
 
 
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';
 
110
 
 
111
            pp_fast_string fast_name (name_buffer, name_size);
 
112
 
 
113
            if (std::string const *actual = resolve_formal (&fast_name))
 
114
              {
 
115
                *__result++ = '\"';
 
116
 
 
117
                for (std::string::const_iterator it = skip_whitespaces (actual->begin (), actual->end ());
 
118
                    it != actual->end (); ++it)
 
119
                  {
 
120
                    if (*it == '"')
 
121
                      {
 
122
                        *__result++ = '\\';
 
123
                        *__result++ = *it;
 
124
                      }
 
125
 
 
126
                    else if (*it == '\n')
 
127
                      {
 
128
                        *__result++ = '"';
 
129
                        *__result++ = '\n';
 
130
                        *__result++ = '"';
 
131
                      }
 
132
 
 
133
                    else
 
134
                      *__result++ = *it;
 
135
                  }
 
136
 
 
137
                *__result++ = '\"';
 
138
                __first = end_id;
 
139
              }
 
140
            else
 
141
              *__result++ = '#'; // ### warning message?
 
142
          }
 
143
        else if (*__first == '\"')
 
144
          {
 
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;
 
149
          }
 
150
        else if (*__first == '\'')
 
151
          {
 
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;
 
156
          }
 
157
        else if (_PP_internal::comment_p (__first, __last))
 
158
          {
 
159
            __first = skip_comment_or_divop (__first, __last);
 
160
            int n = skip_comment_or_divop.lines;
 
161
            lines += n;
 
162
 
 
163
            while (n-- > 0)
 
164
              *__result++ = '\n';
 
165
          }
 
166
        else if (pp_isspace (*__first))
 
167
          {
 
168
            for (; __first != __last; ++__first)
 
169
              {
 
170
                if (*__first == '\n' || !pp_isspace (*__first))
 
171
                  break;
 
172
              }
 
173
 
 
174
            *__result = ' ';
 
175
          }
 
176
        else if (pp_isdigit (*__first))
 
177
          {
 
178
            _InputIterator next_pos = skip_number (__first, __last);
 
179
            lines += skip_number.lines;
 
180
            std::copy (__first, next_pos, __result);
 
181
            __first = next_pos;
 
182
          }
 
183
        else if (pp_isalpha (*__first) || *__first == '_')
 
184
          {
 
185
            _InputIterator name_begin = __first;
 
186
            _InputIterator name_end = skip_identifier (__first, __last);
 
187
            __first = name_end; // advance
 
188
 
 
189
            // search for the paste token
 
190
            _InputIterator next = skip_blanks (__first, __last);
 
191
            if (next != __last && *next == '#')
 
192
              {
 
193
                ++next;
 
194
                if (next != __last && *next == '#')
 
195
                  __first = skip_blanks(++next, __last);
 
196
              }
 
197
 
 
198
            // ### rewrite: not safe
 
199
 
 
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);
 
207
 
 
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';
 
212
 
 
213
            pp_fast_string fast_name (name_buffer, name_size);
 
214
 
 
215
            if (std::string const *actual = resolve_formal (&fast_name))
 
216
              {
 
217
                std::copy (actual->begin (), actual->end (), __result);
 
218
                continue;
 
219
              }
 
220
 
 
221
            static bool hide_next = false; // ### remove me
 
222
 
 
223
            pp_macro *macro = env.resolve (name_buffer, name_size);
 
224
            if (! macro || macro->hidden || hide_next)
 
225
              {
 
226
                hide_next = ! strcmp (name_buffer, "defined");
 
227
 
 
228
                if (__size == 8 && name_buffer [0] == '_' && name_buffer [1] == '_')
 
229
                  {
 
230
                    if (! strcmp (name_buffer, "__LINE__"))
 
231
                      {
 
232
                        char buf [16];
 
233
                        char *end = buf + pp_snprintf (buf, 16, "%d", env.current_line + lines);
 
234
 
 
235
                        std::copy (&buf [0], end, __result);
 
236
                        continue;
 
237
                      }
 
238
 
 
239
                    else if (! strcmp (name_buffer, "__FILE__"))
 
240
                      {
 
241
                        __result++ = '"';
 
242
                        std::copy (env.current_file.begin (), env.current_file.end (), __result); // ### quote
 
243
                        __result++ = '"';
 
244
                        continue;
 
245
                      }
 
246
                  }
 
247
 
 
248
                std::copy (name_begin, name_end, __result);
 
249
                continue;
 
250
              }
 
251
 
 
252
            if (! macro->function_like)
 
253
              {
 
254
                pp_macro *m = 0;
 
255
 
 
256
                if (macro->definition)
 
257
                  {
 
258
                    macro->hidden = true;
 
259
 
 
260
                    std::string __tmp;
 
261
                    __tmp.reserve (256);
 
262
 
 
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;
 
266
 
 
267
                    if (! __tmp.empty ())
 
268
                      {
 
269
                        std::string::iterator __begin_id = skip_whitespaces (__tmp.begin (), __tmp.end ());
 
270
                        std::string::iterator __end_id = skip_identifier (__begin_id, __tmp.end ());
 
271
 
 
272
                        if (__end_id == __tmp.end ())
 
273
                          {
 
274
                            std::string __id;
 
275
                            __id.assign (__begin_id, __end_id);
 
276
 
 
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);
 
284
                          }
 
285
 
 
286
                        if (! m)
 
287
                          std::copy (__tmp.begin (), __tmp.end (), __result);
 
288
                      }
 
289
 
 
290
                    macro->hidden = false;
 
291
                  }
 
292
 
 
293
                if (! m)
 
294
                  continue;
 
295
 
 
296
                macro = m;
 
297
              }
 
298
 
 
299
            // function like macro
 
300
            _InputIterator arg_it = skip_whitespaces (__first, __last);
 
301
 
 
302
            if (arg_it == __last || *arg_it != '(')
 
303
              {
 
304
                std::copy (name_begin, name_end, __result);
 
305
                lines += skip_whitespaces.lines;
 
306
                __first = arg_it;
 
307
                continue;
 
308
              }
 
309
 
 
310
            std::vector<std::string> actuals;
 
311
            actuals.reserve (5);
 
312
            ++arg_it; // skip '('
 
313
 
 
314
            pp_macro_expander expand_actual (env, frame);
 
315
 
 
316
            _InputIterator arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
 
317
            if (arg_it != arg_end)
 
318
              {
 
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;
 
324
              }
 
325
 
 
326
            while (arg_it != __last && *arg_end == ',')
 
327
              {
 
328
                ++arg_it; // skip ','
 
329
 
 
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;
 
336
              }
 
337
 
 
338
              assert (arg_it != __last && *arg_it == ')');
 
339
 
 
340
              ++arg_it; // skip ')'
 
341
              __first = arg_it;
 
342
 
 
343
#if 0 // ### enable me
 
344
              assert ((macro->variadics && macro->formals.size () >= actuals.size ())
 
345
                          || macro->formals.size() == actuals.size());
 
346
#endif
 
347
 
 
348
              pp_frame frame (macro, &actuals);
 
349
              pp_macro_expander expand_macro (env, &frame);
 
350
              macro->hidden = true;
 
351
              expand_macro (macro->definition->begin (), macro->definition->end (), __result);
 
352
              macro->hidden = false;
 
353
              generated_lines += expand_macro.lines;
 
354
          }
 
355
        else
 
356
          *__result++ = *__first++;
 
357
      }
 
358
 
 
359
    return __first;
 
360
  }
 
361
 
 
362
  template <typename _InputIterator>
 
363
  _InputIterator skip_argument_variadics (std::vector<std::string> const &__actuals, pp_macro *__macro,
 
364
                                          _InputIterator __first, _InputIterator __last)
 
365
  {
 
366
    _InputIterator arg_end = skip_argument (__first, __last);
 
367
 
 
368
    while (__macro->variadics && __first != arg_end && arg_end != __last && *arg_end == ','
 
369
        && (__actuals.size () + 1) == __macro->formals.size ())
 
370
      {
 
371
        arg_end = skip_argument (++arg_end, __last);
 
372
      }
 
373
 
 
374
    return arg_end;
 
375
  }
 
376
};
 
377
 
 
378
} // namespace rpp
 
379
 
 
380
#endif // PP_MACRO_EXPANDER_H
 
381
 
 
382
// kate: space-indent on; indent-width 2; replace-tabs on;