1 7 8 package com.sun.java.swing.plaf.gtk; 9 10 import java.io.*; 11 import java.util.HashMap ; 12 13 17 class GTKScanner { 18 19 public static final String CHARS_a_2_z = "abcdefghijklmnopqrstuvwxyz"; 20 public static final String CHARS_A_2_Z = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 21 public static final String 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 whiteSpaceChars = " \t\r\n"; 56 String identifierFirst = CHARS_a_2_z + CHARS_A_2_Z + "_"; 57 String identifierNth = CHARS_a_2_z + CHARS_A_2_Z + "_-" + CHARS_DIGITS; 58 String 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 symbol; 82 83 public int value = -1; 84 85 ScannerKey(int scope, String symbol) { 86 this.scope = scope; 87 this.symbol = symbol; 88 } 89 90 public boolean equals(Object 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 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 inputName; 134 135 private HashMap symbolTable = new HashMap (); 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 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 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 symbol) { 229 return lookupSymbol(symbol) != null; 230 } 231 232 private ScannerKey lookupSymbol(String 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 316 private StringBuffer 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 } 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 (); 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 (); 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 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 (); 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 (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 nfe) { 747 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 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 public void unexpectedToken(int expected, String symbolName, String message, boolean isError) { 768 String 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 |