KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > compiler > Lex


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 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 JavaDoc textValue;
25 }
26
27 public class Lex implements TokenId {
28     private int lastChar;
29     private StringBuffer JavaDoc textBuffer;
30     private Token currentToken;
31     private Token lookAheadTokens;
32
33     private String JavaDoc input;
34     private int position, maxlen, lineNumber;
35
36     /**
37      * Constructs a lexical analyzer.
38      */

39     public Lex(String JavaDoc s) {
40         lastChar = -1;
41         textBuffer = new StringBuffer JavaDoc();
42         currentToken = new Token();
43         lookAheadTokens = null;
44
45         input = s;
46         position = 0;
47         maxlen = s.length();
48         lineNumber = 0;
49     }
50
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      */

65     public int lookAhead() {
66         return lookAhead(0);
67     }
68
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
88     public String JavaDoc getString() {
89         return currentToken.textValue;
90     }
91
92     public long getLong() {
93         return currentToken.longValue;
94     }
95
96     public double getDouble() {
97         return currentToken.doubleValue;
98     }
99
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
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 JavaDoc 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 ('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '_'
137                  || c == '$')
138             return readIdentifier(c, token);
139         else
140             return readSeparator(c);
141     }
142
143     private int getNextNonWhiteChar() {
144         int c;
145         do {
146             c = getc();
147             if (c == '/') {
148                 c = getc();
149                 if (c == '/')
150                     do {
151                         c = getc();
152                     } while (c != '\n' && c != '\r' && c != -1);
153                 else if (c == '*')
154                     while (true) {
155                         c = getc();
156                         if (c == -1)
157                             break;
158                         else if (c == '*')
159                             if ((c = getc()) == '/') {
160                                 c = ' ';
161                                 break;
162                             }
163                             else
164                                 ungetc(c);
165                     }
166                 else {
167                     ungetc(c);
168                     c = '/';
169                 }
170             }
171         } while(isBlank(c));
172         return c;
173     }
174
175     private int readCharConst(Token token) {
176         int c;
177         int value = 0;
178         while ((c = getc()) != '\'')
179             if (c == '\\')
180                 value = readEscapeChar();
181             else if (c < 0x20) {
182                 if (c == '\n')
183                     ++lineNumber;
184
185                 return BadToken;
186             }
187             else
188                 value = c;
189
190         token.longValue = value;
191         return CharConstant;
192     }
193
194     private int readEscapeChar() {
195         int c = getc();
196         if (c == 'n')
197             c = '\n';
198         else if (c == 't')
199             c = '\t';
200         else if (c == 'r')
201             c = '\r';
202         else if (c == 'f')
203             c = '\f';
204         else if (c == '\n')
205             ++lineNumber;
206
207         return c;
208     }
209
210     private int readStringL(Token token) {
211         int c;
212         StringBuffer JavaDoc tbuf = textBuffer;
213         tbuf.setLength(0);
214         for (;;) {
215             while ((c = getc()) != '"') {
216                 if (c == '\\')
217                     c = readEscapeChar();
218                 else if (c == '\n' || c < 0) {
219                     ++lineNumber;
220                     return BadToken;
221                 }
222
223                 tbuf.append((char)c);
224             }
225
226             for (;;) {
227                 c = getc();
228                 if (c == '\n')
229                     ++lineNumber;
230                 else if (!isBlank(c))
231                     break;
232             }
233
234             if (c != '"') {
235                 ungetc(c);
236                 break;
237             }
238         }
239
240         token.textValue = tbuf.toString();
241         return StringL;
242     }
243
244     private int readNumber(int c, Token token) {
245         long value = 0;
246         int c2 = getc();
247         if (c == '0')
248             if (c2 == 'X' || c2 == 'x')
249                 for (;;) {
250                     c = getc();
251                     if ('0' <= c && c <= '9')
252                         value = value * 16 + (long)(c - '0');
253                     else if ('A' <= c && c <= 'F')
254                         value = value * 16 + (long)(c - 'A' + 10);
255                     else if ('a' <= c && c <= 'f')
256                         value = value * 16 + (long)(c - 'a' + 10);
257                     else {
258                         token.longValue = value;
259                         if (c == 'L' || c == 'l')
260                             return LongConstant;
261                         else {
262                             ungetc(c);
263                             return IntConstant;
264                         }
265                     }
266                 }
267             else if ('0' <= c2 && c2 <= '7') {
268                 value = c2 - '0';
269                 for (;;) {
270                     c = getc();
271                     if ('0' <= c && c <= '7')
272                         value = value * 8 + (long)(c - '0');
273                     else {
274                         token.longValue = value;
275                         if (c == 'L' || c == 'l')
276                             return LongConstant;
277                         else {
278                             ungetc(c);
279                             return IntConstant;
280                         }
281                     }
282                 }
283             }
284
285         value = c - '0';
286         while ('0' <= c2 && c2 <= '9') {
287             value = value * 10 + c2 - '0';
288             c2 = getc();
289         }
290
291         token.longValue = value;
292         if (c2 == 'F' || c2 == 'f') {
293             token.doubleValue = (double)value;
294             return FloatConstant;
295         }
296         else if (c2 == 'E' || c2 == 'e'
297                  || c2 == 'D' || c2 == 'd' || c2 == '.') {
298             StringBuffer JavaDoc tbuf = textBuffer;
299             tbuf.setLength(0);
300             tbuf.append(value);
301             return readDouble(tbuf, c2, token);
302         }
303         else if (c2 == 'L' || c2 == 'l')
304             return LongConstant;
305         else {
306             ungetc(c2);
307             return IntConstant;
308         }
309     }
310
311     private int readDouble(StringBuffer JavaDoc sbuf, int c, Token token) {
312         if (c != 'E' && c != 'e' && c != 'D' && c != 'd') {
313             sbuf.append((char)c);
314             for (;;) {
315                 c = getc();
316                 if ('0' <= c && c <= '9')
317                     sbuf.append((char)c);
318                 else
319                     break;
320             }
321         }
322
323         if (c == 'E' || c == 'e') {
324             sbuf.append((char)c);
325             c = getc();
326             if (c == '+' || c == '-') {
327                 sbuf.append((char)c);
328                 c = getc();
329             }
330
331             while ('0' <= c && c <= '9') {
332                 sbuf.append((char)c);
333                 c = getc();
334             }
335         }
336
337         try {
338             token.doubleValue = Double.parseDouble(sbuf.toString());
339         }
340         catch (NumberFormatException JavaDoc e) {
341             return BadToken;
342         }
343
344         if (c == 'F' || c == 'f')
345             return FloatConstant;
346         else {
347             if (c != 'D' && c != 'd')
348                 ungetc(c);
349
350             return DoubleConstant;
351         }
352     }
353
354     // !"#$%&'( )*+,-./0 12345678 9:;<=>?
355
private static final int[] equalOps
356         = { NEQ, 0, 0, 0, MOD_E, AND_E, 0, 0,
357              0, MUL_E, PLUS_E, 0, MINUS_E, 0, DIV_E, 0,
358              0, 0, 0, 0, 0, 0, 0, 0,
359              0, 0, 0, LE, EQ, GE, 0 };
360
361     private int readSeparator(int c) {
362         int c2, c3;
363         if ('!' <= c && c <= '?') {
364             int t = equalOps[c - '!'];
365             if (t == 0)
366                 return c;
367             else {
368                 c2 = getc();
369                 if (c == c2)
370                     switch (c) {
371                     case '=' :
372                         return EQ;
373                     case '+' :
374                         return PLUSPLUS;
375                     case '-' :
376                         return MINUSMINUS;
377                     case '&' :
378                         return ANDAND;
379                     case '<' :
380                         c3 = getc();
381                         if (c3 == '=')
382                             return LSHIFT_E;
383                         else {
384                             ungetc(c3);
385                             return LSHIFT;
386                         }
387                     case '>' :
388                         c3 = getc();
389                         if (c3 == '=')
390                             return RSHIFT_E;
391                         else if (c3 == '>') {
392                             c3 = getc();
393                             if (c3 == '=')
394                                 return ARSHIFT_E;
395                             else {
396                                 ungetc(c3);
397                                 return ARSHIFT;
398                             }
399                         }
400                         else {
401                             ungetc(c3);
402                             return RSHIFT;
403                         }
404                     default :
405                         break;
406                     }
407                 else if (c2 == '=')
408                     return t;
409             }
410         }
411         else if (c == '^') {
412             c2 = getc();
413             if (c2 == '=')
414                 return EXOR_E;
415         }
416         else if (c == '|') {
417             c2 = getc();
418             if (c2 == '=')
419                 return OR_E;
420             else if (c2 == '|')
421                 return OROR;
422         }
423         else
424             return c;
425
426         ungetc(c2);
427         return c;
428     }
429
430     private int readIdentifier(int c, Token token) {
431         StringBuffer JavaDoc tbuf = textBuffer;
432         tbuf.setLength(0);
433
434         do {
435             tbuf.append((char)c);
436             c = getc();
437         } while ('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '_'
438                  || c == '$' || '0' <= c && c <= '9');
439
440         ungetc(c);
441
442         String JavaDoc name = tbuf.toString();
443         int t = ktable.lookup(name);
444         if (t >= 0)
445             return t;
446         else {
447             /* tbuf.toString() is executed quickly since it does not
448              * need memory copy. Using a hand-written extensible
449              * byte-array class instead of StringBuffer is not a good idea
450              * for execution speed. Converting a byte array to a String
451              * object is very slow. Using an extensible char array
452              * might be OK.
453              */

454             token.textValue = name;
455             return Identifier;
456         }
457     }
458
459     private static final KeywordTable ktable = new KeywordTable();
460
461     static {
462         ktable.append("abstract", ABSTRACT);
463         ktable.append("boolean", BOOLEAN);
464         ktable.append("break", BREAK);
465         ktable.append("byte", BYTE);
466         ktable.append("case", CASE);
467         ktable.append("catch", CATCH);
468         ktable.append("char", CHAR);
469         ktable.append("class", CLASS);
470         ktable.append("const", CONST);
471         ktable.append("continue", CONTINUE);
472         ktable.append("default", DEFAULT);
473         ktable.append("do", DO);
474         ktable.append("double", DOUBLE);
475         ktable.append("else", ELSE);
476         ktable.append("extends", EXTENDS);
477         ktable.append("false", FALSE);
478         ktable.append("final", FINAL);
479         ktable.append("finally", FINALLY);
480         ktable.append("float", FLOAT);
481         ktable.append("for", FOR);
482         ktable.append("goto", GOTO);
483         ktable.append("if", IF);
484         ktable.append("implements", IMPLEMENTS);
485         ktable.append("import", IMPORT);
486         ktable.append("instanceof", INSTANCEOF);
487         ktable.append("int", INT);
488         ktable.append("interface", INTERFACE);
489         ktable.append("long", LONG);
490         ktable.append("native", NATIVE);
491         ktable.append("new", NEW);
492         ktable.append("null", NULL);
493         ktable.append("package", PACKAGE);
494         ktable.append("private", PRIVATE);
495         ktable.append("protected", PROTECTED);
496         ktable.append("public", PUBLIC);
497         ktable.append("return", RETURN);
498         ktable.append("short", SHORT);
499         ktable.append("static", STATIC);
500         ktable.append("strict", STRICT);
501         ktable.append("super", SUPER);
502         ktable.append("switch", SWITCH);
503         ktable.append("synchronized", SYNCHRONIZED);
504         ktable.append("this", THIS);
505         ktable.append("throw", THROW);
506         ktable.append("throws", THROWS);
507         ktable.append("transient", TRANSIENT);
508         ktable.append("true", TRUE);
509         ktable.append("try", TRY);
510         ktable.append("void", VOID);
511         ktable.append("volatile", VOLATILE);
512         ktable.append("while", WHILE);
513     }
514
515     private static boolean isBlank(int c) {
516         return c == ' ' || c == '\t' || c == '\f' || c == '\r'
517             || c == '\n';
518     }
519
520     private static boolean isDigit(int c) {
521         return '0' <= c && c <= '9';
522     }
523
524     private void ungetc(int c) {
525         lastChar = c;
526     }
527
528     private int getc() {
529         if (lastChar < 0)
530             if (position < maxlen)
531                 return input.charAt(position++);
532             else
533                 return -1;
534         else {
535             int c = lastChar;
536             lastChar = -1;
537             return c;
538         }
539     }
540 }
541
Popular Tags