php formatter based on the JDT java formatter (very early version)
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / Scanner.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.parser;
12
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
16
17 import net.sourceforge.phpdt.core.compiler.*;
18 import net.sourceforge.phpdt.internal.compiler.ast.StringLiteral;
19
20 public class Scanner implements IScanner, ITerminalSymbols {
21
22   /* APIs ares
23    - getNextToken() which return the current type of the token
24      (this value is not memorized by the scanner)
25    - getCurrentTokenSource() which provides with the token "REAL" source
26      (aka all unicode have been transformed into a correct char)
27    - sourceStart gives the position into the stream
28    - currentPosition-1 gives the sourceEnd position into the stream 
29   */
30
31   // 1.4 feature 
32   private boolean assertMode;
33   public boolean useAssertAsAnIndentifier = false;
34   //flag indicating if processed source contains occurrences of keyword assert 
35   public boolean containsAssertKeyword = false;
36
37   public boolean recordLineSeparator;
38   public boolean phpMode = false;
39
40   public char currentCharacter;
41   public int startPosition;
42   public int currentPosition;
43   public int initialPosition, eofPosition;
44   // after this position eof are generated instead of real token from the source
45
46   public boolean tokenizeComments;
47   public boolean tokenizeWhiteSpace;
48
49   //source should be viewed as a window (aka a part)
50   //of a entire very large stream
51   public char source[];
52
53   //unicode support
54   public char[] withoutUnicodeBuffer;
55   public int withoutUnicodePtr;
56   //when == 0 ==> no unicode in the current token
57   public boolean unicodeAsBackSlash = false;
58
59   public boolean scanningFloatLiteral = false;
60
61   //support for /** comments
62   //public char[][] comments = new char[10][];
63   public int[] commentStops = new int[10];
64   public int[] commentStarts = new int[10];
65   public int commentPtr = -1; // no comment test with commentPtr value -1
66
67   //diet parsing support - jump over some method body when requested
68   public boolean diet = false;
69
70   //support for the  poor-line-debuggers ....
71   //remember the position of the cr/lf
72   public int[] lineEnds = new int[250];
73   public int linePtr = -1;
74   public boolean wasAcr = false;
75
76   public static final String END_OF_SOURCE = "End_Of_Source"; //$NON-NLS-1$
77
78   public static final String INVALID_HEXA = "Invalid_Hexa_Literal"; //$NON-NLS-1$
79   public static final String INVALID_OCTAL = "Invalid_Octal_Literal"; //$NON-NLS-1$
80   public static final String INVALID_CHARACTER_CONSTANT = "Invalid_Character_Constant"; //$NON-NLS-1$
81   public static final String INVALID_ESCAPE = "Invalid_Escape"; //$NON-NLS-1$
82   public static final String INVALID_INPUT = "Invalid_Input"; //$NON-NLS-1$
83   public static final String INVALID_UNICODE_ESCAPE = "Invalid_Unicode_Escape"; //$NON-NLS-1$
84   public static final String INVALID_FLOAT = "Invalid_Float_Literal"; //$NON-NLS-1$
85
86   public static final String NULL_SOURCE_STRING = "Null_Source_String"; //$NON-NLS-1$
87   public static final String UNTERMINATED_STRING = "Unterminated_String"; //$NON-NLS-1$
88   public static final String UNTERMINATED_COMMENT = "Unterminated_Comment"; //$NON-NLS-1$
89   public static final String INVALID_CHAR_IN_STRING = "Invalid_Char_In_String"; //$NON-NLS-1$
90
91   //----------------optimized identifier managment------------------
92   static final char[] charArray_a = new char[] { 'a' },
93     charArray_b = new char[] { 'b' },
94     charArray_c = new char[] { 'c' },
95     charArray_d = new char[] { 'd' },
96     charArray_e = new char[] { 'e' },
97     charArray_f = new char[] { 'f' },
98     charArray_g = new char[] { 'g' },
99     charArray_h = new char[] { 'h' },
100     charArray_i = new char[] { 'i' },
101     charArray_j = new char[] { 'j' },
102     charArray_k = new char[] { 'k' },
103     charArray_l = new char[] { 'l' },
104     charArray_m = new char[] { 'm' },
105     charArray_n = new char[] { 'n' },
106     charArray_o = new char[] { 'o' },
107     charArray_p = new char[] { 'p' },
108     charArray_q = new char[] { 'q' },
109     charArray_r = new char[] { 'r' },
110     charArray_s = new char[] { 's' },
111     charArray_t = new char[] { 't' },
112     charArray_u = new char[] { 'u' },
113     charArray_v = new char[] { 'v' },
114     charArray_w = new char[] { 'w' },
115     charArray_x = new char[] { 'x' },
116     charArray_y = new char[] { 'y' },
117     charArray_z = new char[] { 'z' };
118
119   static final char[] initCharArray =
120     new char[] { '\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000' };
121   static final int TableSize = 30, InternalTableSize = 6;
122   //30*6 = 180 entries
123   public static final int OptimizedLength = 6;
124   public /*static*/
125   final char[][][][] charArray_length =
126     new char[OptimizedLength][TableSize][InternalTableSize][];
127   // support for detecting non-externalized string literals
128   int currentLineNr = -1;
129   int previousLineNr = -1;
130   NLSLine currentLine = null;
131   List lines = new ArrayList();
132   public static final String TAG_PREFIX = "//$NON-NLS-"; //$NON-NLS-1$
133   public static final int TAG_PREFIX_LENGTH = TAG_PREFIX.length();
134   public static final String TAG_POSTFIX = "$"; //$NON-NLS-1$
135   public static final int TAG_POSTFIX_LENGTH = TAG_POSTFIX.length();
136   public StringLiteral[] nonNLSStrings = null;
137   public boolean checkNonExternalizedStringLiterals = true;
138   public boolean wasNonExternalizedStringLiteral = false;
139
140   /*static*/ {
141     for (int i = 0; i < 6; i++) {
142       for (int j = 0; j < TableSize; j++) {
143         for (int k = 0; k < InternalTableSize; k++) {
144           charArray_length[i][j][k] = initCharArray;
145         }
146       }
147     }
148   }
149   static int newEntry2 = 0,
150     newEntry3 = 0,
151     newEntry4 = 0,
152     newEntry5 = 0,
153     newEntry6 = 0;
154
155   public static final int RoundBracket = 0;
156   public static final int SquareBracket = 1;
157   public static final int CurlyBracket = 2;
158   public static final int BracketKinds = 3;
159
160   public static final boolean DEBUG = false;
161   public Scanner() {
162     this(false, false);
163   }
164   public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace) {
165     this(tokenizeComments, tokenizeWhiteSpace, false);
166   }
167
168   /**
169    * Determines if the specified character is
170    * permissible as the first character in a PHP identifier
171    */
172   public static boolean isPHPIdentifierStart(char ch) {
173     return Character.isLetter(ch) || (ch == '_');
174   }
175
176   /**
177    * Determines if the specified character may be part of a PHP identifier as
178    * other than the first character
179    */
180   public static boolean isPHPIdentifierPart(char ch) {
181     return Character.isLetterOrDigit(ch) || (ch == '_');
182   }
183
184   public final boolean atEnd() {
185     // This code is not relevant if source is 
186     // Only a part of the real stream input
187
188     return source.length == currentPosition;
189   }
190   public char[] getCurrentIdentifierSource() {
191     //return the token REAL source (aka unicodes are precomputed)
192
193     char[] result;
194     if (withoutUnicodePtr != 0)
195       //0 is used as a fast test flag so the real first char is in position 1
196       System.arraycopy(
197         withoutUnicodeBuffer,
198         1,
199         result = new char[withoutUnicodePtr],
200         0,
201         withoutUnicodePtr);
202     else {
203       int length = currentPosition - startPosition;
204       switch (length) { // see OptimizedLength
205         case 1 :
206           return optimizedCurrentTokenSource1();
207         case 2 :
208           return optimizedCurrentTokenSource2();
209         case 3 :
210           return optimizedCurrentTokenSource3();
211         case 4 :
212           return optimizedCurrentTokenSource4();
213         case 5 :
214           return optimizedCurrentTokenSource5();
215         case 6 :
216           return optimizedCurrentTokenSource6();
217       }
218       //no optimization
219       System.arraycopy(
220         source,
221         startPosition,
222         result = new char[length],
223         0,
224         length);
225     }
226     return result;
227   }
228   public int getCurrentTokenEndPosition() {
229     return this.currentPosition - 1;
230   }
231   public final char[] getCurrentTokenSource() {
232     // Return the token REAL source (aka unicodes are precomputed)
233
234     char[] result;
235     if (withoutUnicodePtr != 0)
236       // 0 is used as a fast test flag so the real first char is in position 1
237       System.arraycopy(
238         withoutUnicodeBuffer,
239         1,
240         result = new char[withoutUnicodePtr],
241         0,
242         withoutUnicodePtr);
243     else {
244       int length;
245       System.arraycopy(
246         source,
247         startPosition,
248         result = new char[length = currentPosition - startPosition],
249         0,
250         length);
251     }
252     return result;
253   }
254
255   public final char[] getCurrentTokenSource(int startPos) {
256     // Return the token REAL source (aka unicodes are precomputed)
257
258     char[] result;
259     if (withoutUnicodePtr != 0)
260       // 0 is used as a fast test flag so the real first char is in position 1
261       System.arraycopy(
262         withoutUnicodeBuffer,
263         1,
264         result = new char[withoutUnicodePtr],
265         0,
266         withoutUnicodePtr);
267     else {
268       int length;
269       System.arraycopy(
270         source,
271         startPos,
272         result = new char[length = currentPosition - startPos],
273         0,
274         length);
275     }
276     return result;
277   }
278
279   public final char[] getCurrentTokenSourceString() {
280     //return the token REAL source (aka unicodes are precomputed).
281     //REMOVE the two " that are at the beginning and the end.
282
283     char[] result;
284     if (withoutUnicodePtr != 0)
285       //0 is used as a fast test flag so the real first char is in position 1
286       System.arraycopy(withoutUnicodeBuffer, 2,
287       //2 is 1 (real start) + 1 (to jump over the ")
288       result = new char[withoutUnicodePtr - 2], 0, withoutUnicodePtr - 2);
289     else {
290       int length;
291       System.arraycopy(
292         source,
293         startPosition + 1,
294         result = new char[length = currentPosition - startPosition - 2],
295         0,
296         length);
297     }
298     return result;
299   }
300   public int getCurrentTokenStartPosition() {
301     return this.startPosition;
302   }
303   /*
304    * Search the source position corresponding to the end of a given line number
305    *
306    * Line numbers are 1-based, and relative to the scanner initialPosition. 
307    * Character positions are 0-based.
308    *
309    * In case the given line number is inconsistent, answers -1.
310    */
311   public final int getLineEnd(int lineNumber) {
312
313     if (lineEnds == null)
314       return -1;
315     if (lineNumber >= lineEnds.length)
316       return -1;
317     if (lineNumber <= 0)
318       return -1;
319
320     if (lineNumber == lineEnds.length - 1)
321       return eofPosition;
322     return lineEnds[lineNumber - 1];
323     // next line start one character behind the lineEnd of the previous line
324   }
325   /**
326    * Search the source position corresponding to the beginning of a given line number
327    *
328    * Line numbers are 1-based, and relative to the scanner initialPosition. 
329    * Character positions are 0-based.
330    *
331    * e.g.       getLineStart(1) --> 0   i.e. first line starts at character 0.
332    *
333    * In case the given line number is inconsistent, answers -1.
334    */
335   public final int getLineStart(int lineNumber) {
336
337     if (lineEnds == null)
338       return -1;
339     if (lineNumber >= lineEnds.length)
340       return -1;
341     if (lineNumber <= 0)
342       return -1;
343
344     if (lineNumber == 1)
345       return initialPosition;
346     return lineEnds[lineNumber - 2] + 1;
347     // next line start one character behind the lineEnd of the previous line
348   }
349   public final boolean getNextChar(char testedChar) {
350     //BOOLEAN
351     //handle the case of unicode.
352     //when a unicode appears then we must use a buffer that holds char internal values
353     //At the end of this method currentCharacter holds the new visited char
354     //and currentPosition points right next after it
355     //Both previous lines are true if the currentCharacter is == to the testedChar
356     //On false, no side effect has occured.
357
358     //ALL getNextChar.... ARE OPTIMIZED COPIES 
359
360     int temp = currentPosition;
361     try {
362       if (((currentCharacter = source[currentPosition++]) == '\\')
363         && (source[currentPosition] == 'u')) {
364         //-------------unicode traitement ------------
365         int c1, c2, c3, c4;
366         int unicodeSize = 6;
367         currentPosition++;
368         while (source[currentPosition] == 'u') {
369           currentPosition++;
370           unicodeSize++;
371         }
372
373         if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
374           || c1 < 0)
375           || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
376             || c2 < 0)
377           || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
378             || c3 < 0)
379           || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
380             || c4 < 0)) {
381           currentPosition = temp;
382           return false;
383         }
384
385         currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
386         if (currentCharacter != testedChar) {
387           currentPosition = temp;
388           return false;
389         }
390         unicodeAsBackSlash = currentCharacter == '\\';
391
392         //need the unicode buffer
393         if (withoutUnicodePtr == 0) {
394           //buffer all the entries that have been left aside....
395           withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
396           System.arraycopy(
397             source,
398             startPosition,
399             withoutUnicodeBuffer,
400             1,
401             withoutUnicodePtr);
402         }
403         //fill the buffer with the char
404         withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
405         return true;
406
407       } //-------------end unicode traitement--------------
408       else {
409         if (currentCharacter != testedChar) {
410           currentPosition = temp;
411           return false;
412         }
413         unicodeAsBackSlash = false;
414         if (withoutUnicodePtr != 0)
415           withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
416         return true;
417       }
418     } catch (IndexOutOfBoundsException e) {
419       unicodeAsBackSlash = false;
420       currentPosition = temp;
421       return false;
422     }
423   }
424   public final int getNextChar(char testedChar1, char testedChar2) {
425     //INT 0 : testChar1 \\\\///\\\\ 1 : testedChar2 \\\\///\\\\ -1 : others
426     //test can be done with (x==0) for the first and (x>0) for the second
427     //handle the case of unicode.
428     //when a unicode appears then we must use a buffer that holds char internal values
429     //At the end of this method currentCharacter holds the new visited char
430     //and currentPosition points right next after it
431     //Both previous lines are true if the currentCharacter is == to the testedChar1/2
432     //On false, no side effect has occured.
433
434     //ALL getNextChar.... ARE OPTIMIZED COPIES 
435
436     int temp = currentPosition;
437     try {
438       int result;
439       if (((currentCharacter = source[currentPosition++]) == '\\')
440         && (source[currentPosition] == 'u')) {
441         //-------------unicode traitement ------------
442         int c1, c2, c3, c4;
443         int unicodeSize = 6;
444         currentPosition++;
445         while (source[currentPosition] == 'u') {
446           currentPosition++;
447           unicodeSize++;
448         }
449
450         if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
451           || c1 < 0)
452           || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
453             || c2 < 0)
454           || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
455             || c3 < 0)
456           || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
457             || c4 < 0)) {
458           currentPosition = temp;
459           return 2;
460         }
461
462         currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
463         if (currentCharacter == testedChar1)
464           result = 0;
465         else if (currentCharacter == testedChar2)
466           result = 1;
467         else {
468           currentPosition = temp;
469           return -1;
470         }
471
472         //need the unicode buffer
473         if (withoutUnicodePtr == 0) {
474           //buffer all the entries that have been left aside....
475           withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
476           System.arraycopy(
477             source,
478             startPosition,
479             withoutUnicodeBuffer,
480             1,
481             withoutUnicodePtr);
482         }
483         //fill the buffer with the char
484         withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
485         return result;
486       } //-------------end unicode traitement--------------
487       else {
488         if (currentCharacter == testedChar1)
489           result = 0;
490         else if (currentCharacter == testedChar2)
491           result = 1;
492         else {
493           currentPosition = temp;
494           return -1;
495         }
496
497         if (withoutUnicodePtr != 0)
498           withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
499         return result;
500       }
501     } catch (IndexOutOfBoundsException e) {
502       currentPosition = temp;
503       return -1;
504     }
505   }
506   public final boolean getNextCharAsDigit() {
507     //BOOLEAN
508     //handle the case of unicode.
509     //when a unicode appears then we must use a buffer that holds char internal values
510     //At the end of this method currentCharacter holds the new visited char
511     //and currentPosition points right next after it
512     //Both previous lines are true if the currentCharacter is a digit
513     //On false, no side effect has occured.
514
515     //ALL getNextChar.... ARE OPTIMIZED COPIES 
516
517     int temp = currentPosition;
518     try {
519       if (((currentCharacter = source[currentPosition++]) == '\\')
520         && (source[currentPosition] == 'u')) {
521         //-------------unicode traitement ------------
522         int c1, c2, c3, c4;
523         int unicodeSize = 6;
524         currentPosition++;
525         while (source[currentPosition] == 'u') {
526           currentPosition++;
527           unicodeSize++;
528         }
529
530         if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
531           || c1 < 0)
532           || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
533             || c2 < 0)
534           || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
535             || c3 < 0)
536           || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
537             || c4 < 0)) {
538           currentPosition = temp;
539           return false;
540         }
541
542         currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
543         if (!Character.isDigit(currentCharacter)) {
544           currentPosition = temp;
545           return false;
546         }
547
548         //need the unicode buffer
549         if (withoutUnicodePtr == 0) {
550           //buffer all the entries that have been left aside....
551           withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
552           System.arraycopy(
553             source,
554             startPosition,
555             withoutUnicodeBuffer,
556             1,
557             withoutUnicodePtr);
558         }
559         //fill the buffer with the char
560         withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
561         return true;
562       } //-------------end unicode traitement--------------
563       else {
564         if (!Character.isDigit(currentCharacter)) {
565           currentPosition = temp;
566           return false;
567         }
568         if (withoutUnicodePtr != 0)
569           withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
570         return true;
571       }
572     } catch (IndexOutOfBoundsException e) {
573       currentPosition = temp;
574       return false;
575     }
576   }
577   public final boolean getNextCharAsDigit(int radix) {
578     //BOOLEAN
579     //handle the case of unicode.
580     //when a unicode appears then we must use a buffer that holds char internal values
581     //At the end of this method currentCharacter holds the new visited char
582     //and currentPosition points right next after it
583     //Both previous lines are true if the currentCharacter is a digit base on radix
584     //On false, no side effect has occured.
585
586     //ALL getNextChar.... ARE OPTIMIZED COPIES 
587
588     int temp = currentPosition;
589     try {
590       if (((currentCharacter = source[currentPosition++]) == '\\')
591         && (source[currentPosition] == 'u')) {
592         //-------------unicode traitement ------------
593         int c1, c2, c3, c4;
594         int unicodeSize = 6;
595         currentPosition++;
596         while (source[currentPosition] == 'u') {
597           currentPosition++;
598           unicodeSize++;
599         }
600
601         if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
602           || c1 < 0)
603           || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
604             || c2 < 0)
605           || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
606             || c3 < 0)
607           || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
608             || c4 < 0)) {
609           currentPosition = temp;
610           return false;
611         }
612
613         currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
614         if (Character.digit(currentCharacter, radix) == -1) {
615           currentPosition = temp;
616           return false;
617         }
618
619         //need the unicode buffer
620         if (withoutUnicodePtr == 0) {
621           //buffer all the entries that have been left aside....
622           withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
623           System.arraycopy(
624             source,
625             startPosition,
626             withoutUnicodeBuffer,
627             1,
628             withoutUnicodePtr);
629         }
630         //fill the buffer with the char
631         withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
632         return true;
633       } //-------------end unicode traitement--------------
634       else {
635         if (Character.digit(currentCharacter, radix) == -1) {
636           currentPosition = temp;
637           return false;
638         }
639         if (withoutUnicodePtr != 0)
640           withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
641         return true;
642       }
643     } catch (IndexOutOfBoundsException e) {
644       currentPosition = temp;
645       return false;
646     }
647   }
648   public boolean getNextCharAsJavaIdentifierPart() {
649     //BOOLEAN
650     //handle the case of unicode.
651     //when a unicode appears then we must use a buffer that holds char internal values
652     //At the end of this method currentCharacter holds the new visited char
653     //and currentPosition points right next after it
654     //Both previous lines are true if the currentCharacter is a JavaIdentifierPart
655     //On false, no side effect has occured.
656
657     //ALL getNextChar.... ARE OPTIMIZED COPIES 
658
659     int temp = currentPosition;
660     try {
661       if (((currentCharacter = source[currentPosition++]) == '\\')
662         && (source[currentPosition] == 'u')) {
663         //-------------unicode traitement ------------
664         int c1, c2, c3, c4;
665         int unicodeSize = 6;
666         currentPosition++;
667         while (source[currentPosition] == 'u') {
668           currentPosition++;
669           unicodeSize++;
670         }
671
672         if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
673           || c1 < 0)
674           || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
675             || c2 < 0)
676           || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
677             || c3 < 0)
678           || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
679             || c4 < 0)) {
680           currentPosition = temp;
681           return false;
682         }
683
684         currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
685         if (!isPHPIdentifierPart(currentCharacter)) {
686           currentPosition = temp;
687           return false;
688         }
689
690         //need the unicode buffer
691         if (withoutUnicodePtr == 0) {
692           //buffer all the entries that have been left aside....
693           withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
694           System.arraycopy(
695             source,
696             startPosition,
697             withoutUnicodeBuffer,
698             1,
699             withoutUnicodePtr);
700         }
701         //fill the buffer with the char
702         withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
703         return true;
704       } //-------------end unicode traitement--------------
705       else {
706         if (!isPHPIdentifierPart(currentCharacter)) {
707           currentPosition = temp;
708           return false;
709         }
710
711         if (withoutUnicodePtr != 0)
712           withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
713         return true;
714       }
715     } catch (IndexOutOfBoundsException e) {
716       currentPosition = temp;
717       return false;
718     }
719   }
720
721   public int getNextToken() throws InvalidInputException {
722
723     try {
724       int htmlPosition = currentPosition;
725       while (!phpMode) {
726         currentCharacter = source[currentPosition++];
727         if (currentCharacter == '<') {
728           if (getNextChar('?')) {
729             currentCharacter = source[currentPosition++];
730             if ((currentCharacter == ' ')
731               || Character.isWhitespace(currentCharacter)) {
732               // <?
733               startPosition = currentPosition;
734               phpMode = true;
735               if (tokenizeWhiteSpace) {
736                 // && (whiteStart != currentPosition - 1)) {
737                 // reposition scanner in case we are interested by spaces as tokens
738                 startPosition = htmlPosition;
739                 return TokenNameHTML;
740               }
741             } else {
742               boolean phpStart =
743                 (currentCharacter == 'P') || (currentCharacter == 'p');
744               if (phpStart) {
745                 int test = getNextChar('H', 'h');
746                 if (test >= 0) {
747                   test = getNextChar('P', 'p');
748                   if (test >= 0) {
749                     // <?PHP  <?php
750                     startPosition = currentPosition;
751                     phpMode = true;
752
753                     if (tokenizeWhiteSpace) {
754                       // && (whiteStart != currentPosition - 1)) {
755                       // reposition scanner in case we are interested by spaces as tokens
756                       startPosition = htmlPosition;
757                       return TokenNameHTML;
758                     }
759                   }
760                 }
761               }
762             }
763           }
764         }
765
766         if ((currentCharacter == '\r') || (currentCharacter == '\n')) {
767           if (recordLineSeparator) {
768             pushLineSeparator();
769           } else {
770             currentLine = null;
771           }
772         }
773       }
774     } //-----------------end switch while try--------------------
775     catch (IndexOutOfBoundsException e) {
776       return TokenNameEOF;
777     }
778
779     if (phpMode) {
780       this.wasAcr = false;
781       if (diet) {
782         jumpOverMethodBody();
783         diet = false;
784         return currentPosition > source.length ? TokenNameEOF : TokenNameRBRACE;
785       }
786       try {
787         while (true) { //loop for jumping over comments
788           withoutUnicodePtr = 0;
789           //start with a new token (even comment written with unicode )
790
791           // ---------Consume white space and handles startPosition---------
792           int whiteStart = currentPosition;
793           boolean isWhiteSpace;
794           do {
795             startPosition = currentPosition;
796             if (((currentCharacter = source[currentPosition++]) == '\\')
797               && (source[currentPosition] == 'u')) {
798               isWhiteSpace = jumpOverUnicodeWhiteSpace();
799             } else {
800               if ((currentCharacter == '\r') || (currentCharacter == '\n')) {
801                 checkNonExternalizeString();
802                 if (recordLineSeparator) {
803                   pushLineSeparator();
804                 } else {
805                   currentLine = null;
806                 }
807               }
808               isWhiteSpace =
809                 (currentCharacter == ' ')
810                   || Character.isWhitespace(currentCharacter);
811             }
812           } while (isWhiteSpace);
813           if (tokenizeWhiteSpace && (whiteStart != currentPosition - 1)) {
814             // reposition scanner in case we are interested by spaces as tokens
815             currentPosition--;
816             startPosition = whiteStart;
817             return TokenNameWHITESPACE;
818           }
819           //little trick to get out in the middle of a source compuation
820           if (currentPosition > eofPosition)
821             return TokenNameEOF;
822
823           // ---------Identify the next token-------------
824
825           switch (currentCharacter) {
826             case '(' :
827               return TokenNameLPAREN;
828             case ')' :
829               return TokenNameRPAREN;
830             case '{' :
831               return TokenNameLBRACE;
832             case '}' :
833               return TokenNameRBRACE;
834             case '[' :
835               return TokenNameLBRACKET;
836             case ']' :
837               return TokenNameRBRACKET;
838             case ';' :
839               return TokenNameSEMICOLON;
840             case ',' :
841               return TokenNameCOMMA;
842
843             case '.' :
844               if (getNextCharAsDigit())
845                 return scanNumber(true);
846               return TokenNameDOT;
847             case '+' :
848               {
849                 int test;
850                 if ((test = getNextChar('+', '=')) == 0)
851                   return TokenNamePLUS_PLUS;
852                 if (test > 0)
853                   return TokenNamePLUS_EQUAL;
854                 return TokenNamePLUS;
855               }
856             case '-' :
857               {
858                 int test;
859                 if ((test = getNextChar('-', '=')) == 0)
860                   return TokenNameMINUS_MINUS;
861                 if (test > 0)
862                   return TokenNameMINUS_EQUAL;
863                 if (getNextChar('>'))
864                   return TokenNameMINUS_GREATER;
865
866                 return TokenNameMINUS;
867               }
868             case '~' :
869               if (getNextChar('='))
870                 return TokenNameTWIDDLE_EQUAL;
871               return TokenNameTWIDDLE;
872             case '!' :
873               if (getNextChar('='))
874                 return TokenNameNOT_EQUAL;
875               return TokenNameNOT;
876             case '*' :
877               if (getNextChar('='))
878                 return TokenNameMULTIPLY_EQUAL;
879               return TokenNameMULTIPLY;
880             case '%' :
881               if (getNextChar('='))
882                 return TokenNameREMAINDER_EQUAL;
883               return TokenNameREMAINDER;
884             case '<' :
885               {
886                 int test;
887                 if ((test = getNextChar('=', '<')) == 0)
888                   return TokenNameLESS_EQUAL;
889                 if (test > 0) {
890                   if (getNextChar('='))
891                     return TokenNameLEFT_SHIFT_EQUAL;
892                   if (getNextChar('<')) {
893                     int heredocStart = currentPosition;
894                     int heredocLength = 0;
895                     currentCharacter = source[currentPosition++];
896                     if (isPHPIdentifierStart(currentCharacter)) {
897                       currentCharacter = source[currentPosition++];
898                     } else {
899                       return TokenNameERROR;
900                     }
901                     while (isPHPIdentifierPart(currentCharacter)) {
902                       currentCharacter = source[currentPosition++];
903                     }
904
905                     heredocLength = currentPosition - heredocStart - 1;
906
907                     // heredoc end-tag determination
908                     boolean endTag = true;
909                     char ch;
910                     do {
911                       ch = source[currentPosition++];
912                       if (ch == '\r' || ch == '\n') {
913                         if (recordLineSeparator) {
914                           pushLineSeparator();
915                         } else {
916                           currentLine = null;
917                         }
918                         for (int i = 0; i < heredocLength; i++) {
919                           if (source[currentPosition + i]
920                             != source[heredocStart + i]) {
921                             endTag = false;
922                             break;
923                           }
924                         }
925                         if (endTag) {
926                           currentPosition += heredocLength - 1;
927                           currentCharacter = source[currentPosition++];
928                           break; // do...while loop
929                         } else {
930                           endTag = true;
931                         }
932                       }
933
934                     } while (true);
935
936                     return TokenNameHEREDOC;
937                   }
938                   return TokenNameLEFT_SHIFT;
939                 }
940                 return TokenNameLESS;
941               }
942             case '>' :
943               {
944                 int test;
945                 if ((test = getNextChar('=', '>')) == 0)
946                   return TokenNameGREATER_EQUAL;
947                 if (test > 0) {
948                   if ((test = getNextChar('=', '>')) == 0)
949                     return TokenNameRIGHT_SHIFT_EQUAL;
950                   return TokenNameRIGHT_SHIFT;
951                 }
952                 return TokenNameGREATER;
953               }
954             case '=' :
955               if (getNextChar('='))
956                 return TokenNameEQUAL_EQUAL;
957               if (getNextChar('>'))
958                 return TokenNameEQUAL_GREATER;
959               return TokenNameEQUAL;
960             case '&' :
961               {
962                 int test;
963                 if ((test = getNextChar('&', '=')) == 0)
964                   return TokenNameAND_AND;
965                 if (test > 0)
966                   return TokenNameAND_EQUAL;
967                 return TokenNameAND;
968               }
969             case '|' :
970               {
971                 int test;
972                 if ((test = getNextChar('|', '=')) == 0)
973                   return TokenNameOR_OR;
974                 if (test > 0)
975                   return TokenNameOR_EQUAL;
976                 return TokenNameOR;
977               }
978             case '^' :
979               if (getNextChar('='))
980                 return TokenNameXOR_EQUAL;
981               return TokenNameXOR;
982             case '?' :
983               if (getNextChar('>')) {
984                 phpMode = false;
985                 return TokenNameStopPHP;
986               }
987               return TokenNameQUESTION;
988             case ':' :
989               if (getNextChar(':'))
990                 return TokenNameCOLON_COLON;
991               return TokenNameCOLON;
992             case '@' :
993               return TokenNameAT;
994               //                                        case '\'' :
995               //                                                {
996               //                                                        int test;
997               //                                                        if ((test = getNextChar('\n', '\r')) == 0) {
998               //                                                                throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
999               //                                                        }
1000               //                                                        if (test > 0) {
1001               //                                                                // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1002               //                                                                for (int lookAhead = 0;
1003               //                                                                        lookAhead < 3;
1004               //                                                                        lookAhead++) {
1005               //                                                                        if (currentPosition + lookAhead
1006               //                                                                                == source.length)
1007               //                                                                                break;
1008               //                                                                        if (source[currentPosition + lookAhead]
1009               //                                                                                == '\n')
1010               //                                                                                break;
1011               //                                                                        if (source[currentPosition + lookAhead]
1012               //                                                                                == '\'') {
1013               //                                                                                currentPosition += lookAhead + 1;
1014               //                                                                                break;
1015               //                                                                        }
1016               //                                                                }
1017               //                                                                throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
1018               //                                                        }
1019               //                                                }
1020               //                                                if (getNextChar('\'')) {
1021               //                                                        // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1022               //                                                        for (int lookAhead = 0;
1023               //                                                                lookAhead < 3;
1024               //                                                                lookAhead++) {
1025               //                                                                if (currentPosition + lookAhead
1026               //                                                                        == source.length)
1027               //                                                                        break;
1028               //                                                                if (source[currentPosition + lookAhead]
1029               //                                                                        == '\n')
1030               //                                                                        break;
1031               //                                                                if (source[currentPosition + lookAhead]
1032               //                                                                        == '\'') {
1033               //                                                                        currentPosition += lookAhead + 1;
1034               //                                                                        break;
1035               //                                                                }
1036               //                                                        }
1037               //                                                        throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
1038               //                                                }
1039               //                                                if (getNextChar('\\'))
1040               //                                                        scanEscapeCharacter();
1041               //                                                else { // consume next character
1042               //                                                        unicodeAsBackSlash = false;
1043               //                                                        if (((currentCharacter = source[currentPosition++])
1044               //                                                                == '\\')
1045               //                                                                && (source[currentPosition] == 'u')) {
1046               //                                                                getNextUnicodeChar();
1047               //                                                        } else {
1048               //                                                                if (withoutUnicodePtr != 0) {
1049               //                                                                        withoutUnicodeBuffer[++withoutUnicodePtr] =
1050               //                                                                                currentCharacter;
1051               //                                                                }
1052               //                                                        }
1053               //                                                }
1054               //                                                //            if (getNextChar('\''))
1055               //                                                //              return TokenNameCharacterLiteral;
1056               //                                                // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1057               //                                                for (int lookAhead = 0; lookAhead < 20; lookAhead++) {
1058               //                                                        if (currentPosition + lookAhead == source.length)
1059               //                                                                break;
1060               //                                                        if (source[currentPosition + lookAhead] == '\n')
1061               //                                                                break;
1062               //                                                        if (source[currentPosition + lookAhead] == '\'') {
1063               //                                                                currentPosition += lookAhead + 1;
1064               //                                                                break;
1065               //                                                        }
1066               //                                                }
1067               //                                                throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
1068             case '\'' :
1069               try {
1070                 // consume next character
1071                 unicodeAsBackSlash = false;
1072                 if (((currentCharacter = source[currentPosition++]) == '\\')
1073                   && (source[currentPosition] == 'u')) {
1074                   getNextUnicodeChar();
1075                 } else {
1076                   if (withoutUnicodePtr != 0) {
1077                     withoutUnicodeBuffer[++withoutUnicodePtr] =
1078                       currentCharacter;
1079                   }
1080                 }
1081
1082                 while (currentCharacter != '\'') {
1083
1084                   /**** in PHP \r and \n are valid in string literals ****/
1085                   //                  if ((currentCharacter == '\n')
1086                   //                    || (currentCharacter == '\r')) {
1087                   //                    // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1088                   //                    for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1089                   //                      if (currentPosition + lookAhead == source.length)
1090                   //                        break;
1091                   //                      if (source[currentPosition + lookAhead] == '\n')
1092                   //                        break;
1093                   //                      if (source[currentPosition + lookAhead] == '\"') {
1094                   //                        currentPosition += lookAhead + 1;
1095                   //                        break;
1096                   //                      }
1097                   //                    }
1098                   //                    throw new InvalidInputException(INVALID_CHAR_IN_STRING);
1099                   //                  }
1100                   if (currentCharacter == '\\') {
1101                     int escapeSize = currentPosition;
1102                     boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
1103                     //scanEscapeCharacter make a side effect on this value and we need the previous value few lines down this one
1104                     scanSingleQuotedEscapeCharacter();
1105                     escapeSize = currentPosition - escapeSize;
1106                     if (withoutUnicodePtr == 0) {
1107                       //buffer all the entries that have been left aside....
1108                       withoutUnicodePtr =
1109                         currentPosition - escapeSize - 1 - startPosition;
1110                       System.arraycopy(
1111                         source,
1112                         startPosition,
1113                         withoutUnicodeBuffer,
1114                         1,
1115                         withoutUnicodePtr);
1116                       withoutUnicodeBuffer[++withoutUnicodePtr] =
1117                         currentCharacter;
1118                     } else { //overwrite the / in the buffer
1119                       withoutUnicodeBuffer[withoutUnicodePtr] =
1120                         currentCharacter;
1121                       if (backSlashAsUnicodeInString) { //there are TWO \ in the stream where only one is correct
1122                         withoutUnicodePtr--;
1123                       }
1124                     }
1125                   }
1126                   // consume next character
1127                   unicodeAsBackSlash = false;
1128                   if (((currentCharacter = source[currentPosition++]) == '\\')
1129                     && (source[currentPosition] == 'u')) {
1130                     getNextUnicodeChar();
1131                   } else {
1132                     if (withoutUnicodePtr != 0) {
1133                       withoutUnicodeBuffer[++withoutUnicodePtr] =
1134                         currentCharacter;
1135                     }
1136                   }
1137
1138                 }
1139               } catch (IndexOutOfBoundsException e) {
1140                 throw new InvalidInputException(UNTERMINATED_STRING);
1141               } catch (InvalidInputException e) {
1142                 if (e.getMessage().equals(INVALID_ESCAPE)) {
1143                   // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1144                   for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1145                     if (currentPosition + lookAhead == source.length)
1146                       break;
1147                     if (source[currentPosition + lookAhead] == '\n')
1148                       break;
1149                     if (source[currentPosition + lookAhead] == '\'') {
1150                       currentPosition += lookAhead + 1;
1151                       break;
1152                     }
1153                   }
1154
1155                 }
1156                 throw e; // rethrow
1157               }
1158               if (checkNonExternalizedStringLiterals) { // check for presence of        NLS tags //$NON-NLS-?$ where ? is an int.
1159                 if (currentLine == null) {
1160                   currentLine = new NLSLine();
1161                   lines.add(currentLine);
1162                 }
1163                 currentLine.add(
1164                   new StringLiteral(
1165                     getCurrentTokenSourceString(),
1166                     startPosition,
1167                     currentPosition - 1));
1168               }
1169               return TokenNameStringConstant;
1170             case '"' :
1171               try {
1172                 // consume next character
1173                 unicodeAsBackSlash = false;
1174                 if (((currentCharacter = source[currentPosition++]) == '\\')
1175                   && (source[currentPosition] == 'u')) {
1176                   getNextUnicodeChar();
1177                 } else {
1178                   if (withoutUnicodePtr != 0) {
1179                     withoutUnicodeBuffer[++withoutUnicodePtr] =
1180                       currentCharacter;
1181                   }
1182                 }
1183
1184                 while (currentCharacter != '"') {
1185
1186                   /**** in PHP \r and \n are valid in string literals ****/
1187                   //                  if ((currentCharacter == '\n')
1188                   //                    || (currentCharacter == '\r')) {
1189                   //                    // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1190                   //                    for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1191                   //                      if (currentPosition + lookAhead == source.length)
1192                   //                        break;
1193                   //                      if (source[currentPosition + lookAhead] == '\n')
1194                   //                        break;
1195                   //                      if (source[currentPosition + lookAhead] == '\"') {
1196                   //                        currentPosition += lookAhead + 1;
1197                   //                        break;
1198                   //                      }
1199                   //                    }
1200                   //                    throw new InvalidInputException(INVALID_CHAR_IN_STRING);
1201                   //                  }
1202                   if (currentCharacter == '\\') {
1203                     int escapeSize = currentPosition;
1204                     boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
1205                     //scanEscapeCharacter make a side effect on this value and we need the previous value few lines down this one
1206                     scanDoubleQuotedEscapeCharacter();
1207                     escapeSize = currentPosition - escapeSize;
1208                     if (withoutUnicodePtr == 0) {
1209                       //buffer all the entries that have been left aside....
1210                       withoutUnicodePtr =
1211                         currentPosition - escapeSize - 1 - startPosition;
1212                       System.arraycopy(
1213                         source,
1214                         startPosition,
1215                         withoutUnicodeBuffer,
1216                         1,
1217                         withoutUnicodePtr);
1218                       withoutUnicodeBuffer[++withoutUnicodePtr] =
1219                         currentCharacter;
1220                     } else { //overwrite the / in the buffer
1221                       withoutUnicodeBuffer[withoutUnicodePtr] =
1222                         currentCharacter;
1223                       if (backSlashAsUnicodeInString) { //there are TWO \ in the stream where only one is correct
1224                         withoutUnicodePtr--;
1225                       }
1226                     }
1227                   }
1228                   // consume next character
1229                   unicodeAsBackSlash = false;
1230                   if (((currentCharacter = source[currentPosition++]) == '\\')
1231                     && (source[currentPosition] == 'u')) {
1232                     getNextUnicodeChar();
1233                   } else {
1234                     if (withoutUnicodePtr != 0) {
1235                       withoutUnicodeBuffer[++withoutUnicodePtr] =
1236                         currentCharacter;
1237                     }
1238                   }
1239
1240                 }
1241               } catch (IndexOutOfBoundsException e) {
1242                 throw new InvalidInputException(UNTERMINATED_STRING);
1243               } catch (InvalidInputException e) {
1244                 if (e.getMessage().equals(INVALID_ESCAPE)) {
1245                   // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1246                   for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1247                     if (currentPosition + lookAhead == source.length)
1248                       break;
1249                     if (source[currentPosition + lookAhead] == '\n')
1250                       break;
1251                     if (source[currentPosition + lookAhead] == '\"') {
1252                       currentPosition += lookAhead + 1;
1253                       break;
1254                     }
1255                   }
1256
1257                 }
1258                 throw e; // rethrow
1259               }
1260               if (checkNonExternalizedStringLiterals) { // check for presence of        NLS tags //$NON-NLS-?$ where ? is an int.
1261                 if (currentLine == null) {
1262                   currentLine = new NLSLine();
1263                   lines.add(currentLine);
1264                 }
1265                 currentLine.add(
1266                   new StringLiteral(
1267                     getCurrentTokenSourceString(),
1268                     startPosition,
1269                     currentPosition - 1));
1270               }
1271               return TokenNameStringLiteral;
1272             case '`' :
1273               try {
1274                 // consume next character
1275                 unicodeAsBackSlash = false;
1276                 if (((currentCharacter = source[currentPosition++]) == '\\')
1277                   && (source[currentPosition] == 'u')) {
1278                   getNextUnicodeChar();
1279                 } else {
1280                   if (withoutUnicodePtr != 0) {
1281                     withoutUnicodeBuffer[++withoutUnicodePtr] =
1282                       currentCharacter;
1283                   }
1284                 }
1285
1286                 while (currentCharacter != '`') {
1287
1288                   /**** in PHP \r and \n are valid in string literals ****/
1289                   //                if ((currentCharacter == '\n')
1290                   //                  || (currentCharacter == '\r')) {
1291                   //                  // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1292                   //                  for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1293                   //                    if (currentPosition + lookAhead == source.length)
1294                   //                      break;
1295                   //                    if (source[currentPosition + lookAhead] == '\n')
1296                   //                      break;
1297                   //                    if (source[currentPosition + lookAhead] == '\"') {
1298                   //                      currentPosition += lookAhead + 1;
1299                   //                      break;
1300                   //                    }
1301                   //                  }
1302                   //                  throw new InvalidInputException(INVALID_CHAR_IN_STRING);
1303                   //                }
1304                   if (currentCharacter == '\\') {
1305                     int escapeSize = currentPosition;
1306                     boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
1307                     //scanEscapeCharacter make a side effect on this value and we need the previous value few lines down this one
1308                     scanDoubleQuotedEscapeCharacter();
1309                     escapeSize = currentPosition - escapeSize;
1310                     if (withoutUnicodePtr == 0) {
1311                       //buffer all the entries that have been left aside....
1312                       withoutUnicodePtr =
1313                         currentPosition - escapeSize - 1 - startPosition;
1314                       System.arraycopy(
1315                         source,
1316                         startPosition,
1317                         withoutUnicodeBuffer,
1318                         1,
1319                         withoutUnicodePtr);
1320                       withoutUnicodeBuffer[++withoutUnicodePtr] =
1321                         currentCharacter;
1322                     } else { //overwrite the / in the buffer
1323                       withoutUnicodeBuffer[withoutUnicodePtr] =
1324                         currentCharacter;
1325                       if (backSlashAsUnicodeInString) { //there are TWO \ in the stream where only one is correct
1326                         withoutUnicodePtr--;
1327                       }
1328                     }
1329                   }
1330                   // consume next character
1331                   unicodeAsBackSlash = false;
1332                   if (((currentCharacter = source[currentPosition++]) == '\\')
1333                     && (source[currentPosition] == 'u')) {
1334                     getNextUnicodeChar();
1335                   } else {
1336                     if (withoutUnicodePtr != 0) {
1337                       withoutUnicodeBuffer[++withoutUnicodePtr] =
1338                         currentCharacter;
1339                     }
1340                   }
1341
1342                 }
1343               } catch (IndexOutOfBoundsException e) {
1344                 throw new InvalidInputException(UNTERMINATED_STRING);
1345               } catch (InvalidInputException e) {
1346                 if (e.getMessage().equals(INVALID_ESCAPE)) {
1347                   // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
1348                   for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
1349                     if (currentPosition + lookAhead == source.length)
1350                       break;
1351                     if (source[currentPosition + lookAhead] == '\n')
1352                       break;
1353                     if (source[currentPosition + lookAhead] == '`') {
1354                       currentPosition += lookAhead + 1;
1355                       break;
1356                     }
1357                   }
1358
1359                 }
1360                 throw e; // rethrow
1361               }
1362               if (checkNonExternalizedStringLiterals) { // check for presence of        NLS tags //$NON-NLS-?$ where ? is an int.
1363                 if (currentLine == null) {
1364                   currentLine = new NLSLine();
1365                   lines.add(currentLine);
1366                 }
1367                 currentLine.add(
1368                   new StringLiteral(
1369                     getCurrentTokenSourceString(),
1370                     startPosition,
1371                     currentPosition - 1));
1372               }
1373               return TokenNameStringInterpolated;
1374             case '#' :
1375             case '/' :
1376               {
1377                 int test;
1378                 if ((currentCharacter == '#')
1379                   || (test = getNextChar('/', '*')) == 0) {
1380                   //line comment 
1381                   int endPositionForLineComment = 0;
1382                   try { //get the next char 
1383                     if (((currentCharacter = source[currentPosition++])
1384                       == '\\')
1385                       && (source[currentPosition] == 'u')) {
1386                       //-------------unicode traitement ------------
1387                       int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1388                       currentPosition++;
1389                       while (source[currentPosition] == 'u') {
1390                         currentPosition++;
1391                       }
1392                       if ((c1 =
1393                         Character.getNumericValue(source[currentPosition++]))
1394                         > 15
1395                         || c1 < 0
1396                         || (c2 =
1397                           Character.getNumericValue(source[currentPosition++]))
1398                           > 15
1399                         || c2 < 0
1400                         || (c3 =
1401                           Character.getNumericValue(source[currentPosition++]))
1402                           > 15
1403                         || c3 < 0
1404                         || (c4 =
1405                           Character.getNumericValue(source[currentPosition++]))
1406                           > 15
1407                         || c4 < 0) {
1408                         throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
1409                       } else {
1410                         currentCharacter =
1411                           (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1412                       }
1413                     }
1414
1415                     //handle the \\u case manually into comment
1416                     if (currentCharacter == '\\') {
1417                       if (source[currentPosition] == '\\')
1418                         currentPosition++;
1419                     } //jump over the \\
1420                     boolean isUnicode = false;
1421                     while (currentCharacter != '\r'
1422                       && currentCharacter != '\n') {
1423                       if (currentCharacter == '?') {
1424                         if (getNextChar('>')) {
1425                           startPosition = currentPosition - 2;
1426                           phpMode = false;
1427                           return TokenNameStopPHP;
1428                         }
1429                       }
1430
1431                       //get the next char
1432                       isUnicode = false;
1433                       if (((currentCharacter = source[currentPosition++])
1434                         == '\\')
1435                         && (source[currentPosition] == 'u')) {
1436                         isUnicode = true;
1437                         //-------------unicode traitement ------------
1438                         int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1439                         currentPosition++;
1440                         while (source[currentPosition] == 'u') {
1441                           currentPosition++;
1442                         }
1443                         if ((c1 =
1444                           Character.getNumericValue(source[currentPosition++]))
1445                           > 15
1446                           || c1 < 0
1447                           || (c2 =
1448                             Character.getNumericValue(
1449                               source[currentPosition++]))
1450                             > 15
1451                           || c2 < 0
1452                           || (c3 =
1453                             Character.getNumericValue(
1454                               source[currentPosition++]))
1455                             > 15
1456                           || c3 < 0
1457                           || (c4 =
1458                             Character.getNumericValue(
1459                               source[currentPosition++]))
1460                             > 15
1461                           || c4 < 0) {
1462                           throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
1463                         } else {
1464                           currentCharacter =
1465                             (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1466                         }
1467                       }
1468                       //handle the \\u case manually into comment
1469                       if (currentCharacter == '\\') {
1470                         if (source[currentPosition] == '\\')
1471                           currentPosition++;
1472                       } //jump over the \\
1473                     }
1474                     if (isUnicode) {
1475                       endPositionForLineComment = currentPosition - 6;
1476                     } else {
1477                       endPositionForLineComment = currentPosition - 1;
1478                     }
1479                     recordComment(false);
1480                     if ((currentCharacter == '\r')
1481                       || (currentCharacter == '\n')) {
1482                       checkNonExternalizeString();
1483                       if (recordLineSeparator) {
1484                         if (isUnicode) {
1485                           pushUnicodeLineSeparator();
1486                         } else {
1487                           pushLineSeparator();
1488                         }
1489                       } else {
1490                         currentLine = null;
1491                       }
1492                     }
1493                     if (tokenizeComments) {
1494                       if (!isUnicode) {
1495                         currentPosition = endPositionForLineComment;
1496                         // reset one character behind
1497                       }
1498                       return TokenNameCOMMENT_LINE;
1499                     }
1500                   } catch (IndexOutOfBoundsException e) { //an eof will them be generated
1501                     if (tokenizeComments) {
1502                       currentPosition--;
1503                       // reset one character behind
1504                       return TokenNameCOMMENT_LINE;
1505                     }
1506                   }
1507                   break;
1508                 }
1509                 if (test > 0) {
1510                   //traditional and annotation comment
1511                   boolean isJavadoc = false, star = false;
1512                   // consume next character
1513                   unicodeAsBackSlash = false;
1514                   if (((currentCharacter = source[currentPosition++]) == '\\')
1515                     && (source[currentPosition] == 'u')) {
1516                     getNextUnicodeChar();
1517                   } else {
1518                     if (withoutUnicodePtr != 0) {
1519                       withoutUnicodeBuffer[++withoutUnicodePtr] =
1520                         currentCharacter;
1521                     }
1522                   }
1523
1524                   if (currentCharacter == '*') {
1525                     isJavadoc = true;
1526                     star = true;
1527                   }
1528                   if ((currentCharacter == '\r')
1529                     || (currentCharacter == '\n')) {
1530                     checkNonExternalizeString();
1531                     if (recordLineSeparator) {
1532                       pushLineSeparator();
1533                     } else {
1534                       currentLine = null;
1535                     }
1536                   }
1537                   try { //get the next char 
1538                     if (((currentCharacter = source[currentPosition++])
1539                       == '\\')
1540                       && (source[currentPosition] == 'u')) {
1541                       //-------------unicode traitement ------------
1542                       getNextUnicodeChar();
1543                     }
1544                     //handle the \\u case manually into comment
1545                     if (currentCharacter == '\\') {
1546                       if (source[currentPosition] == '\\')
1547                         currentPosition++;
1548                       //jump over the \\
1549                     }
1550                     // empty comment is not a javadoc /**/
1551                     if (currentCharacter == '/') {
1552                       isJavadoc = false;
1553                     }
1554                     //loop until end of comment */
1555                     while ((currentCharacter != '/') || (!star)) {
1556                       if ((currentCharacter == '\r')
1557                         || (currentCharacter == '\n')) {
1558                         checkNonExternalizeString();
1559                         if (recordLineSeparator) {
1560                           pushLineSeparator();
1561                         } else {
1562                           currentLine = null;
1563                         }
1564                       }
1565                       star = currentCharacter == '*';
1566                       //get next char
1567                       if (((currentCharacter = source[currentPosition++])
1568                         == '\\')
1569                         && (source[currentPosition] == 'u')) {
1570                         //-------------unicode traitement ------------
1571                         getNextUnicodeChar();
1572                       }
1573                       //handle the \\u case manually into comment
1574                       if (currentCharacter == '\\') {
1575                         if (source[currentPosition] == '\\')
1576                           currentPosition++;
1577                       } //jump over the \\
1578                     }
1579                     recordComment(isJavadoc);
1580                     if (tokenizeComments) {
1581                       if (isJavadoc)
1582                         return TokenNameCOMMENT_PHPDOC;
1583                       return TokenNameCOMMENT_BLOCK;
1584                     }
1585                   } catch (IndexOutOfBoundsException e) {
1586                     throw new InvalidInputException(UNTERMINATED_COMMENT);
1587                   }
1588                   break;
1589                 }
1590                 if (getNextChar('='))
1591                   return TokenNameDIVIDE_EQUAL;
1592                 return TokenNameDIVIDE;
1593               }
1594             case '\u001a' :
1595               if (atEnd())
1596                 return TokenNameEOF;
1597               //the atEnd may not be <currentPosition == source.length> if source is only some part of a real (external) stream
1598               throw new InvalidInputException("Ctrl-Z"); //$NON-NLS-1$
1599
1600             default :
1601               if (currentCharacter == '$') {
1602                 while ((currentCharacter = source[currentPosition++]) == '$') {
1603                 }
1604                 if (currentCharacter == '{')
1605                   return TokenNameDOLLAR_LBRACE;
1606                 if (isPHPIdentifierStart(currentCharacter))
1607                   return scanIdentifierOrKeyword(true);
1608                 return TokenNameERROR;
1609               }
1610               if (isPHPIdentifierStart(currentCharacter))
1611                 return scanIdentifierOrKeyword(false);
1612               if (Character.isDigit(currentCharacter))
1613                 return scanNumber(false);
1614               return TokenNameERROR;
1615           }
1616         }
1617       } //-----------------end switch while try--------------------
1618       catch (IndexOutOfBoundsException e) {
1619       }
1620     }
1621     return TokenNameEOF;
1622   }
1623
1624   public final void getNextUnicodeChar()
1625     throws IndexOutOfBoundsException, InvalidInputException {
1626     //VOID
1627     //handle the case of unicode.
1628     //when a unicode appears then we must use a buffer that holds char internal values
1629     //At the end of this method currentCharacter holds the new visited char
1630     //and currentPosition points right next after it
1631
1632     //ALL getNextChar.... ARE OPTIMIZED COPIES 
1633
1634     int c1 = 0, c2 = 0, c3 = 0, c4 = 0, unicodeSize = 6;
1635     currentPosition++;
1636     while (source[currentPosition] == 'u') {
1637       currentPosition++;
1638       unicodeSize++;
1639     }
1640
1641     if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
1642       || c1 < 0
1643       || (c2 = Character.getNumericValue(source[currentPosition++])) > 15
1644       || c2 < 0
1645       || (c3 = Character.getNumericValue(source[currentPosition++])) > 15
1646       || c3 < 0
1647       || (c4 = Character.getNumericValue(source[currentPosition++])) > 15
1648       || c4 < 0) {
1649       throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
1650     } else {
1651       currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1652       //need the unicode buffer
1653       if (withoutUnicodePtr == 0) {
1654         //buffer all the entries that have been left aside....
1655         withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
1656         System.arraycopy(
1657           source,
1658           startPosition,
1659           withoutUnicodeBuffer,
1660           1,
1661           withoutUnicodePtr);
1662       }
1663       //fill the buffer with the char
1664       withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
1665     }
1666     unicodeAsBackSlash = currentCharacter == '\\';
1667   }
1668   /* Tokenize a method body, assuming that curly brackets are properly balanced.
1669    */
1670   public final void jumpOverMethodBody() {
1671
1672     this.wasAcr = false;
1673     int found = 1;
1674     try {
1675       while (true) { //loop for jumping over comments
1676         // ---------Consume white space and handles startPosition---------
1677         boolean isWhiteSpace;
1678         do {
1679           startPosition = currentPosition;
1680           if (((currentCharacter = source[currentPosition++]) == '\\')
1681             && (source[currentPosition] == 'u')) {
1682             isWhiteSpace = jumpOverUnicodeWhiteSpace();
1683           } else {
1684             if (recordLineSeparator
1685               && ((currentCharacter == '\r') || (currentCharacter == '\n')))
1686               pushLineSeparator();
1687             isWhiteSpace = Character.isWhitespace(currentCharacter);
1688           }
1689         } while (isWhiteSpace);
1690
1691         // -------consume token until } is found---------
1692         switch (currentCharacter) {
1693           case '{' :
1694             found++;
1695             break;
1696           case '}' :
1697             found--;
1698             if (found == 0)
1699               return;
1700             break;
1701           case '\'' :
1702             {
1703               boolean test;
1704               test = getNextChar('\\');
1705               if (test) {
1706                 try {
1707                   scanDoubleQuotedEscapeCharacter();
1708                 } catch (InvalidInputException ex) {
1709                 };
1710               } else {
1711                 try { // consume next character
1712                   unicodeAsBackSlash = false;
1713                   if (((currentCharacter = source[currentPosition++]) == '\\')
1714                     && (source[currentPosition] == 'u')) {
1715                     getNextUnicodeChar();
1716                   } else {
1717                     if (withoutUnicodePtr != 0) {
1718                       withoutUnicodeBuffer[++withoutUnicodePtr] =
1719                         currentCharacter;
1720                     }
1721                   }
1722                 } catch (InvalidInputException ex) {
1723                 };
1724               }
1725               getNextChar('\'');
1726               break;
1727             }
1728           case '"' :
1729             try {
1730               try { // consume next character
1731                 unicodeAsBackSlash = false;
1732                 if (((currentCharacter = source[currentPosition++]) == '\\')
1733                   && (source[currentPosition] == 'u')) {
1734                   getNextUnicodeChar();
1735                 } else {
1736                   if (withoutUnicodePtr != 0) {
1737                     withoutUnicodeBuffer[++withoutUnicodePtr] =
1738                       currentCharacter;
1739                   }
1740                 }
1741               } catch (InvalidInputException ex) {
1742               };
1743               while (currentCharacter != '"') {
1744                 if (currentCharacter == '\r') {
1745                   if (source[currentPosition] == '\n')
1746                     currentPosition++;
1747                   break;
1748                   // the string cannot go further that the line
1749                 }
1750                 if (currentCharacter == '\n') {
1751                   break;
1752                   // the string cannot go further that the line
1753                 }
1754                 if (currentCharacter == '\\') {
1755                   try {
1756                     scanDoubleQuotedEscapeCharacter();
1757                   } catch (InvalidInputException ex) {
1758                   };
1759                 }
1760                 try { // consume next character
1761                   unicodeAsBackSlash = false;
1762                   if (((currentCharacter = source[currentPosition++]) == '\\')
1763                     && (source[currentPosition] == 'u')) {
1764                     getNextUnicodeChar();
1765                   } else {
1766                     if (withoutUnicodePtr != 0) {
1767                       withoutUnicodeBuffer[++withoutUnicodePtr] =
1768                         currentCharacter;
1769                     }
1770                   }
1771                 } catch (InvalidInputException ex) {
1772                 };
1773               }
1774             } catch (IndexOutOfBoundsException e) {
1775               return;
1776             }
1777             break;
1778           case '/' :
1779             {
1780               int test;
1781               if ((test = getNextChar('/', '*')) == 0) {
1782                 //line comment 
1783                 try {
1784                   //get the next char 
1785                   if (((currentCharacter = source[currentPosition++]) == '\\')
1786                     && (source[currentPosition] == 'u')) {
1787                     //-------------unicode traitement ------------
1788                     int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1789                     currentPosition++;
1790                     while (source[currentPosition] == 'u') {
1791                       currentPosition++;
1792                     }
1793                     if ((c1 =
1794                       Character.getNumericValue(source[currentPosition++]))
1795                       > 15
1796                       || c1 < 0
1797                       || (c2 =
1798                         Character.getNumericValue(source[currentPosition++]))
1799                         > 15
1800                       || c2 < 0
1801                       || (c3 =
1802                         Character.getNumericValue(source[currentPosition++]))
1803                         > 15
1804                       || c3 < 0
1805                       || (c4 =
1806                         Character.getNumericValue(source[currentPosition++]))
1807                         > 15
1808                       || c4 < 0) {
1809                       //error don't care of the value
1810                       currentCharacter = 'A';
1811                     } //something different from \n and \r
1812                     else {
1813                       currentCharacter =
1814                         (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1815                     }
1816                   }
1817
1818                   while (currentCharacter != '\r'
1819                     && currentCharacter != '\n') {
1820                     //get the next char 
1821                     if (((currentCharacter = source[currentPosition++])
1822                       == '\\')
1823                       && (source[currentPosition] == 'u')) {
1824                       //-------------unicode traitement ------------
1825                       int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1826                       currentPosition++;
1827                       while (source[currentPosition] == 'u') {
1828                         currentPosition++;
1829                       }
1830                       if ((c1 =
1831                         Character.getNumericValue(source[currentPosition++]))
1832                         > 15
1833                         || c1 < 0
1834                         || (c2 =
1835                           Character.getNumericValue(source[currentPosition++]))
1836                           > 15
1837                         || c2 < 0
1838                         || (c3 =
1839                           Character.getNumericValue(source[currentPosition++]))
1840                           > 15
1841                         || c3 < 0
1842                         || (c4 =
1843                           Character.getNumericValue(source[currentPosition++]))
1844                           > 15
1845                         || c4 < 0) {
1846                         //error don't care of the value
1847                         currentCharacter = 'A';
1848                       } //something different from \n and \r
1849                       else {
1850                         currentCharacter =
1851                           (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1852                       }
1853                     }
1854                   }
1855                   if (recordLineSeparator
1856                     && ((currentCharacter == '\r') || (currentCharacter == '\n')))
1857                     pushLineSeparator();
1858                 } catch (IndexOutOfBoundsException e) {
1859                 } //an eof will them be generated
1860                 break;
1861               }
1862               if (test > 0) {
1863                 //traditional and annotation comment
1864                 boolean star = false;
1865                 try { // consume next character
1866                   unicodeAsBackSlash = false;
1867                   if (((currentCharacter = source[currentPosition++]) == '\\')
1868                     && (source[currentPosition] == 'u')) {
1869                     getNextUnicodeChar();
1870                   } else {
1871                     if (withoutUnicodePtr != 0) {
1872                       withoutUnicodeBuffer[++withoutUnicodePtr] =
1873                         currentCharacter;
1874                     }
1875                   };
1876                 } catch (InvalidInputException ex) {
1877                 };
1878                 if (currentCharacter == '*') {
1879                   star = true;
1880                 }
1881                 if (recordLineSeparator
1882                   && ((currentCharacter == '\r') || (currentCharacter == '\n')))
1883                   pushLineSeparator();
1884                 try { //get the next char 
1885                   if (((currentCharacter = source[currentPosition++]) == '\\')
1886                     && (source[currentPosition] == 'u')) {
1887                     //-------------unicode traitement ------------
1888                     int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1889                     currentPosition++;
1890                     while (source[currentPosition] == 'u') {
1891                       currentPosition++;
1892                     }
1893                     if ((c1 =
1894                       Character.getNumericValue(source[currentPosition++]))
1895                       > 15
1896                       || c1 < 0
1897                       || (c2 =
1898                         Character.getNumericValue(source[currentPosition++]))
1899                         > 15
1900                       || c2 < 0
1901                       || (c3 =
1902                         Character.getNumericValue(source[currentPosition++]))
1903                         > 15
1904                       || c3 < 0
1905                       || (c4 =
1906                         Character.getNumericValue(source[currentPosition++]))
1907                         > 15
1908                       || c4 < 0) {
1909                       //error don't care of the value
1910                       currentCharacter = 'A';
1911                     } //something different from * and /
1912                     else {
1913                       currentCharacter =
1914                         (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1915                     }
1916                   }
1917                   //loop until end of comment */ 
1918                   while ((currentCharacter != '/') || (!star)) {
1919                     if (recordLineSeparator
1920                       && ((currentCharacter == '\r')
1921                         || (currentCharacter == '\n')))
1922                       pushLineSeparator();
1923                     star = currentCharacter == '*';
1924                     //get next char
1925                     if (((currentCharacter = source[currentPosition++])
1926                       == '\\')
1927                       && (source[currentPosition] == 'u')) {
1928                       //-------------unicode traitement ------------
1929                       int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
1930                       currentPosition++;
1931                       while (source[currentPosition] == 'u') {
1932                         currentPosition++;
1933                       }
1934                       if ((c1 =
1935                         Character.getNumericValue(source[currentPosition++]))
1936                         > 15
1937                         || c1 < 0
1938                         || (c2 =
1939                           Character.getNumericValue(source[currentPosition++]))
1940                           > 15
1941                         || c2 < 0
1942                         || (c3 =
1943                           Character.getNumericValue(source[currentPosition++]))
1944                           > 15
1945                         || c3 < 0
1946                         || (c4 =
1947                           Character.getNumericValue(source[currentPosition++]))
1948                           > 15
1949                         || c4 < 0) {
1950                         //error don't care of the value
1951                         currentCharacter = 'A';
1952                       } //something different from * and /
1953                       else {
1954                         currentCharacter =
1955                           (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
1956                       }
1957                     }
1958                   }
1959                 } catch (IndexOutOfBoundsException e) {
1960                   return;
1961                 }
1962                 break;
1963               }
1964               break;
1965             }
1966
1967           default :
1968             if (isPHPIdentifierStart(currentCharacter)
1969               || currentCharacter == '$') {
1970               try {
1971                 scanIdentifierOrKeyword((currentCharacter == '$'));
1972               } catch (InvalidInputException ex) {
1973               };
1974               break;
1975             }
1976             if (Character.isDigit(currentCharacter)) {
1977               try {
1978                 scanNumber(false);
1979               } catch (InvalidInputException ex) {
1980               };
1981               break;
1982             }
1983         }
1984       }
1985       //-----------------end switch while try--------------------
1986     } catch (IndexOutOfBoundsException e) {
1987     } catch (InvalidInputException e) {
1988     }
1989     return;
1990   }
1991   public final boolean jumpOverUnicodeWhiteSpace()
1992     throws InvalidInputException {
1993     //BOOLEAN
1994     //handle the case of unicode. Jump over the next whiteSpace
1995     //making startPosition pointing on the next available char
1996     //On false, the currentCharacter is filled up with a potential
1997     //correct char
1998
1999     try {
2000       this.wasAcr = false;
2001       int c1, c2, c3, c4;
2002       int unicodeSize = 6;
2003       currentPosition++;
2004       while (source[currentPosition] == 'u') {
2005         currentPosition++;
2006         unicodeSize++;
2007       }
2008
2009       if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
2010         || c1 < 0)
2011         || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15
2012           || c2 < 0)
2013         || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15
2014           || c3 < 0)
2015         || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15
2016           || c4 < 0)) {
2017         throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
2018       }
2019
2020       currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
2021       if (recordLineSeparator
2022         && ((currentCharacter == '\r') || (currentCharacter == '\n')))
2023         pushLineSeparator();
2024       if (Character.isWhitespace(currentCharacter))
2025         return true;
2026
2027       //buffer the new char which is not a white space
2028       withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
2029       //withoutUnicodePtr == 1 is true here
2030       return false;
2031     } catch (IndexOutOfBoundsException e) {
2032       throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
2033     }
2034   }
2035   public final int[] getLineEnds() {
2036     //return a bounded copy of this.lineEnds 
2037
2038     int[] copy;
2039     System.arraycopy(lineEnds, 0, copy = new int[linePtr + 1], 0, linePtr + 1);
2040     return copy;
2041   }
2042
2043   public char[] getSource() {
2044     return this.source;
2045   }
2046   final char[] optimizedCurrentTokenSource1() {
2047     //return always the same char[] build only once
2048
2049     //optimization at no speed cost of 99.5 % of the singleCharIdentifier
2050     char charOne = source[startPosition];
2051     switch (charOne) {
2052       case 'a' :
2053         return charArray_a;
2054       case 'b' :
2055         return charArray_b;
2056       case 'c' :
2057         return charArray_c;
2058       case 'd' :
2059         return charArray_d;
2060       case 'e' :
2061         return charArray_e;
2062       case 'f' :
2063         return charArray_f;
2064       case 'g' :
2065         return charArray_g;
2066       case 'h' :
2067         return charArray_h;
2068       case 'i' :
2069         return charArray_i;
2070       case 'j' :
2071         return charArray_j;
2072       case 'k' :
2073         return charArray_k;
2074       case 'l' :
2075         return charArray_l;
2076       case 'm' :
2077         return charArray_m;
2078       case 'n' :
2079         return charArray_n;
2080       case 'o' :
2081         return charArray_o;
2082       case 'p' :
2083         return charArray_p;
2084       case 'q' :
2085         return charArray_q;
2086       case 'r' :
2087         return charArray_r;
2088       case 's' :
2089         return charArray_s;
2090       case 't' :
2091         return charArray_t;
2092       case 'u' :
2093         return charArray_u;
2094       case 'v' :
2095         return charArray_v;
2096       case 'w' :
2097         return charArray_w;
2098       case 'x' :
2099         return charArray_x;
2100       case 'y' :
2101         return charArray_y;
2102       case 'z' :
2103         return charArray_z;
2104       default :
2105         return new char[] { charOne };
2106     }
2107   }
2108
2109   final char[] optimizedCurrentTokenSource2() {
2110     //try to return the same char[] build only once
2111
2112     char c0, c1;
2113     int hash =
2114       (((c0 = source[startPosition]) << 6) + (c1 = source[startPosition + 1]))
2115         % TableSize;
2116     char[][] table = charArray_length[0][hash];
2117     int i = newEntry2;
2118     while (++i < InternalTableSize) {
2119       char[] charArray = table[i];
2120       if ((c0 == charArray[0]) && (c1 == charArray[1]))
2121         return charArray;
2122     }
2123     //---------other side---------
2124     i = -1;
2125     int max = newEntry2;
2126     while (++i <= max) {
2127       char[] charArray = table[i];
2128       if ((c0 == charArray[0]) && (c1 == charArray[1]))
2129         return charArray;
2130     }
2131     //--------add the entry-------
2132     if (++max >= InternalTableSize)
2133       max = 0;
2134     char[] r;
2135     table[max] = (r = new char[] { c0, c1 });
2136     newEntry2 = max;
2137     return r;
2138   }
2139
2140   final char[] optimizedCurrentTokenSource3() {
2141     //try to return the same char[] build only once
2142
2143     char c0, c1, c2;
2144     int hash =
2145       (((c0 = source[startPosition]) << 12)
2146         + ((c1 = source[startPosition + 1]) << 6)
2147         + (c2 = source[startPosition + 2]))
2148         % TableSize;
2149     char[][] table = charArray_length[1][hash];
2150     int i = newEntry3;
2151     while (++i < InternalTableSize) {
2152       char[] charArray = table[i];
2153       if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
2154         return charArray;
2155     }
2156     //---------other side---------
2157     i = -1;
2158     int max = newEntry3;
2159     while (++i <= max) {
2160       char[] charArray = table[i];
2161       if ((c0 == charArray[0]) && (c1 == charArray[1]) && (c2 == charArray[2]))
2162         return charArray;
2163     }
2164     //--------add the entry-------
2165     if (++max >= InternalTableSize)
2166       max = 0;
2167     char[] r;
2168     table[max] = (r = new char[] { c0, c1, c2 });
2169     newEntry3 = max;
2170     return r;
2171   }
2172
2173   final char[] optimizedCurrentTokenSource4() {
2174     //try to return the same char[] build only once
2175
2176     char c0, c1, c2, c3;
2177     long hash =
2178       ((((long) (c0 = source[startPosition])) << 18)
2179         + ((c1 = source[startPosition + 1]) << 12)
2180         + ((c2 = source[startPosition + 2]) << 6)
2181         + (c3 = source[startPosition + 3]))
2182         % TableSize;
2183     char[][] table = charArray_length[2][(int) hash];
2184     int i = newEntry4;
2185     while (++i < InternalTableSize) {
2186       char[] charArray = table[i];
2187       if ((c0 == charArray[0])
2188         && (c1 == charArray[1])
2189         && (c2 == charArray[2])
2190         && (c3 == charArray[3]))
2191         return charArray;
2192     }
2193     //---------other side---------
2194     i = -1;
2195     int max = newEntry4;
2196     while (++i <= max) {
2197       char[] charArray = table[i];
2198       if ((c0 == charArray[0])
2199         && (c1 == charArray[1])
2200         && (c2 == charArray[2])
2201         && (c3 == charArray[3]))
2202         return charArray;
2203     }
2204     //--------add the entry-------
2205     if (++max >= InternalTableSize)
2206       max = 0;
2207     char[] r;
2208     table[max] = (r = new char[] { c0, c1, c2, c3 });
2209     newEntry4 = max;
2210     return r;
2211
2212   }
2213
2214   final char[] optimizedCurrentTokenSource5() {
2215     //try to return the same char[] build only once
2216
2217     char c0, c1, c2, c3, c4;
2218     long hash =
2219       ((((long) (c0 = source[startPosition])) << 24)
2220         + (((long) (c1 = source[startPosition + 1])) << 18)
2221         + ((c2 = source[startPosition + 2]) << 12)
2222         + ((c3 = source[startPosition + 3]) << 6)
2223         + (c4 = source[startPosition + 4]))
2224         % TableSize;
2225     char[][] table = charArray_length[3][(int) hash];
2226     int i = newEntry5;
2227     while (++i < InternalTableSize) {
2228       char[] charArray = table[i];
2229       if ((c0 == charArray[0])
2230         && (c1 == charArray[1])
2231         && (c2 == charArray[2])
2232         && (c3 == charArray[3])
2233         && (c4 == charArray[4]))
2234         return charArray;
2235     }
2236     //---------other side---------
2237     i = -1;
2238     int max = newEntry5;
2239     while (++i <= max) {
2240       char[] charArray = table[i];
2241       if ((c0 == charArray[0])
2242         && (c1 == charArray[1])
2243         && (c2 == charArray[2])
2244         && (c3 == charArray[3])
2245         && (c4 == charArray[4]))
2246         return charArray;
2247     }
2248     //--------add the entry-------
2249     if (++max >= InternalTableSize)
2250       max = 0;
2251     char[] r;
2252     table[max] = (r = new char[] { c0, c1, c2, c3, c4 });
2253     newEntry5 = max;
2254     return r;
2255
2256   }
2257
2258   final char[] optimizedCurrentTokenSource6() {
2259     //try to return the same char[] build only once
2260
2261     char c0, c1, c2, c3, c4, c5;
2262     long hash =
2263       ((((long) (c0 = source[startPosition])) << 32)
2264         + (((long) (c1 = source[startPosition + 1])) << 24)
2265         + (((long) (c2 = source[startPosition + 2])) << 18)
2266         + ((c3 = source[startPosition + 3]) << 12)
2267         + ((c4 = source[startPosition + 4]) << 6)
2268         + (c5 = source[startPosition + 5]))
2269         % TableSize;
2270     char[][] table = charArray_length[4][(int) hash];
2271     int i = newEntry6;
2272     while (++i < InternalTableSize) {
2273       char[] charArray = table[i];
2274       if ((c0 == charArray[0])
2275         && (c1 == charArray[1])
2276         && (c2 == charArray[2])
2277         && (c3 == charArray[3])
2278         && (c4 == charArray[4])
2279         && (c5 == charArray[5]))
2280         return charArray;
2281     }
2282     //---------other side---------
2283     i = -1;
2284     int max = newEntry6;
2285     while (++i <= max) {
2286       char[] charArray = table[i];
2287       if ((c0 == charArray[0])
2288         && (c1 == charArray[1])
2289         && (c2 == charArray[2])
2290         && (c3 == charArray[3])
2291         && (c4 == charArray[4])
2292         && (c5 == charArray[5]))
2293         return charArray;
2294     }
2295     //--------add the entry-------
2296     if (++max >= InternalTableSize)
2297       max = 0;
2298     char[] r;
2299     table[max] = (r = new char[] { c0, c1, c2, c3, c4, c5 });
2300     newEntry6 = max;
2301     return r;
2302   }
2303
2304   public final void pushLineSeparator() throws InvalidInputException {
2305     //see comment on isLineDelimiter(char) for the use of '\n' and '\r'
2306     final int INCREMENT = 250;
2307
2308     if (this.checkNonExternalizedStringLiterals) {
2309       // reinitialize the current line for non externalize strings purpose
2310       currentLine = null;
2311     }
2312     //currentCharacter is at position currentPosition-1
2313
2314     // cr 000D
2315     if (currentCharacter == '\r') {
2316       int separatorPos = currentPosition - 1;
2317       if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
2318         return;
2319       //System.out.println("CR-" + separatorPos);
2320       try {
2321         lineEnds[++linePtr] = separatorPos;
2322       } catch (IndexOutOfBoundsException e) {
2323         //linePtr value is correct
2324         int oldLength = lineEnds.length;
2325         int[] old = lineEnds;
2326         lineEnds = new int[oldLength + INCREMENT];
2327         System.arraycopy(old, 0, lineEnds, 0, oldLength);
2328         lineEnds[linePtr] = separatorPos;
2329       }
2330       // look-ahead for merged cr+lf
2331       try {
2332         if (source[currentPosition] == '\n') {
2333           //System.out.println("look-ahead LF-" + currentPosition);                     
2334           lineEnds[linePtr] = currentPosition;
2335           currentPosition++;
2336           wasAcr = false;
2337         } else {
2338           wasAcr = true;
2339         }
2340       } catch (IndexOutOfBoundsException e) {
2341         wasAcr = true;
2342       }
2343     } else {
2344       // lf 000A
2345       if (currentCharacter == '\n') {
2346         //must merge eventual cr followed by lf
2347         if (wasAcr && (lineEnds[linePtr] == (currentPosition - 2))) {
2348           //System.out.println("merge LF-" + (currentPosition - 1));                                                    
2349           lineEnds[linePtr] = currentPosition - 1;
2350         } else {
2351           int separatorPos = currentPosition - 1;
2352           if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
2353             return;
2354           // System.out.println("LF-" + separatorPos);                                                  
2355           try {
2356             lineEnds[++linePtr] = separatorPos;
2357           } catch (IndexOutOfBoundsException e) {
2358             //linePtr value is correct
2359             int oldLength = lineEnds.length;
2360             int[] old = lineEnds;
2361             lineEnds = new int[oldLength + INCREMENT];
2362             System.arraycopy(old, 0, lineEnds, 0, oldLength);
2363             lineEnds[linePtr] = separatorPos;
2364           }
2365         }
2366         wasAcr = false;
2367       }
2368     }
2369   }
2370   public final void pushUnicodeLineSeparator() {
2371     // isUnicode means that the \r or \n has been read as a unicode character
2372
2373     //see comment on isLineDelimiter(char) for the use of '\n' and '\r'
2374
2375     final int INCREMENT = 250;
2376     //currentCharacter is at position currentPosition-1
2377
2378     if (this.checkNonExternalizedStringLiterals) {
2379       // reinitialize the current line for non externalize strings purpose
2380       currentLine = null;
2381     }
2382
2383     // cr 000D
2384     if (currentCharacter == '\r') {
2385       int separatorPos = currentPosition - 6;
2386       if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
2387         return;
2388       //System.out.println("CR-" + separatorPos);
2389       try {
2390         lineEnds[++linePtr] = separatorPos;
2391       } catch (IndexOutOfBoundsException e) {
2392         //linePtr value is correct
2393         int oldLength = lineEnds.length;
2394         int[] old = lineEnds;
2395         lineEnds = new int[oldLength + INCREMENT];
2396         System.arraycopy(old, 0, lineEnds, 0, oldLength);
2397         lineEnds[linePtr] = separatorPos;
2398       }
2399       // look-ahead for merged cr+lf
2400       if (source[currentPosition] == '\n') {
2401         //System.out.println("look-ahead LF-" + currentPosition);                       
2402         lineEnds[linePtr] = currentPosition;
2403         currentPosition++;
2404         wasAcr = false;
2405       } else {
2406         wasAcr = true;
2407       }
2408     } else {
2409       // lf 000A
2410       if (currentCharacter == '\n') {
2411         //must merge eventual cr followed by lf
2412         if (wasAcr && (lineEnds[linePtr] == (currentPosition - 7))) {
2413           //System.out.println("merge LF-" + (currentPosition - 1));                                                    
2414           lineEnds[linePtr] = currentPosition - 6;
2415         } else {
2416           int separatorPos = currentPosition - 6;
2417           if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos))
2418             return;
2419           // System.out.println("LF-" + separatorPos);                                                  
2420           try {
2421             lineEnds[++linePtr] = separatorPos;
2422           } catch (IndexOutOfBoundsException e) {
2423             //linePtr value is correct
2424             int oldLength = lineEnds.length;
2425             int[] old = lineEnds;
2426             lineEnds = new int[oldLength + INCREMENT];
2427             System.arraycopy(old, 0, lineEnds, 0, oldLength);
2428             lineEnds[linePtr] = separatorPos;
2429           }
2430         }
2431         wasAcr = false;
2432       }
2433     }
2434   }
2435   public final void recordComment(boolean isJavadoc) {
2436
2437     // a new annotation comment is recorded
2438     try {
2439       commentStops[++commentPtr] =
2440         isJavadoc ? currentPosition : -currentPosition;
2441     } catch (IndexOutOfBoundsException e) {
2442       int oldStackLength = commentStops.length;
2443       int[] oldStack = commentStops;
2444       commentStops = new int[oldStackLength + 30];
2445       System.arraycopy(oldStack, 0, commentStops, 0, oldStackLength);
2446       commentStops[commentPtr] = isJavadoc ? currentPosition : -currentPosition;
2447       //grows the positions buffers too
2448       int[] old = commentStarts;
2449       commentStarts = new int[oldStackLength + 30];
2450       System.arraycopy(old, 0, commentStarts, 0, oldStackLength);
2451     }
2452
2453     //the buffer is of a correct size here
2454     commentStarts[commentPtr] = startPosition;
2455   }
2456   public void resetTo(int begin, int end) {
2457     //reset the scanner to a given position where it may rescan again
2458
2459     diet = false;
2460     initialPosition = startPosition = currentPosition = begin;
2461     eofPosition = end < Integer.MAX_VALUE ? end + 1 : end;
2462     commentPtr = -1; // reset comment stack
2463   }
2464
2465   public final void scanSingleQuotedEscapeCharacter()
2466     throws InvalidInputException {
2467     // the string with "\\u" is a legal string of two chars \ and u
2468     //thus we use a direct access to the source (for regular cases).
2469
2470     if (unicodeAsBackSlash) {
2471       // consume next character
2472       unicodeAsBackSlash = false;
2473       if (((currentCharacter = source[currentPosition++]) == '\\')
2474         && (source[currentPosition] == 'u')) {
2475         getNextUnicodeChar();
2476       } else {
2477         if (withoutUnicodePtr != 0) {
2478           withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
2479         }
2480       }
2481     } else
2482       currentCharacter = source[currentPosition++];
2483     switch (currentCharacter) {
2484       case '\'' :
2485         currentCharacter = '\'';
2486         break;
2487       case '\\' :
2488         currentCharacter = '\\';
2489         break;
2490       default :
2491         currentCharacter = '\\';
2492         currentPosition--;
2493     }
2494   }
2495
2496   public final void scanDoubleQuotedEscapeCharacter()
2497     throws InvalidInputException {
2498     // the string with "\\u" is a legal string of two chars \ and u
2499     //thus we use a direct access to the source (for regular cases).
2500
2501     if (unicodeAsBackSlash) {
2502       // consume next character
2503       unicodeAsBackSlash = false;
2504       if (((currentCharacter = source[currentPosition++]) == '\\')
2505         && (source[currentPosition] == 'u')) {
2506         getNextUnicodeChar();
2507       } else {
2508         if (withoutUnicodePtr != 0) {
2509           withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
2510         }
2511       }
2512     } else
2513       currentCharacter = source[currentPosition++];
2514     switch (currentCharacter) {
2515       //      case 'b' :
2516       //        currentCharacter = '\b';
2517       //        break;
2518       case 't' :
2519         currentCharacter = '\t';
2520         break;
2521       case 'n' :
2522         currentCharacter = '\n';
2523         break;
2524         //      case 'f' :
2525         //        currentCharacter = '\f';
2526         //        break;
2527       case 'r' :
2528         currentCharacter = '\r';
2529         break;
2530       case '\"' :
2531         currentCharacter = '\"';
2532         break;
2533       case '\'' :
2534         currentCharacter = '\'';
2535         break;
2536       case '\\' :
2537         currentCharacter = '\\';
2538         break;
2539       case '$' :
2540         currentCharacter = '$';
2541         break;
2542       default :
2543         // -----------octal escape--------------
2544         // OctalDigit
2545         // OctalDigit OctalDigit
2546         // ZeroToThree OctalDigit OctalDigit
2547
2548         int number = Character.getNumericValue(currentCharacter);
2549         if (number >= 0 && number <= 7) {
2550           boolean zeroToThreeNot = number > 3;
2551           if (Character
2552             .isDigit(currentCharacter = source[currentPosition++])) {
2553             int digit = Character.getNumericValue(currentCharacter);
2554             if (digit >= 0 && digit <= 7) {
2555               number = (number * 8) + digit;
2556               if (Character
2557                 .isDigit(currentCharacter = source[currentPosition++])) {
2558                 if (zeroToThreeNot) { // has read \NotZeroToThree OctalDigit Digit --> ignore last character
2559                   currentPosition--;
2560                 } else {
2561                   digit = Character.getNumericValue(currentCharacter);
2562                   if (digit >= 0 && digit <= 7) {
2563                     // has read \ZeroToThree OctalDigit OctalDigit
2564                     number = (number * 8) + digit;
2565                   } else { // has read \ZeroToThree OctalDigit NonOctalDigit --> ignore last character
2566                     currentPosition--;
2567                   }
2568                 }
2569               } else { // has read \OctalDigit NonDigit--> ignore last character
2570                 currentPosition--;
2571               }
2572             } else { // has read \OctalDigit NonOctalDigit--> ignore last character                                             
2573               currentPosition--;
2574             }
2575           } else { // has read \OctalDigit --> ignore last character
2576             currentPosition--;
2577           }
2578           if (number > 255)
2579             throw new InvalidInputException(INVALID_ESCAPE);
2580           currentCharacter = (char) number;
2581         }
2582         //else
2583         //     throw new InvalidInputException(INVALID_ESCAPE);
2584     }
2585   }
2586
2587   //  public int scanIdentifierOrKeyword() throws InvalidInputException {
2588   //    return scanIdentifierOrKeyword( false );
2589   //  }
2590
2591   public int scanIdentifierOrKeyword(boolean isVariable)
2592     throws InvalidInputException {
2593     //test keywords
2594
2595     //first dispatch on the first char.
2596     //then the length. If there are several
2597     //keywors with the same length AND the same first char, then do another
2598     //disptach on the second char :-)...cool....but fast !
2599
2600     useAssertAsAnIndentifier = false;
2601
2602     while (getNextCharAsJavaIdentifierPart()) {
2603     };
2604
2605     if (isVariable) {
2606       return TokenNameVariable;
2607     }
2608     int index, length;
2609     char[] data;
2610     char firstLetter;
2611     if (withoutUnicodePtr == 0)
2612
2613       //quick test on length == 1 but not on length > 12 while most identifier
2614       //have a length which is <= 12...but there are lots of identifier with
2615       //only one char....
2616
2617       {
2618       if ((length = currentPosition - startPosition) == 1)
2619         return TokenNameIdentifier;
2620       //  data = source;
2621       data = new char[length];
2622       index = startPosition;
2623       for (int i = 0; i < length; i++) {
2624         data[i] = Character.toLowerCase(source[index + i]);
2625       }
2626       index = 0;
2627     } else {
2628       if ((length = withoutUnicodePtr) == 1)
2629         return TokenNameIdentifier;
2630       // data = withoutUnicodeBuffer;
2631       data = new char[withoutUnicodeBuffer.length];
2632       for (int i = 0; i < withoutUnicodeBuffer.length; i++) {
2633         data[i] = Character.toLowerCase(withoutUnicodeBuffer[i]);
2634       }
2635       index = 1;
2636     }
2637
2638     firstLetter = data[index];
2639     switch (firstLetter) {
2640
2641       case 'a' : // as and array
2642         switch (length) {
2643           case 2 : //as
2644             if ((data[++index] == 's')) {
2645               return TokenNameas;
2646             } else {
2647               return TokenNameIdentifier;
2648             }
2649           case 3 : //and
2650             if ((data[++index] == 'n') && (data[++index] == 'd')) {
2651               return TokenNameAND;
2652             } else {
2653               return TokenNameIdentifier;
2654             }
2655             //          case 5 :
2656             //            if ((data[++index] == 'r') && (data[++index] == 'r') && (data[++index] == 'a') && (data[++index] == 'y'))
2657             //              return TokenNamearray;
2658             //            else
2659             //              return TokenNameIdentifier;
2660           default :
2661             return TokenNameIdentifier;
2662         }
2663       case 'b' : //break
2664         switch (length) {
2665           case 5 :
2666             if ((data[++index] == 'r')
2667               && (data[++index] == 'e')
2668               && (data[++index] == 'a')
2669               && (data[++index] == 'k'))
2670               return TokenNamebreak;
2671             else
2672               return TokenNameIdentifier;
2673           default :
2674             return TokenNameIdentifier;
2675         }
2676
2677       case 'c' : //case class continue
2678         switch (length) {
2679           case 4 :
2680             if ((data[++index] == 'a')
2681               && (data[++index] == 's')
2682               && (data[++index] == 'e'))
2683               return TokenNamecase;
2684             else
2685               return TokenNameIdentifier;
2686           case 5 :
2687             if ((data[++index] == 'l')
2688               && (data[++index] == 'a')
2689               && (data[++index] == 's')
2690               && (data[++index] == 's'))
2691               return TokenNameclass;
2692             else
2693               return TokenNameIdentifier;
2694           case 8 :
2695             if ((data[++index] == 'o')
2696               && (data[++index] == 'n')
2697               && (data[++index] == 't')
2698               && (data[++index] == 'i')
2699               && (data[++index] == 'n')
2700               && (data[++index] == 'u')
2701               && (data[++index] == 'e'))
2702               return TokenNamecontinue;
2703             else
2704               return TokenNameIdentifier;
2705           default :
2706             return TokenNameIdentifier;
2707         }
2708
2709       case 'd' : //define default do 
2710         switch (length) {
2711           case 2 :
2712             if ((data[++index] == 'o'))
2713               return TokenNamedo;
2714             else
2715               return TokenNameIdentifier;
2716           case 6 :
2717             if ((data[++index] == 'e')
2718               && (data[++index] == 'f')
2719               && (data[++index] == 'i')
2720               && (data[++index] == 'n')
2721               && (data[++index] == 'e'))
2722               return TokenNamedefine;
2723             else
2724               return TokenNameIdentifier;
2725           case 7 :
2726             if ((data[++index] == 'e')
2727               && (data[++index] == 'f')
2728               && (data[++index] == 'a')
2729               && (data[++index] == 'u')
2730               && (data[++index] == 'l')
2731               && (data[++index] == 't'))
2732               return TokenNamedefault;
2733             else
2734               return TokenNameIdentifier;
2735           default :
2736             return TokenNameIdentifier;
2737         }
2738       case 'e' : //echo else elseif extends
2739         switch (length) {
2740           case 4 :
2741             if ((data[++index] == 'c')
2742               && (data[++index] == 'h')
2743               && (data[++index] == 'o'))
2744               return TokenNameecho;
2745             else if (
2746               (data[index] == 'l')
2747                 && (data[++index] == 's')
2748                 && (data[++index] == 'e'))
2749               return TokenNameelse;
2750             else
2751               return TokenNameIdentifier;
2752           case 5 : // endif
2753             if ((data[++index] == 'n')
2754               && (data[++index] == 'd')
2755               && (data[++index] == 'i')
2756               && (data[++index] == 'f'))
2757               return TokenNameendif;
2758             else
2759               return TokenNameIdentifier;
2760           case 6 : // endfor
2761             if ((data[++index] == 'n')
2762               && (data[++index] == 'd')
2763               && (data[++index] == 'f')
2764               && (data[++index] == 'o')
2765               && (data[++index] == 'r'))
2766               return TokenNameendfor;
2767             else if (
2768               (data[index] == 'l')
2769                 && (data[++index] == 's')
2770                 && (data[++index] == 'e')
2771                 && (data[++index] == 'i')
2772                 && (data[++index] == 'f'))
2773               return TokenNameelseif;
2774             else
2775               return TokenNameIdentifier;
2776           case 7 :
2777             if ((data[++index] == 'x')
2778               && (data[++index] == 't')
2779               && (data[++index] == 'e')
2780               && (data[++index] == 'n')
2781               && (data[++index] == 'd')
2782               && (data[++index] == 's'))
2783               return TokenNameextends;
2784             else
2785               return TokenNameIdentifier;
2786           case 8 : // endwhile
2787             if ((data[++index] == 'n')
2788               && (data[++index] == 'd')
2789               && (data[++index] == 'w')
2790               && (data[++index] == 'h')
2791               && (data[++index] == 'i')
2792               && (data[++index] == 'l')
2793               && (data[++index] == 'e'))
2794               return TokenNameendwhile;
2795             else
2796               return TokenNameIdentifier;
2797           case 9 : // endswitch
2798             if ((data[++index] == 'n')
2799               && (data[++index] == 'd')
2800               && (data[++index] == 's')
2801               && (data[++index] == 'w')
2802               && (data[++index] == 'i')
2803               && (data[++index] == 't')
2804               && (data[++index] == 'c')
2805               && (data[++index] == 'h'))
2806               return TokenNameendswitch;
2807             else
2808               return TokenNameIdentifier;
2809           case 10 : // endforeach
2810             if ((data[++index] == 'n')
2811               && (data[++index] == 'd')
2812               && (data[++index] == 'f')
2813               && (data[++index] == 'o')
2814               && (data[++index] == 'r')
2815               && (data[++index] == 'e')
2816               && (data[++index] == 'a')
2817               && (data[++index] == 'c')
2818               && (data[++index] == 'h'))
2819               return TokenNameendforeach;
2820             else
2821               return TokenNameIdentifier;
2822
2823           default :
2824             return TokenNameIdentifier;
2825         }
2826
2827       case 'f' : //for false function
2828         switch (length) {
2829           case 3 :
2830             if ((data[++index] == 'o') && (data[++index] == 'r'))
2831               return TokenNamefor;
2832             else
2833               return TokenNameIdentifier;
2834           case 5 :
2835             if ((data[++index] == 'a')
2836               && (data[++index] == 'l')
2837               && (data[++index] == 's')
2838               && (data[++index] == 'e'))
2839               return TokenNamefalse;
2840             else
2841               return TokenNameIdentifier;
2842           case 7 : // function
2843             if ((data[++index] == 'o')
2844               && (data[++index] == 'r')
2845               && (data[++index] == 'e')
2846               && (data[++index] == 'a')
2847               && (data[++index] == 'c')
2848               && (data[++index] == 'h'))
2849               return TokenNameforeach;
2850             else
2851               return TokenNameIdentifier;
2852           case 8 : // function
2853             if ((data[++index] == 'u')
2854               && (data[++index] == 'n')
2855               && (data[++index] == 'c')
2856               && (data[++index] == 't')
2857               && (data[++index] == 'i')
2858               && (data[++index] == 'o')
2859               && (data[++index] == 'n'))
2860               return TokenNamefunction;
2861             else
2862               return TokenNameIdentifier;
2863           default :
2864             return TokenNameIdentifier;
2865         }
2866       case 'g' : //global
2867         if (length == 6) {
2868           if ((data[++index] == 'l')
2869             && (data[++index] == 'o')
2870             && (data[++index] == 'b')
2871             && (data[++index] == 'a')
2872             && (data[++index] == 'l')) {
2873             return TokenNameglobal;
2874           }
2875         }
2876         return TokenNameIdentifier;
2877
2878       case 'i' : //if int 
2879         switch (length) {
2880           case 2 :
2881             if (data[++index] == 'f')
2882               return TokenNameif;
2883             else
2884               return TokenNameIdentifier;
2885             //          case 3 :
2886             //            if ((data[++index] == 'n') && (data[++index] == 't'))
2887             //              return TokenNameint;
2888             //            else
2889             //              return TokenNameIdentifier;
2890           case 7 :
2891             if ((data[++index] == 'n')
2892               && (data[++index] == 'c')
2893               && (data[++index] == 'l')
2894               && (data[++index] == 'u')
2895               && (data[++index] == 'd')
2896               && (data[++index] == 'e'))
2897               return TokenNameinclude;
2898             else
2899               return TokenNameIdentifier;
2900           case 12 :
2901             if ((data[++index] == 'n')
2902               && (data[++index] == 'c')
2903               && (data[++index] == 'l')
2904               && (data[++index] == 'u')
2905               && (data[++index] == 'd')
2906               && (data[++index] == 'e')
2907               && (data[++index] == '_')
2908               && (data[++index] == 'o')
2909               && (data[++index] == 'n')
2910               && (data[++index] == 'c')
2911               && (data[++index] == 'e'))
2912               return TokenNameinclude_once;
2913             else
2914               return TokenNameIdentifier;
2915           default :
2916             return TokenNameIdentifier;
2917         }
2918
2919       case 'l' : //list
2920         if (length == 4) {
2921           if ((data[++index] == 'i')
2922             && (data[++index] == 's')
2923             && (data[++index] == 't')) {
2924             return TokenNamelist;
2925           }
2926         }
2927         return TokenNameIdentifier;
2928
2929       case 'n' : // new null
2930         switch (length) {
2931           case 3 :
2932             if ((data[++index] == 'e') && (data[++index] == 'w'))
2933               return TokenNamenew;
2934             else
2935               return TokenNameIdentifier;
2936           case 4 :
2937             if ((data[++index] == 'u')
2938               && (data[++index] == 'l')
2939               && (data[++index] == 'l'))
2940               return TokenNamenull;
2941             else
2942               return TokenNameIdentifier;
2943
2944           default :
2945             return TokenNameIdentifier;
2946         }
2947       case 'o' : // or old_function
2948         if (length == 2) {
2949           if (data[++index] == 'r') {
2950             return TokenNameOR;
2951           }
2952         }
2953         //        if (length == 12) {
2954         //          if ((data[++index] == 'l')
2955         //            && (data[++index] == 'd')
2956         //            && (data[++index] == '_')
2957         //            && (data[++index] == 'f')
2958         //            && (data[++index] == 'u')
2959         //            && (data[++index] == 'n')
2960         //            && (data[++index] == 'c')
2961         //            && (data[++index] == 't')
2962         //            && (data[++index] == 'i')
2963         //            && (data[++index] == 'o')
2964         //            && (data[++index] == 'n')) {
2965         //            return TokenNameold_function;
2966         //          }
2967         //        }
2968         return TokenNameIdentifier;
2969
2970       case 'p' : // print
2971         if (length == 5) {
2972           if ((data[++index] == 'r')
2973             && (data[++index] == 'i')
2974             && (data[++index] == 'n')
2975             && (data[++index] == 't')) {
2976             return TokenNameprint;
2977           }
2978         }
2979         return TokenNameIdentifier;
2980       case 'r' : //return require require_once
2981         if (length == 6) {
2982           if ((data[++index] == 'e')
2983             && (data[++index] == 't')
2984             && (data[++index] == 'u')
2985             && (data[++index] == 'r')
2986             && (data[++index] == 'n')) {
2987             return TokenNamereturn;
2988           }
2989         } else if (length == 7) {
2990           if ((data[++index] == 'e')
2991             && (data[++index] == 'q')
2992             && (data[++index] == 'u')
2993             && (data[++index] == 'i')
2994             && (data[++index] == 'r')
2995             && (data[++index] == 'e')) {
2996             return TokenNamerequire;
2997           }
2998         } else if (length == 12) {
2999           if ((data[++index] == 'e')
3000             && (data[++index] == 'q')
3001             && (data[++index] == 'u')
3002             && (data[++index] == 'i')
3003             && (data[++index] == 'r')
3004             && (data[++index] == 'e')
3005             && (data[++index] == '_')
3006             && (data[++index] == 'o')
3007             && (data[++index] == 'n')
3008             && (data[++index] == 'c')
3009             && (data[++index] == 'e')) {
3010             return TokenNamerequire_once;
3011           }
3012         } else
3013           return TokenNameIdentifier;
3014
3015       case 's' : //static switch 
3016         switch (length) {
3017           case 6 :
3018             if (data[++index] == 't')
3019               if ((data[++index] == 'a')
3020                 && (data[++index] == 't')
3021                 && (data[++index] == 'i')
3022                 && (data[++index] == 'c')) {
3023                 return TokenNamestatic;
3024               } else
3025                 return TokenNameIdentifier;
3026             else if (
3027               (data[index] == 'w')
3028                 && (data[++index] == 'i')
3029                 && (data[++index] == 't')
3030                 && (data[++index] == 'c')
3031                 && (data[++index] == 'h'))
3032               return TokenNameswitch;
3033             else
3034               return TokenNameIdentifier;
3035           default :
3036             return TokenNameIdentifier;
3037         }
3038
3039       case 't' : // true
3040         switch (length) {
3041
3042           case 4 :
3043             if ((data[++index] == 'r')
3044               && (data[++index] == 'u')
3045               && (data[++index] == 'e'))
3046               return TokenNametrue;
3047             else
3048               return TokenNameIdentifier;
3049             //            if ((data[++index] == 'h') && (data[++index] == 'i') && (data[++index] == 's'))
3050             //              return TokenNamethis;
3051
3052           default :
3053             return TokenNameIdentifier;
3054         }
3055
3056       case 'v' : //var 
3057         switch (length) {
3058           case 3 :
3059             if ((data[++index] == 'a') && (data[++index] == 'r'))
3060               return TokenNamevar;
3061             else
3062               return TokenNameIdentifier;
3063
3064           default :
3065             return TokenNameIdentifier;
3066         }
3067
3068       case 'w' : //while 
3069         switch (length) {
3070           case 5 :
3071             if ((data[++index] == 'h')
3072               && (data[++index] == 'i')
3073               && (data[++index] == 'l')
3074               && (data[++index] == 'e'))
3075               return TokenNamewhile;
3076             else
3077               return TokenNameIdentifier;
3078             //case 6:if ( (data[++index] =='i') && (data[++index]=='d') && (data[++index]=='e') && (data[++index]=='f')&& (data[++index]=='p'))
3079             //return TokenNamewidefp ;
3080             //else
3081             //return TokenNameIdentifier;
3082           default :
3083             return TokenNameIdentifier;
3084         }
3085
3086       case 'x' : //xor
3087         switch (length) {
3088           case 3 :
3089             if ((data[++index] == 'o') && (data[++index] == 'r'))
3090               return TokenNameXOR;
3091             else
3092               return TokenNameIdentifier;
3093
3094           default :
3095             return TokenNameIdentifier;
3096         }
3097       default :
3098         return TokenNameIdentifier;
3099     }
3100   }
3101   public int scanNumber(boolean dotPrefix) throws InvalidInputException {
3102
3103     //when entering this method the currentCharacter is the firt
3104     //digit of the number , i.e. it may be preceeded by a . when
3105     //dotPrefix is true
3106
3107     boolean floating = dotPrefix;
3108     if ((!dotPrefix) && (currentCharacter == '0')) {
3109       if (getNextChar('x', 'X') >= 0) { //----------hexa-----------------
3110         //force the first char of the hexa number do exist...
3111         // consume next character
3112         unicodeAsBackSlash = false;
3113         if (((currentCharacter = source[currentPosition++]) == '\\')
3114           && (source[currentPosition] == 'u')) {
3115           getNextUnicodeChar();
3116         } else {
3117           if (withoutUnicodePtr != 0) {
3118             withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3119           }
3120         }
3121         if (Character.digit(currentCharacter, 16) == -1)
3122           throw new InvalidInputException(INVALID_HEXA);
3123         //---end forcing--
3124         while (getNextCharAsDigit(16)) {
3125         };
3126         //        if (getNextChar('l', 'L') >= 0)
3127         //          return TokenNameLongLiteral;
3128         //        else
3129         return TokenNameIntegerLiteral;
3130       }
3131
3132       //there is x or X in the number
3133       //potential octal ! ... some one may write 000099.0 ! thus 00100 < 00078.0 is true !!!!! crazy language
3134       if (getNextCharAsDigit()) {
3135         //-------------potential octal-----------------
3136         while (getNextCharAsDigit()) {
3137         };
3138
3139         //        if (getNextChar('l', 'L') >= 0) {
3140         //          return TokenNameLongLiteral;
3141         //        }
3142         //
3143         //        if (getNextChar('f', 'F') >= 0) {
3144         //          return TokenNameFloatingPointLiteral;
3145         //        }
3146
3147         if (getNextChar('d', 'D') >= 0) {
3148           return TokenNameDoubleLiteral;
3149         } else { //make the distinction between octal and float ....
3150           if (getNextChar('.')) { //bingo ! ....
3151             while (getNextCharAsDigit()) {
3152             };
3153             if (getNextChar('e', 'E') >= 0) {
3154               // consume next character
3155               unicodeAsBackSlash = false;
3156               if (((currentCharacter = source[currentPosition++]) == '\\')
3157                 && (source[currentPosition] == 'u')) {
3158                 getNextUnicodeChar();
3159               } else {
3160                 if (withoutUnicodePtr != 0) {
3161                   withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3162                 }
3163               }
3164
3165               if ((currentCharacter == '-') || (currentCharacter == '+')) {
3166                 // consume next character
3167                 unicodeAsBackSlash = false;
3168                 if (((currentCharacter = source[currentPosition++]) == '\\')
3169                   && (source[currentPosition] == 'u')) {
3170                   getNextUnicodeChar();
3171                 } else {
3172                   if (withoutUnicodePtr != 0) {
3173                     withoutUnicodeBuffer[++withoutUnicodePtr] =
3174                       currentCharacter;
3175                   }
3176                 }
3177               }
3178               if (!Character.isDigit(currentCharacter))
3179                 throw new InvalidInputException(INVALID_FLOAT);
3180               while (getNextCharAsDigit()) {
3181               };
3182             }
3183             //            if (getNextChar('f', 'F') >= 0)
3184             //              return TokenNameFloatingPointLiteral;
3185             getNextChar('d', 'D'); //jump over potential d or D
3186             return TokenNameDoubleLiteral;
3187           } else {
3188             return TokenNameIntegerLiteral;
3189           }
3190         }
3191       } else {
3192         /* carry on */
3193       }
3194     }
3195
3196     while (getNextCharAsDigit()) {
3197     };
3198
3199     //    if ((!dotPrefix) && (getNextChar('l', 'L') >= 0))
3200     //      return TokenNameLongLiteral;
3201
3202     if ((!dotPrefix) && (getNextChar('.'))) { //decimal part that can be empty
3203       while (getNextCharAsDigit()) {
3204       };
3205       floating = true;
3206     }
3207
3208     //if floating is true both exponant and suffix may be optional
3209
3210     if (getNextChar('e', 'E') >= 0) {
3211       floating = true;
3212       // consume next character
3213       unicodeAsBackSlash = false;
3214       if (((currentCharacter = source[currentPosition++]) == '\\')
3215         && (source[currentPosition] == 'u')) {
3216         getNextUnicodeChar();
3217       } else {
3218         if (withoutUnicodePtr != 0) {
3219           withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3220         }
3221       }
3222
3223       if ((currentCharacter == '-')
3224         || (currentCharacter == '+')) { // consume next character
3225         unicodeAsBackSlash = false;
3226         if (((currentCharacter = source[currentPosition++]) == '\\')
3227           && (source[currentPosition] == 'u')) {
3228           getNextUnicodeChar();
3229         } else {
3230           if (withoutUnicodePtr != 0) {
3231             withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
3232           }
3233         }
3234       }
3235       if (!Character.isDigit(currentCharacter))
3236         throw new InvalidInputException(INVALID_FLOAT);
3237       while (getNextCharAsDigit()) {
3238       };
3239     }
3240
3241     if (getNextChar('d', 'D') >= 0)
3242       return TokenNameDoubleLiteral;
3243     //    if (getNextChar('f', 'F') >= 0)
3244     //      return TokenNameFloatingPointLiteral;
3245
3246     //the long flag has been tested before
3247
3248     return floating ? TokenNameDoubleLiteral : TokenNameIntegerLiteral;
3249   }
3250   /**
3251    * Search the line number corresponding to a specific position
3252    *
3253    */
3254   public final int getLineNumber(int position) {
3255
3256     if (lineEnds == null)
3257       return 1;
3258     int length = linePtr + 1;
3259     if (length == 0)
3260       return 1;
3261     int g = 0, d = length - 1;
3262     int m = 0;
3263     while (g <= d) {
3264       m = (g + d) / 2;
3265       if (position < lineEnds[m]) {
3266         d = m - 1;
3267       } else if (position > lineEnds[m]) {
3268         g = m + 1;
3269       } else {
3270         return m + 1;
3271       }
3272     }
3273     if (position < lineEnds[m]) {
3274       return m + 1;
3275     }
3276     return m + 2;
3277   }
3278
3279   public void setPHPMode(boolean mode) {
3280     phpMode = mode;
3281   }
3282
3283   public final void setSource(char[] source) {
3284     //the source-buffer is set to sourceString
3285
3286     if (source == null) {
3287       this.source = new char[0];
3288     } else {
3289       this.source = source;
3290     }
3291     startPosition = -1;
3292     initialPosition = currentPosition = 0;
3293     containsAssertKeyword = false;
3294     withoutUnicodeBuffer = new char[this.source.length];
3295
3296   }
3297
3298   public String toString() {
3299     if (startPosition == source.length)
3300       return "EOF\n\n" + new String(source); //$NON-NLS-1$
3301     if (currentPosition > source.length)
3302       return "behind the EOF :-( ....\n\n" + new String(source); //$NON-NLS-1$
3303
3304     char front[] = new char[startPosition];
3305     System.arraycopy(source, 0, front, 0, startPosition);
3306
3307     int middleLength = (currentPosition - 1) - startPosition + 1;
3308     char middle[];
3309     if (middleLength > -1) {
3310       middle = new char[middleLength];
3311       System.arraycopy(source, startPosition, middle, 0, middleLength);
3312     } else {
3313       middle = new char[0];
3314     }
3315
3316     char end[] = new char[source.length - (currentPosition - 1)];
3317     System.arraycopy(
3318       source,
3319       (currentPosition - 1) + 1,
3320       end,
3321       0,
3322       source.length - (currentPosition - 1) - 1);
3323
3324     return new String(front) + "\n===============================\nStarts here -->" //$NON-NLS-1$
3325     + new String(middle) + "<-- Ends here\n===============================\n" //$NON-NLS-1$
3326     + new String(end);
3327   }
3328   public final String toStringAction(int act) {
3329     switch (act) {
3330       case TokenNameERROR :
3331         return "ScannerError(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$
3332       case TokenNameStopPHP :
3333         return "StopPHP(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3334       case TokenNameIdentifier :
3335         return "Identifier(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3336       case TokenNameVariable :
3337         return "Variable(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3338       case TokenNameas :
3339         return "as"; //$NON-NLS-1$
3340       case TokenNamebreak :
3341         return "break"; //$NON-NLS-1$
3342       case TokenNamecase :
3343         return "case"; //$NON-NLS-1$
3344       case TokenNameclass :
3345         return "class"; //$NON-NLS-1$
3346       case TokenNamecontinue :
3347         return "continue"; //$NON-NLS-1$
3348       case TokenNamedefault :
3349         return "default"; //$NON-NLS-1$
3350       case TokenNamedefine :
3351         return "define"; //$NON-NLS-1$
3352       case TokenNamedo :
3353         return "do"; //$NON-NLS-1$
3354       case TokenNameecho :
3355         return "echo"; //$NON-NLS-1$
3356       case TokenNameelse :
3357         return "else"; //$NON-NLS-1$
3358       case TokenNameelseif :
3359         return "elseif"; //$NON-NLS-1$
3360       case TokenNameendfor :
3361         return "endfor"; //$NON-NLS-1$
3362       case TokenNameendforeach :
3363         return "endforeach"; //$NON-NLS-1$
3364       case TokenNameendif :
3365         return "endif"; //$NON-NLS-1$
3366       case TokenNameendswitch :
3367         return "endswitch"; //$NON-NLS-1$
3368       case TokenNameendwhile :
3369         return "endwhile"; //$NON-NLS-1$
3370       case TokenNameextends :
3371         return "extends"; //$NON-NLS-1$
3372       case TokenNamefalse :
3373         return "false"; //$NON-NLS-1$
3374       case TokenNamefor :
3375         return "for"; //$NON-NLS-1$
3376       case TokenNameforeach :
3377         return "foreach"; //$NON-NLS-1$
3378       case TokenNamefunction :
3379         return "function"; //$NON-NLS-1$
3380       case TokenNameglobal :
3381         return "global"; //$NON-NLS-1$
3382       case TokenNameif :
3383         return "if"; //$NON-NLS-1$
3384       case TokenNameinclude :
3385         return "include"; //$NON-NLS-1$
3386       case TokenNameinclude_once :
3387         return "include_once"; //$NON-NLS-1$
3388       case TokenNamelist :
3389         return "list"; //$NON-NLS-1$
3390       case TokenNamenew :
3391         return "new"; //$NON-NLS-1$
3392       case TokenNamenull :
3393         return "null"; //$NON-NLS-1$
3394       case TokenNameprint :
3395         return "print"; //$NON-NLS-1$
3396       case TokenNamerequire :
3397         return "require"; //$NON-NLS-1$
3398       case TokenNamerequire_once :
3399         return "require_once"; //$NON-NLS-1$
3400       case TokenNamereturn :
3401         return "return"; //$NON-NLS-1$
3402       case TokenNamestatic :
3403         return "static"; //$NON-NLS-1$
3404       case TokenNameswitch :
3405         return "switch"; //$NON-NLS-1$
3406       case TokenNametrue :
3407         return "true"; //$NON-NLS-1$
3408       case TokenNamevar :
3409         return "var"; //$NON-NLS-1$
3410       case TokenNamewhile :
3411         return "while"; //$NON-NLS-1$
3412       case TokenNameIntegerLiteral :
3413         return "Integer(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3414       case TokenNameDoubleLiteral :
3415         return "Double(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3416       case TokenNameStringLiteral :
3417         return "String(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3418       case TokenNameStringConstant :
3419         return "StringConstant(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3420       case TokenNameStringInterpolated :
3421         return "StringInterpolated(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
3422       case TokenNameHEREDOC :
3423         return "HEREDOC(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$
3424
3425       case TokenNamePLUS_PLUS :
3426         return "++"; //$NON-NLS-1$
3427       case TokenNameMINUS_MINUS :
3428         return "--"; //$NON-NLS-1$
3429       case TokenNameEQUAL_EQUAL :
3430         return "=="; //$NON-NLS-1$
3431       case TokenNameEQUAL_GREATER :
3432         return "=>"; //$NON-NLS-1$
3433       case TokenNameLESS_EQUAL :
3434         return "<="; //$NON-NLS-1$
3435       case TokenNameGREATER_EQUAL :
3436         return ">="; //$NON-NLS-1$
3437       case TokenNameNOT_EQUAL :
3438         return "!="; //$NON-NLS-1$
3439       case TokenNameLEFT_SHIFT :
3440         return "<<"; //$NON-NLS-1$
3441       case TokenNameRIGHT_SHIFT :
3442         return ">>"; //$NON-NLS-1$
3443       case TokenNamePLUS_EQUAL :
3444         return "+="; //$NON-NLS-1$
3445       case TokenNameMINUS_EQUAL :
3446         return "-="; //$NON-NLS-1$
3447       case TokenNameMULTIPLY_EQUAL :
3448         return "*="; //$NON-NLS-1$
3449       case TokenNameDIVIDE_EQUAL :
3450         return "/="; //$NON-NLS-1$
3451       case TokenNameAND_EQUAL :
3452         return "&="; //$NON-NLS-1$
3453       case TokenNameOR_EQUAL :
3454         return "|="; //$NON-NLS-1$
3455       case TokenNameXOR_EQUAL :
3456         return "^="; //$NON-NLS-1$
3457       case TokenNameREMAINDER_EQUAL :
3458         return "%="; //$NON-NLS-1$
3459       case TokenNameLEFT_SHIFT_EQUAL :
3460         return "<<="; //$NON-NLS-1$
3461       case TokenNameRIGHT_SHIFT_EQUAL :
3462         return ">>="; //$NON-NLS-1$
3463       case TokenNameOR_OR :
3464         return "||"; //$NON-NLS-1$
3465       case TokenNameAND_AND :
3466         return "&&"; //$NON-NLS-1$
3467       case TokenNamePLUS :
3468         return "+"; //$NON-NLS-1$
3469       case TokenNameMINUS :
3470         return "-"; //$NON-NLS-1$
3471       case TokenNameMINUS_GREATER :
3472         return "->";
3473       case TokenNameNOT :
3474         return "!"; //$NON-NLS-1$
3475       case TokenNameREMAINDER :
3476         return "%"; //$NON-NLS-1$
3477       case TokenNameXOR :
3478         return "^"; //$NON-NLS-1$
3479       case TokenNameAND :
3480         return "&"; //$NON-NLS-1$
3481       case TokenNameMULTIPLY :
3482         return "*"; //$NON-NLS-1$
3483       case TokenNameOR :
3484         return "|"; //$NON-NLS-1$
3485       case TokenNameTWIDDLE :
3486         return "~"; //$NON-NLS-1$
3487       case TokenNameTWIDDLE_EQUAL :
3488         return "~="; //$NON-NLS-1$
3489       case TokenNameDIVIDE :
3490         return "/"; //$NON-NLS-1$
3491       case TokenNameGREATER :
3492         return ">"; //$NON-NLS-1$
3493       case TokenNameLESS :
3494         return "<"; //$NON-NLS-1$
3495       case TokenNameLPAREN :
3496         return "("; //$NON-NLS-1$
3497       case TokenNameRPAREN :
3498         return ")"; //$NON-NLS-1$
3499       case TokenNameLBRACE :
3500         return "{"; //$NON-NLS-1$
3501       case TokenNameRBRACE :
3502         return "}"; //$NON-NLS-1$
3503       case TokenNameLBRACKET :
3504         return "["; //$NON-NLS-1$
3505       case TokenNameRBRACKET :
3506         return "]"; //$NON-NLS-1$
3507       case TokenNameSEMICOLON :
3508         return ";"; //$NON-NLS-1$
3509       case TokenNameQUESTION :
3510         return "?"; //$NON-NLS-1$
3511       case TokenNameCOLON :
3512         return ":"; //$NON-NLS-1$
3513       case TokenNameCOMMA :
3514         return ","; //$NON-NLS-1$
3515       case TokenNameDOT :
3516         return "."; //$NON-NLS-1$
3517       case TokenNameEQUAL :
3518         return "="; //$NON-NLS-1$
3519       case TokenNameAT :
3520         return "@";
3521       case TokenNameDOLLAR_LBRACE :
3522         return "${";
3523       case TokenNameEOF :
3524         return "EOF"; //$NON-NLS-1$
3525       default :
3526         return "not-a-token(" + (new Integer(act)) + ") " + new String(getCurrentTokenSource()); //$NON-NLS-1$
3527     }
3528   }
3529
3530   public Scanner(
3531     boolean tokenizeComments,
3532     boolean tokenizeWhiteSpace,
3533     boolean checkNonExternalizedStringLiterals) {
3534     this(
3535       tokenizeComments,
3536       tokenizeWhiteSpace,
3537       checkNonExternalizedStringLiterals,
3538       false);
3539   }
3540
3541   public Scanner(
3542     boolean tokenizeComments,
3543     boolean tokenizeWhiteSpace,
3544     boolean checkNonExternalizedStringLiterals,
3545     boolean assertMode) {
3546     this.eofPosition = Integer.MAX_VALUE;
3547     this.tokenizeComments = tokenizeComments;
3548     this.tokenizeWhiteSpace = tokenizeWhiteSpace;
3549     this.checkNonExternalizedStringLiterals =
3550       checkNonExternalizedStringLiterals;
3551     this.assertMode = assertMode;
3552   }
3553
3554   private void checkNonExternalizeString() throws InvalidInputException {
3555     if (currentLine == null)
3556       return;
3557     parseTags(currentLine);
3558   }
3559
3560   private void parseTags(NLSLine line) throws InvalidInputException {
3561     String s = new String(getCurrentTokenSource());
3562     int pos = s.indexOf(TAG_PREFIX);
3563     int lineLength = line.size();
3564     while (pos != -1) {
3565       int start = pos + TAG_PREFIX_LENGTH;
3566       int end = s.indexOf(TAG_POSTFIX, start);
3567       String index = s.substring(start, end);
3568       int i = 0;
3569       try {
3570         i = Integer.parseInt(index) - 1;
3571         // Tags are one based not zero based.
3572       } catch (NumberFormatException e) {
3573         i = -1; // we don't want to consider this as a valid NLS tag
3574       }
3575       if (line.exists(i)) {
3576         line.set(i, null);
3577       }
3578       pos = s.indexOf(TAG_PREFIX, start);
3579     }
3580
3581     this.nonNLSStrings = new StringLiteral[lineLength];
3582     int nonNLSCounter = 0;
3583     for (Iterator iterator = line.iterator(); iterator.hasNext();) {
3584       StringLiteral literal = (StringLiteral) iterator.next();
3585       if (literal != null) {
3586         this.nonNLSStrings[nonNLSCounter++] = literal;
3587       }
3588     }
3589     if (nonNLSCounter == 0) {
3590       this.nonNLSStrings = null;
3591       currentLine = null;
3592       return;
3593     }
3594     this.wasNonExternalizedStringLiteral = true;
3595     if (nonNLSCounter != lineLength) {
3596       System.arraycopy(
3597         this.nonNLSStrings,
3598         0,
3599         (this.nonNLSStrings = new StringLiteral[nonNLSCounter]),
3600         0,
3601         nonNLSCounter);
3602     }
3603     currentLine = null;
3604   }
3605 }