• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License.  Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */
15 
16 package javassist.compiler;
17 
18 class Token {
19     public Token next = null;
20     public int tokenId;
21 
22     public long longValue;
23     public double doubleValue;
24     public String textValue;
25 }
26 
27 public class Lex implements TokenId {
28     private int lastChar;
29     private StringBuffer textBuffer;
30     private Token currentToken;
31     private Token lookAheadTokens;
32 
33     private String input;
34     private int position, maxlen, lineNumber;
35 
36     /**
37      * Constructs a lexical analyzer.
38      */
Lex(String s)39     public Lex(String s) {
40         lastChar = -1;
41         textBuffer = new StringBuffer();
42         currentToken = new Token();
43         lookAheadTokens = null;
44 
45         input = s;
46         position = 0;
47         maxlen = s.length();
48         lineNumber = 0;
49     }
50 
get()51     public int get() {
52         if (lookAheadTokens == null)
53             return get(currentToken);
54         else {
55             Token t;
56             currentToken = t = lookAheadTokens;
57             lookAheadTokens = lookAheadTokens.next;
58             return t.tokenId;
59         }
60     }
61 
62     /**
63      * Looks at the next token.
64      */
lookAhead()65     public int lookAhead() {
66         return lookAhead(0);
67     }
68 
lookAhead(int i)69     public int lookAhead(int i) {
70         Token tk = lookAheadTokens;
71         if (tk == null) {
72             lookAheadTokens = tk = currentToken;  // reuse an object!
73             tk.next = null;
74             get(tk);
75         }
76 
77         for (; i-- > 0; tk = tk.next)
78             if (tk.next == null) {
79                 Token tk2;
80                 tk.next = tk2 = new Token();
81                 get(tk2);
82             }
83 
84         currentToken = tk;
85         return tk.tokenId;
86     }
87 
getString()88     public String getString() {
89         return currentToken.textValue;
90     }
91 
getLong()92     public long getLong() {
93         return currentToken.longValue;
94     }
95 
getDouble()96     public double getDouble() {
97         return currentToken.doubleValue;
98     }
99 
get(Token token)100     private int get(Token token) {
101         int t;
102         do {
103             t = readLine(token);
104         } while (t == '\n');
105         token.tokenId = t;
106         return t;
107     }
108 
readLine(Token token)109     private int readLine(Token token) {
110         int c = getNextNonWhiteChar();
111         if(c < 0)
112             return c;
113         else if(c == '\n') {
114             ++lineNumber;
115             return '\n';
116         }
117         else if (c == '\'')
118             return readCharConst(token);
119         else if (c == '"')
120             return readStringL(token);
121         else if ('0' <= c && c <= '9')
122             return readNumber(c, token);
123         else if(c == '.'){
124             c = getc();
125             if ('0' <= c && c <= '9') {
126                 StringBuffer tbuf = textBuffer;
127                 tbuf.setLength(0);
128                 tbuf.append('.');
129                 return readDouble(tbuf, c, token);
130             }
131             else{
132                 ungetc(c);
133                 return readSeparator('.');
134             }
135         }
136         else if (Character.isJavaIdentifierStart((char)c))
137             return readIdentifier(c, token);
138         else
139             return readSeparator(c);
140     }
141 
getNextNonWhiteChar()142     private int getNextNonWhiteChar() {
143         int c;
144         do {
145             c = getc();
146             if (c == '/') {
147                 c = getc();
148                 if (c == '/')
149                     do {
150                         c = getc();
151                     } while (c != '\n' && c != '\r' && c != -1);
152                 else if (c == '*')
153                     while (true) {
154                         c = getc();
155                         if (c == -1)
156                             break;
157                         else if (c == '*')
158                             if ((c = getc()) == '/') {
159                                 c = ' ';
160                                 break;
161                             }
162                             else
163                                 ungetc(c);
164                     }
165                 else {
166                     ungetc(c);
167                     c = '/';
168                 }
169             }
170         } while(isBlank(c));
171         return c;
172     }
173 
readCharConst(Token token)174     private int readCharConst(Token token) {
175         int c;
176         int value = 0;
177         while ((c = getc()) != '\'')
178             if (c == '\\')
179                 value = readEscapeChar();
180             else if (c < 0x20) {
181                 if (c == '\n')
182                     ++lineNumber;
183 
184                 return BadToken;
185             }
186             else
187                 value = c;
188 
189         token.longValue = value;
190         return CharConstant;
191     }
192 
readEscapeChar()193     private int readEscapeChar() {
194         int c = getc();
195         if (c == 'n')
196             c = '\n';
197         else if (c == 't')
198             c = '\t';
199         else if (c == 'r')
200             c = '\r';
201         else if (c == 'f')
202             c = '\f';
203         else if (c == '\n')
204             ++lineNumber;
205 
206         return c;
207     }
208 
readStringL(Token token)209     private int readStringL(Token token) {
210         int c;
211         StringBuffer tbuf = textBuffer;
212         tbuf.setLength(0);
213         for (;;) {
214             while ((c = getc()) != '"') {
215                 if (c == '\\')
216                     c = readEscapeChar();
217                 else if (c == '\n' || c < 0) {
218                     ++lineNumber;
219                     return BadToken;
220                 }
221 
222                 tbuf.append((char)c);
223             }
224 
225             for (;;) {
226                 c = getc();
227                 if (c == '\n')
228                     ++lineNumber;
229                 else if (!isBlank(c))
230                     break;
231             }
232 
233             if (c != '"') {
234                 ungetc(c);
235                 break;
236             }
237         }
238 
239         token.textValue = tbuf.toString();
240         return StringL;
241     }
242 
readNumber(int c, Token token)243     private int readNumber(int c, Token token) {
244         long value = 0;
245         int c2 = getc();
246         if (c == '0')
247             if (c2 == 'X' || c2 == 'x')
248                 for (;;) {
249                     c = getc();
250                     if ('0' <= c && c <= '9')
251                         value = value * 16 + (long)(c - '0');
252                     else if ('A' <= c && c <= 'F')
253                         value = value * 16 + (long)(c - 'A' + 10);
254                     else if ('a' <= c && c <= 'f')
255                         value = value * 16 + (long)(c - 'a' + 10);
256                     else {
257                         token.longValue = value;
258                         if (c == 'L' || c == 'l')
259                             return LongConstant;
260                         else {
261                             ungetc(c);
262                             return IntConstant;
263                         }
264                     }
265                 }
266             else if ('0' <= c2 && c2 <= '7') {
267                 value = c2 - '0';
268                 for (;;) {
269                     c = getc();
270                     if ('0' <= c && c <= '7')
271                         value = value * 8 + (long)(c - '0');
272                     else {
273                         token.longValue = value;
274                         if (c == 'L' || c == 'l')
275                             return LongConstant;
276                         else {
277                             ungetc(c);
278                             return IntConstant;
279                         }
280                     }
281                 }
282             }
283 
284         value = c - '0';
285         while ('0' <= c2 && c2 <= '9') {
286             value = value * 10 + c2 - '0';
287             c2 = getc();
288         }
289 
290         token.longValue = value;
291         if (c2 == 'F' || c2 == 'f') {
292             token.doubleValue = (double)value;
293             return FloatConstant;
294         }
295         else if (c2 == 'E' || c2 == 'e'
296                  || c2 == 'D' || c2 == 'd' || c2 == '.') {
297             StringBuffer tbuf = textBuffer;
298             tbuf.setLength(0);
299             tbuf.append(value);
300             return readDouble(tbuf, c2, token);
301         }
302         else if (c2 == 'L' || c2 == 'l')
303             return LongConstant;
304         else {
305             ungetc(c2);
306             return IntConstant;
307         }
308     }
309 
readDouble(StringBuffer sbuf, int c, Token token)310     private int readDouble(StringBuffer sbuf, int c, Token token) {
311         if (c != 'E' && c != 'e' && c != 'D' && c != 'd') {
312             sbuf.append((char)c);
313             for (;;) {
314                 c = getc();
315                 if ('0' <= c && c <= '9')
316                     sbuf.append((char)c);
317                 else
318                     break;
319             }
320         }
321 
322         if (c == 'E' || c == 'e') {
323             sbuf.append((char)c);
324             c = getc();
325             if (c == '+' || c == '-') {
326                 sbuf.append((char)c);
327                 c = getc();
328             }
329 
330             while ('0' <= c && c <= '9') {
331                 sbuf.append((char)c);
332                 c = getc();
333             }
334         }
335 
336         try {
337             token.doubleValue = Double.parseDouble(sbuf.toString());
338         }
339         catch (NumberFormatException e) {
340             return BadToken;
341         }
342 
343         if (c == 'F' || c == 'f')
344             return FloatConstant;
345         else {
346             if (c != 'D' && c != 'd')
347                 ungetc(c);
348 
349             return DoubleConstant;
350         }
351     }
352 
353     // !"#$%&'(    )*+,-./0    12345678    9:;<=>?
354     private static final int[] equalOps
355         =  { NEQ, 0, 0, 0, MOD_E, AND_E, 0, 0,
356              0, MUL_E, PLUS_E, 0, MINUS_E, 0, DIV_E, 0,
357              0, 0, 0, 0, 0, 0, 0, 0,
358              0, 0, 0, LE, EQ, GE, 0 };
359 
readSeparator(int c)360     private int readSeparator(int c) {
361         int c2, c3;
362         if ('!' <= c && c <= '?') {
363             int t = equalOps[c - '!'];
364             if (t == 0)
365                 return c;
366             else {
367                 c2 = getc();
368                 if (c == c2)
369                     switch (c) {
370                     case '=' :
371                         return EQ;
372                     case '+' :
373                         return PLUSPLUS;
374                     case '-' :
375                         return MINUSMINUS;
376                     case '&' :
377                         return ANDAND;
378                     case '<' :
379                         c3 = getc();
380                         if (c3 == '=')
381                             return LSHIFT_E;
382                         else {
383                             ungetc(c3);
384                             return LSHIFT;
385                         }
386                     case '>' :
387                         c3 = getc();
388                         if (c3 == '=')
389                             return RSHIFT_E;
390                         else if (c3 == '>') {
391                             c3 = getc();
392                             if (c3 == '=')
393                                 return ARSHIFT_E;
394                             else {
395                                 ungetc(c3);
396                                 return ARSHIFT;
397                             }
398                         }
399                         else {
400                             ungetc(c3);
401                             return RSHIFT;
402                         }
403                     default :
404                         break;
405                     }
406                 else if (c2 == '=')
407                     return t;
408             }
409         }
410         else if (c == '^') {
411             c2 = getc();
412             if (c2 == '=')
413                 return EXOR_E;
414         }
415         else if (c == '|') {
416             c2 = getc();
417             if (c2 == '=')
418                 return OR_E;
419             else if (c2 == '|')
420                 return OROR;
421         }
422         else
423             return c;
424 
425         ungetc(c2);
426         return c;
427     }
428 
readIdentifier(int c, Token token)429     private int readIdentifier(int c, Token token) {
430         StringBuffer tbuf = textBuffer;
431         tbuf.setLength(0);
432 
433         do {
434             tbuf.append((char)c);
435             c = getc();
436         } while (Character.isJavaIdentifierPart((char)c));
437 
438         ungetc(c);
439 
440         String name = tbuf.toString();
441         int t = ktable.lookup(name);
442         if (t >= 0)
443             return t;
444         else {
445             /* tbuf.toString() is executed quickly since it does not
446              * need memory copy.  Using a hand-written extensible
447              * byte-array class instead of StringBuffer is not a good idea
448              * for execution speed.  Converting a byte array to a String
449              * object is very slow.  Using an extensible char array
450              * might be OK.
451              */
452             token.textValue = name;
453             return Identifier;
454         }
455     }
456 
457     private static final KeywordTable ktable = new KeywordTable();
458 
459     static {
460         ktable.append("abstract", ABSTRACT);
461         ktable.append("boolean", BOOLEAN);
462         ktable.append("break", BREAK);
463         ktable.append("byte", BYTE);
464         ktable.append("case", CASE);
465         ktable.append("catch", CATCH);
466         ktable.append("char", CHAR);
467         ktable.append("class", CLASS);
468         ktable.append("const", CONST);
469         ktable.append("continue", CONTINUE);
470         ktable.append("default", DEFAULT);
471         ktable.append("do", DO);
472         ktable.append("double", DOUBLE);
473         ktable.append("else", ELSE);
474         ktable.append("extends", EXTENDS);
475         ktable.append("false", FALSE);
476         ktable.append("final", FINAL);
477         ktable.append("finally", FINALLY);
478         ktable.append("float", FLOAT);
479         ktable.append("for", FOR);
480         ktable.append("goto", GOTO);
481         ktable.append("if", IF);
482         ktable.append("implements", IMPLEMENTS);
483         ktable.append("import", IMPORT);
484         ktable.append("instanceof", INSTANCEOF);
485         ktable.append("int", INT);
486         ktable.append("interface", INTERFACE);
487         ktable.append("long", LONG);
488         ktable.append("native", NATIVE);
489         ktable.append("new", NEW);
490         ktable.append("null", NULL);
491         ktable.append("package", PACKAGE);
492         ktable.append("private", PRIVATE);
493         ktable.append("protected", PROTECTED);
494         ktable.append("public", PUBLIC);
495         ktable.append("return", RETURN);
496         ktable.append("short", SHORT);
497         ktable.append("static", STATIC);
498         ktable.append("strictfp", STRICT);
499         ktable.append("super", SUPER);
500         ktable.append("switch", SWITCH);
501         ktable.append("synchronized", SYNCHRONIZED);
502         ktable.append("this", THIS);
503         ktable.append("throw", THROW);
504         ktable.append("throws", THROWS);
505         ktable.append("transient", TRANSIENT);
506         ktable.append("true", TRUE);
507         ktable.append("try", TRY);
508         ktable.append("void", VOID);
509         ktable.append("volatile", VOLATILE);
510         ktable.append("while", WHILE);
511     }
512 
isBlank(int c)513     private static boolean isBlank(int c) {
514         return c == ' ' || c == '\t' || c == '\f' || c == '\r'
515             || c == '\n';
516     }
517 
isDigit(int c)518     private static boolean isDigit(int c) {
519         return '0' <= c && c <= '9';
520     }
521 
ungetc(int c)522     private void ungetc(int c) {
523         lastChar = c;
524     }
525 
getTextAround()526     public String getTextAround() {
527         int begin = position - 10;
528         if (begin < 0)
529             begin = 0;
530 
531         int end = position + 10;
532         if (end > maxlen)
533             end = maxlen;
534 
535         return input.substring(begin, end);
536     }
537 
getc()538     private int getc() {
539         if (lastChar < 0)
540             if (position < maxlen)
541                 return input.charAt(position++);
542             else
543                 return -1;
544         else {
545             int c = lastChar;
546             lastChar = -1;
547             return c;
548         }
549     }
550 }
551