1
2 package net.sourceforge.pmd.ast;
3
4 /***
5 * An implementation of interface CharStream, where the stream is assumed to
6 * contain only ASCII characters (with java-like unicode escape processing).
7 */
8
9 public class JavaCharStream implements CharStream {
10 public static final boolean staticFlag = false;
11
12 static final int hexval(char c) throws java.io.IOException {
13 switch (c) {
14 case '0':
15 return 0;
16 case '1':
17 return 1;
18 case '2':
19 return 2;
20 case '3':
21 return 3;
22 case '4':
23 return 4;
24 case '5':
25 return 5;
26 case '6':
27 return 6;
28 case '7':
29 return 7;
30 case '8':
31 return 8;
32 case '9':
33 return 9;
34
35 case 'a':
36 case 'A':
37 return 10;
38 case 'b':
39 case 'B':
40 return 11;
41 case 'c':
42 case 'C':
43 return 12;
44 case 'd':
45 case 'D':
46 return 13;
47 case 'e':
48 case 'E':
49 return 14;
50 case 'f':
51 case 'F':
52 return 15;
53 }
54
55 throw new java.io.IOException();
56 }
57
58 public int bufpos = -1;
59 int bufsize;
60 int available;
61 int tokenBegin;
62 protected int bufline[];
63 protected int bufcolumn[];
64
65 protected int column = 0;
66 protected int line = 1;
67
68 protected boolean prevCharIsCR = false;
69 protected boolean prevCharIsLF = false;
70
71 protected java.io.Reader inputStream;
72
73 protected char[] nextCharBuf;
74 protected char[] buffer;
75 protected int maxNextCharInd = 0;
76 protected int nextCharInd = -1;
77 protected int inBuf = 0;
78
79 protected void ExpandBuff(boolean wrapAround) {
80 char[] newbuffer = new char[bufsize + 2048];
81 int newbufline[] = new int[bufsize + 2048];
82 int newbufcolumn[] = new int[bufsize + 2048];
83
84 try {
85 if (wrapAround) {
86 System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
87 System.arraycopy(buffer, 0, newbuffer,
88 bufsize - tokenBegin, bufpos);
89 buffer = newbuffer;
90
91 System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
92 System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
93 bufline = newbufline;
94
95 System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
96 System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
97 bufcolumn = newbufcolumn;
98
99 bufpos += (bufsize - tokenBegin);
100 } else {
101 System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
102 buffer = newbuffer;
103
104 System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
105 bufline = newbufline;
106
107 System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
108 bufcolumn = newbufcolumn;
109
110 bufpos -= tokenBegin;
111 }
112 } catch (Throwable t) {
113 throw new RuntimeException(t.getMessage());
114 }
115
116 available = (bufsize += 2048);
117 tokenBegin = 0;
118 }
119
120 protected void FillBuff() throws java.io.IOException {
121 int i;
122 if (maxNextCharInd == 4096)
123 maxNextCharInd = nextCharInd = 0;
124
125 try {
126 if ((i = inputStream.read(nextCharBuf, maxNextCharInd,
127 4096 - maxNextCharInd)) == -1) {
128 inputStream.close();
129 throw new java.io.IOException();
130 } else
131 maxNextCharInd += i;
132 return;
133 } catch (java.io.IOException e) {
134 if (bufpos != 0) {
135 --bufpos;
136 backup(0);
137 } else {
138 bufline[bufpos] = line;
139 bufcolumn[bufpos] = column;
140 }
141 throw e;
142 }
143 }
144
145 protected char ReadByte() throws java.io.IOException {
146 if (++nextCharInd >= maxNextCharInd)
147 FillBuff();
148
149 return nextCharBuf[nextCharInd];
150 }
151
152 public char BeginToken() throws java.io.IOException {
153 if (inBuf > 0) {
154 --inBuf;
155
156 if (++bufpos == bufsize)
157 bufpos = 0;
158
159 tokenBegin = bufpos;
160 return buffer[bufpos];
161 }
162
163 tokenBegin = 0;
164 bufpos = -1;
165
166 return readChar();
167 }
168
169 protected void AdjustBuffSize() {
170 if (available == bufsize) {
171 if (tokenBegin > 2048) {
172 bufpos = 0;
173 available = tokenBegin;
174 } else
175 ExpandBuff(false);
176 } else if (available > tokenBegin)
177 available = bufsize;
178 else if ((tokenBegin - available) < 2048)
179 ExpandBuff(true);
180 else
181 available = tokenBegin;
182 }
183
184 protected void UpdateLineColumn(char c) {
185 column++;
186
187 if (prevCharIsLF) {
188 prevCharIsLF = false;
189 line += (column = 1);
190 } else if (prevCharIsCR) {
191 prevCharIsCR = false;
192 if (c == '\n') {
193 prevCharIsLF = true;
194 } else
195 line += (column = 1);
196 }
197
198 switch (c) {
199 case '\r':
200 prevCharIsCR = true;
201 break;
202 case '\n':
203 prevCharIsLF = true;
204 break;
205 case '\t':
206 column--;
207 column += (8 - (column & 07));
208 break;
209 default :
210 break;
211 }
212
213 bufline[bufpos] = line;
214 bufcolumn[bufpos] = column;
215 }
216
217 public char readChar() throws java.io.IOException {
218 if (inBuf > 0) {
219 --inBuf;
220
221 if (++bufpos == bufsize)
222 bufpos = 0;
223
224 return buffer[bufpos];
225 }
226
227 char c;
228
229 if (++bufpos == available)
230 AdjustBuffSize();
231
232 if ((buffer[bufpos] = c = ReadByte()) == '//') {
233 UpdateLineColumn(c);
234
235 int backSlashCnt = 1;
236
237 for (; ;)
238 {
239 if (++bufpos == available)
240 AdjustBuffSize();
241
242 try {
243 if ((buffer[bufpos] = c = ReadByte()) != '//') {
244 UpdateLineColumn(c);
245
246 if ((c == 'u') && ((backSlashCnt & 1) == 1)) {
247 if (--bufpos < 0)
248 bufpos = bufsize - 1;
249
250 break;
251 }
252
253 backup(backSlashCnt);
254 return '//';
255 }
256 } catch (java.io.IOException e) {
257 if (backSlashCnt > 1)
258 backup(backSlashCnt);
259
260 return '//';
261 }
262
263 UpdateLineColumn(c);
264 backSlashCnt++;
265 }
266
267
268 try {
269 while ((c = ReadByte()) == 'u')
270 ++column;
271
272 buffer[bufpos] = c = (char) (hexval(c) << 12 |
273 hexval(ReadByte()) << 8 |
274 hexval(ReadByte()) << 4 |
275 hexval(ReadByte()));
276
277 column += 4;
278 } catch (java.io.IOException e) {
279 throw new RuntimeException("Invalid escape character at line " + line +
280 " column " + column + ".");
281 }
282
283 if (backSlashCnt == 1)
284 return c;
285 else {
286 backup(backSlashCnt - 1);
287 return '//';
288 }
289 } else {
290 UpdateLineColumn(c);
291 return (c);
292 }
293 }
294
295 /***
296 * @see #getEndColumn
297 * @deprecated
298 */
299
300 public int getColumn() {
301 return bufcolumn[bufpos];
302 }
303
304 /***
305 * @see #getEndLine
306 * @deprecated
307 */
308
309 public int getLine() {
310 return bufline[bufpos];
311 }
312
313 public int getEndColumn() {
314 return bufcolumn[bufpos];
315 }
316
317 public int getEndLine() {
318 return bufline[bufpos];
319 }
320
321 public int getBeginColumn() {
322 return bufcolumn[tokenBegin];
323 }
324
325 public int getBeginLine() {
326 return bufline[tokenBegin];
327 }
328
329 public void backup(int amount) {
330
331 inBuf += amount;
332 if ((bufpos -= amount) < 0)
333 bufpos += bufsize;
334 }
335
336 public JavaCharStream(java.io.Reader dstream,
337 int startline, int startcolumn, int buffersize) {
338 inputStream = dstream;
339 line = startline;
340 column = startcolumn - 1;
341
342 available = bufsize = buffersize;
343 buffer = new char[buffersize];
344 bufline = new int[buffersize];
345 bufcolumn = new int[buffersize];
346 nextCharBuf = new char[4096];
347 }
348
349 public JavaCharStream(java.io.Reader dstream,
350 int startline, int startcolumn) {
351 this(dstream, startline, startcolumn, 4096);
352 }
353
354 public JavaCharStream(java.io.Reader dstream) {
355 this(dstream, 1, 1, 4096);
356 }
357
358 public void ReInit(java.io.Reader dstream,
359 int startline, int startcolumn, int buffersize) {
360 inputStream = dstream;
361 line = startline;
362 column = startcolumn - 1;
363
364 if (buffer == null || buffersize != buffer.length) {
365 available = bufsize = buffersize;
366 buffer = new char[buffersize];
367 bufline = new int[buffersize];
368 bufcolumn = new int[buffersize];
369 nextCharBuf = new char[4096];
370 }
371 prevCharIsLF = prevCharIsCR = false;
372 tokenBegin = inBuf = maxNextCharInd = 0;
373 nextCharInd = bufpos = -1;
374 }
375
376 public void ReInit(java.io.Reader dstream,
377 int startline, int startcolumn) {
378 ReInit(dstream, startline, startcolumn, 4096);
379 }
380
381 public void ReInit(java.io.Reader dstream) {
382 ReInit(dstream, 1, 1, 4096);
383 }
384
385 public JavaCharStream(java.io.InputStream dstream, int startline,
386 int startcolumn, int buffersize) {
387 this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096);
388 }
389
390 public JavaCharStream(java.io.InputStream dstream, int startline,
391 int startcolumn) {
392 this(dstream, startline, startcolumn, 4096);
393 }
394
395 public JavaCharStream(java.io.InputStream dstream) {
396 this(dstream, 1, 1, 4096);
397 }
398
399 public void ReInit(java.io.InputStream dstream, int startline,
400 int startcolumn, int buffersize) {
401 ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096);
402 }
403
404 public void ReInit(java.io.InputStream dstream, int startline,
405 int startcolumn) {
406 ReInit(dstream, startline, startcolumn, 4096);
407 }
408
409 public void ReInit(java.io.InputStream dstream) {
410 ReInit(dstream, 1, 1, 4096);
411 }
412
413 public String GetImage() {
414 if (bufpos >= tokenBegin)
415 return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
416 else
417 return new String(buffer, tokenBegin, bufsize - tokenBegin) +
418 new String(buffer, 0, bufpos + 1);
419 }
420
421 public char[] GetSuffix(int len) {
422 char[] ret = new char[len];
423
424 if ((bufpos + 1) >= len)
425 System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
426 else {
427 System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
428 len - bufpos - 1);
429 System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
430 }
431
432 return ret;
433 }
434
435 public void Done() {
436 nextCharBuf = null;
437 buffer = null;
438 bufline = null;
439 bufcolumn = null;
440 }
441
442 /***
443 * Method to adjust line and column numbers for the start of a token.<BR>
444 */
445 public void adjustBeginLineColumn(int newLine, int newCol) {
446 int start = tokenBegin;
447 int len;
448
449 if (bufpos >= tokenBegin) {
450 len = bufpos - tokenBegin + inBuf + 1;
451 } else {
452 len = bufsize - tokenBegin + bufpos + 1 + inBuf;
453 }
454
455 int i = 0, j = 0, k = 0;
456 int nextColDiff = 0, columnDiff = 0;
457
458 while (i < len &&
459 bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) {
460 bufline[j] = newLine;
461 nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
462 bufcolumn[j] = newCol + columnDiff;
463 columnDiff = nextColDiff;
464 i++;
465 }
466
467 if (i < len) {
468 bufline[j] = newLine++;
469 bufcolumn[j] = newCol + columnDiff;
470
471 while (i++ < len) {
472 if (bufline[j = start % bufsize] != bufline[++start % bufsize])
473 bufline[j] = newLine++;
474 else
475 bufline[j] = newLine;
476 }
477 }
478
479 line = bufline[j];
480 column = bufcolumn[j];
481 }
482
483 }