~ubuntu-branches/debian/sid/kdevelop/sid

« back to all changes in this revision

Viewing changes to languages/cpp/parser/rpp/pp-scanner.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Lainé
  • Date: 2010-05-05 07:21:55 UTC
  • mfrom: (1.2.3 upstream) (5.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100505072155-h78lx19pu04sbhtn
Tags: 4:4.0.0-2
* Upload to unstable (Closes: #579947, #481832).
* Acknowledge obsolete NMU fixes (Closes: #562410, #546961).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
 
3
  Copyright 2006 Hamish Rodda <rodda@kde.org>
 
4
 
 
5
  Permission to use, copy, modify, distribute, and sell this software and its
 
6
  documentation for any purpose is hereby granted without fee, provided that
 
7
  the above copyright notice appear in all copies and that both that
 
8
  copyright notice and this permission notice appear in supporting
 
9
  documentation.
 
10
 
 
11
  The above copyright notice and this permission notice shall be included in
 
12
  all copies or substantial portions of the Software.
 
13
 
 
14
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
15
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
16
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 
17
  KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 
18
  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
19
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
20
*/
 
21
 
 
22
#include "pp-scanner.h"
 
23
#include "chartools.h"
 
24
#include <language/duchain/indexedstring.h>
 
25
#include <util/kdevvarlengtharray.h>
 
26
 
 
27
using namespace rpp;
 
28
 
 
29
void pp_skip_blanks::operator()(Stream& input, Stream& output)
 
30
{
 
31
  while (!input.atEnd()) {
 
32
    if (input == '\\') {
 
33
      ++input;
 
34
      if (input != '\n') {
 
35
        --input;
 
36
        return;
 
37
 
 
38
      } else {
 
39
        ++input;
 
40
        continue;
 
41
      }
 
42
    }
 
43
 
 
44
    if (input == '\n' || !isSpace(input.current()))
 
45
      return;
 
46
 
 
47
    output << input;
 
48
    ++input;
 
49
  }
 
50
}
 
51
 
 
52
void pp_skip_whitespaces::operator()(Stream& input, Stream& output)
 
53
{
 
54
  while (!input.atEnd()) {
 
55
    if (!isSpace(input.current()))
 
56
      return;
 
57
 
 
58
    output << input;
 
59
    ++input;
 
60
  }
 
61
}
 
62
 
 
63
void pp_skip_comment_or_divop::operator()(Stream& input, Stream& output, bool outputText)
 
64
{
 
65
  enum {
 
66
    MAYBE_BEGIN,
 
67
    BEGIN,
 
68
    MAYBE_END,
 
69
    END,
 
70
    IN_COMMENT,
 
71
    IN_CXX_COMMENT
 
72
  } state (MAYBE_BEGIN);
 
73
 
 
74
  while (!input.atEnd()) {
 
75
    switch (state) {
 
76
      case MAYBE_BEGIN:
 
77
        if (input != '/')
 
78
          return;
 
79
 
 
80
        state = BEGIN;
 
81
        break;
 
82
 
 
83
      case BEGIN:
 
84
        if (input == '*')
 
85
          state = IN_COMMENT;
 
86
        else if (input == '/')
 
87
          state = IN_CXX_COMMENT;
 
88
        else
 
89
          return;
 
90
        break;
 
91
 
 
92
      case IN_COMMENT:
 
93
        if (input == '*')
 
94
          state = MAYBE_END;
 
95
        break;
 
96
 
 
97
      case IN_CXX_COMMENT:
 
98
        if (input == '\n')
 
99
          return;
 
100
        break;
 
101
 
 
102
      case MAYBE_END:
 
103
        if (input == '/')
 
104
          state = END;
 
105
        else if (input != '*')
 
106
          state = IN_COMMENT;
 
107
        break;
 
108
 
 
109
      case END:
 
110
        return;
 
111
    }
 
112
 
 
113
    if (outputText) {
 
114
      output << input;
 
115
      ++input;
 
116
 
 
117
    } else if (input == '\n') {
 
118
      output << '\n';
 
119
      ++input;
 
120
      output.mark(input.inputPosition());
 
121
 
 
122
    } else {
 
123
      output << ' ';
 
124
      ++input;
 
125
    }
 
126
  }
 
127
}
 
128
 
 
129
uint pp_skip_identifier::operator()(Stream& input)
 
130
{
 
131
  KDevVarLengthArray<char, 100> identifier;
 
132
  
 
133
  KDevelop::IndexedString::RunningHash hash;
 
134
 
 
135
  while (!input.atEnd()) {
 
136
    if(!isCharacter(input.current())) {
 
137
      //Do a more complex merge, where also tokenized identifiers can be merged
 
138
      KDevelop::IndexedString ret;
 
139
      if(!identifier.isEmpty())
 
140
        ret = KDevelop::IndexedString(identifier.constData(), identifier.size(), hash.hash);
 
141
      
 
142
      while (!input.atEnd()) {
 
143
        uint current = input.current();
 
144
        
 
145
        if (!isLetterOrNumber(current) && input != '_' && isCharacter(current))
 
146
          break;
 
147
        
 
148
        if(ret.isEmpty())
 
149
          ret = KDevelop::IndexedString::fromIndex(current); //The most common fast path
 
150
        else ///@todo Be better to build up a complete buffer and then append it all, so we don't get he intermediate strings into the repository
 
151
          ret = KDevelop::IndexedString(ret.byteArray() + KDevelop::IndexedString::fromIndex(input.current()).byteArray());
 
152
        
 
153
        ++input;
 
154
      }
 
155
      return ret.index();
 
156
    }
 
157
    //Collect characters and connect them to an IndexedString
 
158
    
 
159
    if (!isLetterOrNumber(input.current()) && input != '_')
 
160
        break;
 
161
 
 
162
    char c = characterFromIndex(input);
 
163
    hash.append(c);
 
164
    identifier.append(c);
 
165
    ++input;
 
166
  }
 
167
 
 
168
  return KDevelop::IndexedString(identifier.constData(), identifier.size(), hash.hash).index();
 
169
}
 
170
 
 
171
void pp_skip_number::operator()(Stream& input, Stream& output)
 
172
{
 
173
  while (!input.atEnd()) {
 
174
    if (!isLetterOrNumber(input.current()) && input != '_')
 
175
        return;
 
176
 
 
177
    output << input;
 
178
    ++input;
 
179
  }
 
180
}
 
181
 
 
182
void pp_skip_string_literal::operator()(Stream& input, Stream& output)
 
183
{
 
184
  enum {
 
185
    BEGIN,
 
186
    IN_STRING,
 
187
    QUOTE,
 
188
    END
 
189
  } state (BEGIN);
 
190
 
 
191
  while (!input.atEnd()) {
 
192
    switch (state) {
 
193
      case BEGIN:
 
194
        if (input != '\"')
 
195
          return;
 
196
        state = IN_STRING;
 
197
        break;
 
198
 
 
199
      case IN_STRING:
 
200
//         Q_ASSERT(input != '\n');
 
201
 
 
202
        if (input == '\"')
 
203
          state = END;
 
204
        else if (input == '\\')
 
205
          state = QUOTE;
 
206
        break;
 
207
 
 
208
      case QUOTE:
 
209
        state = IN_STRING;
 
210
        break;
 
211
 
 
212
      case END:
 
213
        return;
 
214
    }
 
215
 
 
216
    output << input;
 
217
    ++input;
 
218
  }
 
219
}
 
220
 
 
221
void pp_skip_char_literal::operator()(Stream& input, Stream& output)
 
222
{
 
223
  enum {
 
224
    BEGIN,
 
225
    IN_STRING,
 
226
    QUOTE,
 
227
    END
 
228
  } state (BEGIN);
 
229
  int inner_count = 0;
 
230
 
 
231
  while (!input.atEnd()) {
 
232
    if (state == END)
 
233
      break;
 
234
 
 
235
    switch (state) {
 
236
      case BEGIN:
 
237
        if (input != '\'')
 
238
          return;
 
239
        state = IN_STRING;
 
240
        break;
 
241
 
 
242
      case IN_STRING:
 
243
        if(input == '\n' || inner_count > 3)
 
244
          return; //Probably this isn't a string literal. Example: "#warning What's up"
 
245
 
 
246
        if (input == '\'')
 
247
          state = END;
 
248
        else if (input == '\\')
 
249
          state = QUOTE;
 
250
        break;
 
251
        ++inner_count;
 
252
      case QUOTE:
 
253
        state = IN_STRING;
 
254
        break;
 
255
 
 
256
      default:
 
257
        Q_ASSERT(0);
 
258
        break;
 
259
    }
 
260
 
 
261
    output << input;
 
262
    ++input;
 
263
  }
 
264
}
 
265
 
 
266
///@todo Can this deal with comments? like /*(*/
 
267
void pp_skip_argument::operator()(Stream& input, Stream& output)
 
268
{
 
269
  int depth = 0;
 
270
 
 
271
  while (!input.atEnd()) {
 
272
    if (!depth && (input == ')' || input == ',')) {
 
273
      return;
 
274
 
 
275
    } else if (input == '(') {
 
276
      ++depth;
 
277
 
 
278
    } else if (input == ')') {
 
279
      --depth;
 
280
 
 
281
    } else if (input == '\"') {
 
282
      skip_string_literal(input, output);
 
283
      continue;
 
284
 
 
285
    } else if (input == '\'') {
 
286
      skip_char_literal (input, output);
 
287
      continue;
 
288
 
 
289
    } else if (input == '/') {
 
290
      skip_comment_or_divop (input, output, true);
 
291
      continue;
 
292
 
 
293
    } else if (isLetter(input.current()) || input == '_') {
 
294
      Anchor inputPosition = input.inputPosition();
 
295
      output.appendString(inputPosition, KDevelop::IndexedString::fromIndex(skip_identifier(input)));
 
296
      continue;
 
297
 
 
298
    } else if (isNumber(input.current())) {
 
299
      output.mark(input.inputPosition());
 
300
      skip_number(input, output);
 
301
      continue;
 
302
 
 
303
    }
 
304
 
 
305
    output << input;
 
306
    ++input;
 
307
  }
 
308
 
 
309
  return;
 
310
}