KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > java > swing > plaf > gtk > GTKScanner


1 /*
2  * @(#)GTKScanner.java 1.40 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package com.sun.java.swing.plaf.gtk;
9
10 import java.io.*;
11 import java.util.HashMap JavaDoc;
12
13 /**
14  * @author Shannon Hickey
15  * @version 1.40 12/19/03
16  */

17 class GTKScanner {
18
19     public static final String JavaDoc CHARS_a_2_z = "abcdefghijklmnopqrstuvwxyz";
20     public static final String JavaDoc CHARS_A_2_Z = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
21     public static final String JavaDoc CHARS_DIGITS = "0123456789";
22
23     public static final int TOKEN_EOF = -1;
24     public static final int TOKEN_LEFT_PAREN = '(';
25     public static final int TOKEN_RIGHT_PAREN = ')';
26     public static final int TOKEN_LEFT_CURLY = '{';
27     public static final int TOKEN_RIGHT_CURLY = '}';
28     public static final int TOKEN_LEFT_BRACE = '[';
29     public static final int TOKEN_RIGHT_BRACE = ']';
30     public static final int TOKEN_EQUAL_SIGN = '=';
31     public static final int TOKEN_COMMA = ',';
32     public static final int TOKEN_NONE = 256;
33     public static final int TOKEN_ERROR = TOKEN_NONE + 1;
34     public static final int TOKEN_CHAR = TOKEN_ERROR + 1;
35     public static final int TOKEN_BINARY = TOKEN_CHAR + 1;
36     public static final int TOKEN_OCTAL = TOKEN_BINARY + 1;
37     public static final int TOKEN_INT = TOKEN_OCTAL + 1;
38     public static final int TOKEN_HEX = TOKEN_INT + 1;
39     public static final int TOKEN_FLOAT = TOKEN_HEX + 1;
40     public static final int TOKEN_STRING = TOKEN_FLOAT + 1;
41     public static final int TOKEN_SYMBOL = TOKEN_STRING + 1;
42     public static final int TOKEN_IDENTIFIER = TOKEN_SYMBOL + 1;
43     public static final int TOKEN_IDENTIFIER_NULL = TOKEN_IDENTIFIER + 1;
44     public static final int TOKEN_LAST = TOKEN_IDENTIFIER_NULL + 1;
45
46     public static final int ERR_UNKNOWN = 0;
47     public static final int ERR_UNEXP_EOF = ERR_UNKNOWN + 1;
48     public static final int ERR_UNEXP_EOF_IN_STRING = ERR_UNEXP_EOF + 1;
49     public static final int ERR_UNEXP_EOF_IN_COMMENT = ERR_UNEXP_EOF_IN_STRING + 1;
50     public static final int ERR_NON_DIGIT_IN_CONST = ERR_UNEXP_EOF_IN_COMMENT + 1;
51     public static final int ERR_DIGIT_RADIX = ERR_NON_DIGIT_IN_CONST + 1;
52     public static final int ERR_FLOAT_RADIX = ERR_DIGIT_RADIX + 1;
53     public static final int ERR_FLOAT_MALFORMED = ERR_FLOAT_RADIX + 1;
54
55     String JavaDoc whiteSpaceChars = " \t\r\n";
56     String JavaDoc identifierFirst = CHARS_a_2_z + CHARS_A_2_Z + "_";
57     String JavaDoc identifierNth = CHARS_a_2_z + CHARS_A_2_Z + "_-" + CHARS_DIGITS;
58     String JavaDoc commentSingle = "#\n";
59     boolean caseSensitive = false;
60     boolean scanCommentMulti = true;
61     boolean scanIdentifier = true;
62     boolean scanIdentifier1Char = false;
63     boolean scanIdentifierNULL = false;
64     boolean scanSymbols = true;
65     boolean scanBinary = false;
66     boolean scanOctal = true;
67     boolean scanFloat = true;
68     boolean scanHex = true;
69     boolean scanHexDollar = false;
70     boolean scanStringSq = true;
71     boolean scanStringDq = true;
72     boolean numbers2Int = true;
73     boolean int2Float = false;
74     boolean identifier2String = false;
75     boolean char2Token = true;
76     boolean symbol2Token = false;
77
78     private static class ScannerKey {
79
80         private int scope;
81         private String JavaDoc symbol;
82
83         public int value = -1;
84
85         ScannerKey(int scope, String JavaDoc symbol) {
86             this.scope = scope;
87             this.symbol = symbol;
88         }
89
90         public boolean equals(Object JavaDoc o) {
91             if (o instanceof ScannerKey) {
92                 ScannerKey comp = (ScannerKey)o;
93                 return scope == comp.scope && symbol.equals(comp.symbol);
94             }
95
96             return false;
97         }
98
99         public int hashCode() {
100             int result = 17;
101             result = 37 * result + scope;
102             result = 37 * result + symbol.hashCode();
103             return result;
104         }
105
106     }
107
108     static class TokenValue {
109         long longVal;
110         double doubleVal;
111         char charVal;
112         String JavaDoc stringVal;
113
114         TokenValue() {
115             clear();
116         }
117
118         void copyFrom(TokenValue other) {
119             longVal = other.longVal;
120             doubleVal = other.doubleVal;
121             charVal = other.charVal;
122             stringVal = other.stringVal;
123         }
124
125         void clear() {
126             longVal = 0L;
127             doubleVal = 0.0D;
128             charVal = (char)0;
129             stringVal = null;
130         }
131     }
132     
133     private String JavaDoc inputName;
134
135     private HashMap JavaDoc symbolTable = new HashMap JavaDoc();
136
137     private Reader reader;
138
139     int currToken;
140     TokenValue currValue = new TokenValue();
141     int currLine;
142     int currPosition;
143
144     int nextToken;
145     TokenValue nextValue = new TokenValue();
146     int nextLine;
147     int nextPosition;
148
149     int currScope = 0;
150     private static int nextUniqueScope = 1;
151
152     private static final int CHAR_EOF = -1;
153     private static final int CHAR_NONE = -2;
154
155     private int peekedChar = CHAR_NONE;
156
157     private ScannerKey lookupKey = new ScannerKey(0, null);
158
159     public GTKScanner() {
160         clearScanner();
161     }
162
163     public void clearScanner() {
164         if (reader != null) {
165             try {
166                 reader.close();
167             } catch (IOException ioe) {
168             }
169             
170             reader = null;
171         }
172
173         inputName = null;
174         
175         currToken = TOKEN_NONE;
176         currValue.clear();
177         currLine = 1;
178         currPosition = 0;
179
180         nextToken = TOKEN_NONE;
181         nextValue.clear();
182         nextLine = 1;
183         nextPosition = 0;
184
185         currScope = 0;
186
187         peekedChar = CHAR_NONE;
188     }
189
190     public void scanReader(Reader r, String JavaDoc inputName) {
191         if (r == null) {
192             return;
193         }
194
195         if (reader != null) {
196             clearScanner();
197         }
198
199         reader = r;
200         this.inputName = inputName;
201     }
202
203     public static int getUniqueScopeID() {
204         return nextUniqueScope++;
205     }
206
207     public int setScope(int scope) {
208         int oldScope = currScope;
209         currScope = scope;
210         return oldScope;
211     }
212
213     public void addSymbol(String JavaDoc symbol, int value) {
214         if (symbol == null) {
215             return;
216         }
217
218         ScannerKey key = lookupSymbol(symbol);
219
220         if (key == null) {
221             key = new ScannerKey(currScope, caseSensitive ? symbol : symbol.toLowerCase());
222             symbolTable.put(key, key);
223         }
224
225         key.value = value;
226     }
227
228     public boolean containsSymbol(String JavaDoc symbol) {
229         return lookupSymbol(symbol) != null;
230     }
231
232     private ScannerKey lookupSymbol(String JavaDoc symbol) {
233         lookupKey.scope = currScope;
234         lookupKey.symbol = (caseSensitive ? symbol : symbol.toLowerCase());
235         return (ScannerKey)symbolTable.get(lookupKey);
236     }
237
238     public void clearSymbolTable() {
239         symbolTable.clear();
240     }
241
242     public int peekNextToken() throws IOException {
243         if (nextToken == TOKEN_NONE) {
244             readAToken();
245
246             switch(nextToken) {
247                 case TOKEN_SYMBOL:
248                     if (symbol2Token) {
249                         nextToken = (int)nextValue.longVal;
250                     }
251                     break;
252                 case TOKEN_IDENTIFIER:
253                     if (identifier2String) {
254                         nextToken = TOKEN_STRING;
255                     }
256                     break;
257                 case TOKEN_HEX:
258                 case TOKEN_OCTAL:
259                 case TOKEN_BINARY:
260                     if (numbers2Int) {
261                         nextToken = TOKEN_INT;
262                     }
263                     break;
264             }
265
266             if (nextToken == TOKEN_INT && int2Float) {
267                 nextToken = TOKEN_FLOAT;
268                 nextValue.doubleVal = nextValue.longVal;
269             }
270         }
271
272         return nextToken;
273     }
274
275     public int getToken() throws IOException {
276         currToken = peekNextToken();
277         currValue.copyFrom(nextValue);
278         currLine = nextLine;
279         currPosition = nextPosition;
280
281         if (currToken != TOKEN_EOF) {
282             nextToken = TOKEN_NONE;
283         }
284
285         return currToken;
286     }
287
288     private int peekNextChar() throws IOException {
289         if (peekedChar == CHAR_NONE) {
290             peekedChar = reader.read();
291         }
292
293         return peekedChar;
294     }
295
296     private int getChar() throws IOException {
297         int ch = peekNextChar();
298
299         if (ch != CHAR_EOF) {
300             peekedChar = CHAR_NONE;
301
302             if (ch == '\n') {
303                 nextPosition = 0;
304                 nextLine++;
305             } else {
306                 nextPosition++;
307             }
308         }
309
310         return ch;
311     }
312
313
314     // ----- scanning methods and variables ----- //
315

316     private StringBuffer JavaDoc sb;
317     private TokenValue value = new TokenValue();
318     private int token;
319     private int ch;
320
321     private boolean skipSpaceAndComments() throws IOException {
322         while(ch != CHAR_EOF) {
323             if (whiteSpaceChars.indexOf(ch) != -1) {
324                 // continue
325
} else if (scanCommentMulti && ch == '/' && peekNextChar() == '*') {
326                 getChar();
327                 
328                 while((ch = getChar()) != CHAR_EOF) {
329                     if (ch == '*' && peekNextChar() == '/') {
330                         getChar();
331                         break;
332                     }
333                 }
334
335                 if (ch == CHAR_EOF) {
336                     return false;
337                 }
338             } else if (commentSingle.length() == 2 && ch == commentSingle.charAt(0)) {
339                 while((ch = getChar()) != CHAR_EOF) {
340                     if (ch == commentSingle.charAt(1)) {
341                         break;
342                     }
343                 }
344                 
345                 if (ch == CHAR_EOF) {
346                     return false;
347                 }
348             } else {
349                 break;
350             }
351             
352             ch = getChar();
353         }
354         
355         return true;
356     }
357
358     private void readAToken() throws IOException {
359         boolean inString = false;
360
361         nextValue.clear();
362         sb = null;
363
364         do {
365             value.clear();
366             token = TOKEN_NONE;
367
368             ch = getChar();
369             
370             if (!skipSpaceAndComments()) {
371                 token = TOKEN_ERROR;
372                 value.longVal = ERR_UNEXP_EOF_IN_COMMENT;
373             } else if (scanIdentifier && ch != CHAR_EOF && identifierFirst.indexOf(ch) != -1) {
374                 checkForIdentifier();
375                 handleOrdinaryChar();
376             } else {
377                 switch(ch) {
378                     case CHAR_EOF:
379                         token = TOKEN_EOF;
380                         break;
381                     case '"':
382                         if (!scanStringDq) {
383                             handleOrdinaryChar();
384                         } else {
385                             token = TOKEN_STRING;
386                             inString = true;
387                             
388                             sb = new StringBuffer JavaDoc();
389
390                             while ((ch = getChar()) != CHAR_EOF) {
391                                 if (ch == '"') {
392                                     inString = false;
393                                     break;
394                                 } else {
395                                     if (ch == '\\') {
396                                         ch = getChar();
397                                         switch(ch) {
398                                             case CHAR_EOF:
399                                                 break;
400                                             case '\\':
401                                                 sb.append('\\');
402                                                 break;
403                                             case 'n':
404                                                 sb.append('\n');
405                                                 break;
406                                             case 'r':
407                                                 sb.append('\r');
408                                                 break;
409                                             case 't':
410                                                 sb.append('\t');
411                                                 break;
412                                             case 'f':
413                                                 sb.append('\f');
414                                                 break;
415                                             case 'b':
416                                                 sb.append('\b');
417                                                 break;
418                                             case '0':
419                                             case '1':
420                                             case '2':
421                                             case '3':
422                                             case '4':
423                                             case '5':
424                                             case '6':
425                                             case '7':
426                                                 int i = ch - '0';
427                                                 int nextCh = peekNextChar();
428
429                                                 if (nextCh >= '0' && nextCh <= '7') {
430                                                     ch = getChar();
431                                                     i = i * 8 + ch - '0';
432                                                     nextCh = peekNextChar();
433                                                     if (nextCh >= '0' && nextCh <= '7') {
434                                                         ch = getChar();
435                                                         i = i * 8 + ch - '0';
436                                                     }
437                                                 }
438
439                                                 sb.append((char)i);
440                                                 break;
441                                             default:
442                                                 sb.append((char)ch);
443                                                 break;
444                                         }
445                                     } else {
446                                         sb.append((char)ch);
447                                     }
448                                 }
449                             }
450
451                             ch = CHAR_EOF;
452                         }
453
454                         break;
455                     case '\'':
456                         if (!scanStringSq) {
457                             handleOrdinaryChar();
458                         } else {
459                             token = TOKEN_STRING;
460                             inString = true;
461                             
462                             sb = new StringBuffer JavaDoc();
463
464                             while ((ch = getChar()) != CHAR_EOF) {
465                                 if (ch == '\'') {
466                                     inString = false;
467                                     break;
468                                 } else {
469                                     sb.append((char)ch);
470                                 }
471                             }
472
473                             ch = CHAR_EOF;
474                         }
475
476                         break;
477                     case '$':
478                         if (!scanHexDollar) {
479                             handleOrdinaryChar();
480                         } else {
481                             token = TOKEN_HEX;
482                             ch = getChar();
483                             scanNumber(false);
484                         }
485
486                         break;
487                     case '.':
488                         if (!scanFloat) {
489                             handleOrdinaryChar();
490                         } else {
491                             token = TOKEN_FLOAT;
492                             ch = getChar();
493                             scanNumber(true);
494                         }
495
496                         break;
497                     case '0':
498                         if (scanOctal) {
499                             token = TOKEN_OCTAL;
500                         } else {
501                             token = TOKEN_INT;
502                         }
503
504                         ch = peekNextChar();
505
506                         if (scanHex && (ch == 'x' || ch == 'X')) {
507                             token = TOKEN_HEX;
508                             getChar();
509                             ch = getChar();
510                             if (ch == CHAR_EOF) {
511                                 token = TOKEN_ERROR;
512                                 value.longVal = ERR_UNEXP_EOF;
513                                 break;
514                             }
515
516                             if (char2int(ch, 16) < 0) {
517                                 token = TOKEN_ERROR;
518                                 value.longVal = ERR_DIGIT_RADIX;
519                                 ch = CHAR_EOF;
520                                 break;
521                             }
522                         } else if (scanBinary && (ch == 'b' || ch == 'B')) {
523                             token = TOKEN_BINARY;
524                             getChar();
525                             ch = getChar();
526                             if (ch == CHAR_EOF) {
527                                 token = TOKEN_ERROR;
528                                 value.longVal = ERR_UNEXP_EOF;
529                                 break;
530                             }
531
532                             if (char2int(ch, 2) < 0) {
533                                 token = TOKEN_ERROR;
534                                 value.longVal = ERR_NON_DIGIT_IN_CONST;
535                                 ch = CHAR_EOF;
536                                 break;
537                             }
538                         } else {
539                             ch = '0';
540                         }
541
542                         // purposely fall through
543
case '1':
544                     case '2':
545                     case '3':
546                     case '4':
547                     case '5':
548                     case '6':
549                     case '7':
550                     case '8':
551                     case '9':
552                         scanNumber(false);
553                         break;
554                     default:
555                         handleOrdinaryChar();
556                         break;
557                 }
558             }
559         } while (ch != CHAR_EOF);
560
561         if (inString) {
562             token = TOKEN_ERROR;
563             value.longVal = ERR_UNEXP_EOF_IN_STRING;
564             sb = null;
565         }
566
567         if (sb != null) {
568             value.stringVal = sb.toString();
569             sb = null;
570         }
571
572         if (token == TOKEN_IDENTIFIER) {
573             if (scanSymbols) {
574                 int scope = currScope;
575                 ScannerKey key = lookupSymbol(value.stringVal);
576
577                 if (key != null) {
578                     value.stringVal = null;
579                     token = TOKEN_SYMBOL;
580                     value.longVal = key.value;
581                 }
582             }
583
584             if (token == TOKEN_IDENTIFIER && scanIdentifierNULL & value.stringVal.length() == 4) {
585                 if ("NULL".equals(caseSensitive ? value.stringVal : value.stringVal.toUpperCase())) {
586                     token = TOKEN_IDENTIFIER_NULL;
587                 }
588             }
589         }
590
591         nextToken = token;
592         nextValue.copyFrom(value);
593     }
594
595     private void handleOrdinaryChar() throws IOException {
596         if (ch != CHAR_EOF) {
597             if (char2Token) {
598                 token = ch;
599             } else {
600                 token = TOKEN_CHAR;
601                 value.charVal = (char)ch;
602             }
603
604             ch = CHAR_EOF;
605         }
606     }
607
608     private void checkForIdentifier() throws IOException {
609         if (ch != CHAR_EOF && identifierNth.indexOf(peekNextChar()) != -1) {
610             token = TOKEN_IDENTIFIER;
611
612             sb = new StringBuffer JavaDoc();
613             sb.append((char)ch);
614
615             do {
616                 ch = getChar();
617                 sb.append((char)ch);
618                 ch = peekNextChar();
619             } while (ch != CHAR_EOF && identifierNth.indexOf(ch) != -1);
620
621             ch = CHAR_EOF;
622         } else if (scanIdentifier1Char) {
623             token = TOKEN_IDENTIFIER;
624             value.stringVal = String.valueOf((char)ch);
625
626             ch = CHAR_EOF;
627         }
628     }
629
630     private static int char2int(int c, int base) {
631         if (c >= '0' && c <= '9') {
632             c -= '0';
633         } else if (c >= 'A' && c <= 'Z') {
634             c -= 'A' - 10;
635         } else if (c >= 'a' && c <= 'z') {
636             c -= 'a' - 10;
637         } else {
638             return -1;
639         }
640
641         return c < base ? c : -1;
642     }
643
644     private void scanNumber(boolean seenDot) throws IOException {
645         boolean inNumber = true;
646
647         if (token == TOKEN_NONE) {
648             token = TOKEN_INT;
649         }
650         
651         sb = new StringBuffer JavaDoc(seenDot ? "0." : "");
652         sb.append((char)ch);
653
654         do {
655             boolean isExponent = (token == TOKEN_FLOAT && (ch == 'e' || ch == 'E'));
656
657             ch = peekNextChar();
658
659             if (char2int(ch, 36) >= 0
660                     || (scanFloat && ch == '.')
661                     || (isExponent && (ch == '+' || ch == '-'))) {
662                 ch = getChar();
663
664                 switch(ch) {
665                     case '0':
666                     case '1':
667                     case '2':
668                     case '3':
669                     case '4':
670                     case '5':
671                     case '6':
672                     case '7':
673                     case '8':
674                     case '9':
675                         sb.append((char)ch);
676                         break;
677                     case '.':
678                         if (token != TOKEN_INT && token != TOKEN_OCTAL) {
679                             value.longVal = (token == TOKEN_FLOAT ? ERR_FLOAT_MALFORMED : ERR_FLOAT_RADIX);
680                             token = TOKEN_ERROR;
681                             inNumber = false;
682                         } else {
683                             token = TOKEN_FLOAT;
684                             sb.append((char)ch);
685                         }
686                         break;
687                     case '+':
688                     case '-':
689                         if (token != TOKEN_FLOAT) {
690                             token = TOKEN_ERROR;
691                             value.longVal = ERR_NON_DIGIT_IN_CONST;
692                             inNumber = false;
693                         } else {
694                             sb.append((char)ch);
695                         }
696                         break;
697                     case 'E':
698                     case 'e':
699                         if ((token != TOKEN_HEX && !scanFloat)
700                                 || (token != TOKEN_HEX
701                                     && token != TOKEN_OCTAL
702                                     && token != TOKEN_FLOAT
703                                     && token != TOKEN_INT)) {
704                             token = TOKEN_ERROR;
705                             value.longVal = ERR_NON_DIGIT_IN_CONST;
706                             inNumber = false;
707                         } else {
708                             if (token != TOKEN_HEX) {
709                                 token = TOKEN_FLOAT;
710                             }
711                             sb.append((char)ch);
712                         }
713                         break;
714                     default:
715                         if (token != TOKEN_HEX) {
716                             token = TOKEN_ERROR;
717                             value.longVal = ERR_NON_DIGIT_IN_CONST;
718                         } else {
719                             sb.append((char)ch);
720                         }
721                         break;
722                 }
723             } else {
724                 inNumber = false;
725             }
726         } while (inNumber);
727
728         try {
729             switch(token) {
730                 case TOKEN_INT:
731                     value.longVal = Long.parseLong(sb.toString(), 10);
732                     break;
733                 case TOKEN_FLOAT:
734                     value.doubleVal = Double.parseDouble(sb.toString());
735                     break;
736                 case TOKEN_HEX:
737                     value.longVal = Long.parseLong(sb.toString(), 16);
738                     break;
739                 case TOKEN_OCTAL:
740                     value.longVal = Long.parseLong(sb.toString(), 8);
741                     break;
742                 case TOKEN_BINARY:
743                     value.longVal = Long.parseLong(sb.toString(), 2);
744                     break;
745             }
746         } catch (NumberFormatException JavaDoc nfe) {
747             // PENDING(shannonh) - in some cases this could actually be ERR_DIGIT_RADIX
748
token = TOKEN_ERROR;
749             value.longVal = ERR_NON_DIGIT_IN_CONST;
750         }
751
752         sb = null;
753         ch = CHAR_EOF;
754     }
755
756     public void printMessage(String JavaDoc message, boolean isError) {
757         System.err.print(inputName + ":" + currLine + ": ");
758
759         if (isError) {
760             System.err.print("error: ");
761         }
762
763         System.err.println(message);
764     }
765
766     // PENDING(shannonh) - a good implementation of this method is needed
767
public void unexpectedToken(int expected, String JavaDoc symbolName, String JavaDoc message, boolean isError) {
768         String JavaDoc prefix = "lexical error or unexpected token, expected valid token";
769
770         if (message != null) {
771             prefix += " - " + message;
772         }
773
774         printMessage(prefix, isError);
775     }
776
777 }
778
Popular Tags