- /*
- * @(#)GTKScanner.java 1.39 03/01/23
- *
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package com.sun.java.swing.plaf.gtk;
-
- import java.io.*;
- import java.util.HashMap;
-
- /**
- * @author Shannon Hickey
- * @version 1.39 01/23/03
- */
- class GTKScanner {
-
- public static final String CHARS_a_2_z = "abcdefghijklmnopqrstuvwxyz";
- public static final String CHARS_A_2_Z = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- public static final String CHARS_DIGITS = "0123456789";
-
- public static final int TOKEN_EOF = -1;
- public static final int TOKEN_LEFT_PAREN = '(';
- public static final int TOKEN_RIGHT_PAREN = ')';
- public static final int TOKEN_LEFT_CURLY = '{';
- public static final int TOKEN_RIGHT_CURLY = '}';
- public static final int TOKEN_LEFT_BRACE = '[';
- public static final int TOKEN_RIGHT_BRACE = ']';
- public static final int TOKEN_EQUAL_SIGN = '=';
- public static final int TOKEN_COMMA = ',';
- public static final int TOKEN_NONE = 256;
- public static final int TOKEN_ERROR = TOKEN_NONE + 1;
- public static final int TOKEN_CHAR = TOKEN_ERROR + 1;
- public static final int TOKEN_BINARY = TOKEN_CHAR + 1;
- public static final int TOKEN_OCTAL = TOKEN_BINARY + 1;
- public static final int TOKEN_INT = TOKEN_OCTAL + 1;
- public static final int TOKEN_HEX = TOKEN_INT + 1;
- public static final int TOKEN_FLOAT = TOKEN_HEX + 1;
- public static final int TOKEN_STRING = TOKEN_FLOAT + 1;
- public static final int TOKEN_SYMBOL = TOKEN_STRING + 1;
- public static final int TOKEN_IDENTIFIER = TOKEN_SYMBOL + 1;
- public static final int TOKEN_IDENTIFIER_NULL = TOKEN_IDENTIFIER + 1;
- public static final int TOKEN_LAST = TOKEN_IDENTIFIER_NULL + 1;
-
- public static final int ERR_UNKNOWN = 0;
- public static final int ERR_UNEXP_EOF = ERR_UNKNOWN + 1;
- public static final int ERR_UNEXP_EOF_IN_STRING = ERR_UNEXP_EOF + 1;
- public static final int ERR_UNEXP_EOF_IN_COMMENT = ERR_UNEXP_EOF_IN_STRING + 1;
- public static final int ERR_NON_DIGIT_IN_CONST = ERR_UNEXP_EOF_IN_COMMENT + 1;
- public static final int ERR_DIGIT_RADIX = ERR_NON_DIGIT_IN_CONST + 1;
- public static final int ERR_FLOAT_RADIX = ERR_DIGIT_RADIX + 1;
- public static final int ERR_FLOAT_MALFORMED = ERR_FLOAT_RADIX + 1;
-
- String whiteSpaceChars = " \t\r\n";
- String identifierFirst = CHARS_a_2_z + CHARS_A_2_Z + "_";
- String identifierNth = CHARS_a_2_z + CHARS_A_2_Z + "_-" + CHARS_DIGITS;
- String commentSingle = "#\n";
- boolean caseSensitive = false;
- boolean scanCommentMulti = true;
- boolean scanIdentifier = true;
- boolean scanIdentifier1Char = false;
- boolean scanIdentifierNULL = false;
- boolean scanSymbols = true;
- boolean scanBinary = false;
- boolean scanOctal = true;
- boolean scanFloat = true;
- boolean scanHex = true;
- boolean scanHexDollar = false;
- boolean scanStringSq = true;
- boolean scanStringDq = true;
- boolean numbers2Int = true;
- boolean int2Float = false;
- boolean identifier2String = false;
- boolean char2Token = true;
- boolean symbol2Token = false;
-
- private static class ScannerKey {
-
- private int scope;
- private String symbol;
-
- public int value = -1;
-
- ScannerKey(int scope, String symbol) {
- this.scope = scope;
- this.symbol = symbol;
- }
-
- public boolean equals(Object o) {
- if (o instanceof ScannerKey) {
- ScannerKey comp = (ScannerKey)o;
- return scope == comp.scope && symbol.equals(comp.symbol);
- }
-
- return false;
- }
-
- public int hashCode() {
- int result = 17;
- result = 37 * result + scope;
- result = 37 * result + symbol.hashCode();
- return result;
- }
-
- }
-
- static class TokenValue {
- long longVal;
- double doubleVal;
- char charVal;
- String stringVal;
-
- TokenValue() {
- clear();
- }
-
- void copyFrom(TokenValue other) {
- longVal = other.longVal;
- doubleVal = other.doubleVal;
- charVal = other.charVal;
- stringVal = other.stringVal;
- }
-
- void clear() {
- longVal = 0L;
- doubleVal = 0.0D;
- charVal = (char)0;
- stringVal = null;
- }
- }
-
- private String inputName;
-
- private HashMap symbolTable = new HashMap();
-
- private Reader reader;
-
- int currToken;
- TokenValue currValue = new TokenValue();
- int currLine;
- int currPosition;
-
- int nextToken;
- TokenValue nextValue = new TokenValue();
- int nextLine;
- int nextPosition;
-
- int currScope = 0;
- private static int nextUniqueScope = 1;
-
- private static final int CHAR_EOF = -1;
- private static final int CHAR_NONE = -2;
-
- private int peekedChar = CHAR_NONE;
-
- private ScannerKey lookupKey = new ScannerKey(0, null);
-
- public GTKScanner() {
- clearScanner();
- }
-
- public void clearScanner() {
- if (reader != null) {
- try {
- reader.close();
- } catch (IOException ioe) {
- }
-
- reader = null;
- }
-
- inputName = null;
-
- currToken = TOKEN_NONE;
- currValue.clear();
- currLine = 1;
- currPosition = 0;
-
- nextToken = TOKEN_NONE;
- nextValue.clear();
- nextLine = 1;
- nextPosition = 0;
-
- currScope = 0;
-
- peekedChar = CHAR_NONE;
- }
-
- public void scanReader(Reader r, String inputName) {
- if (r == null) {
- return;
- }
-
- if (reader != null) {
- clearScanner();
- }
-
- reader = r;
- this.inputName = inputName;
- }
-
- public static int getUniqueScopeID() {
- return nextUniqueScope++;
- }
-
- public int setScope(int scope) {
- int oldScope = currScope;
- currScope = scope;
- return oldScope;
- }
-
- public void addSymbol(String symbol, int value) {
- if (symbol == null) {
- return;
- }
-
- ScannerKey key = lookupSymbol(symbol);
-
- if (key == null) {
- key = new ScannerKey(currScope, caseSensitive ? symbol : symbol.toLowerCase());
- symbolTable.put(key, key);
- }
-
- key.value = value;
- }
-
- public boolean containsSymbol(String symbol) {
- return lookupSymbol(symbol) != null;
- }
-
- private ScannerKey lookupSymbol(String symbol) {
- lookupKey.scope = currScope;
- lookupKey.symbol = (caseSensitive ? symbol : symbol.toLowerCase());
- return (ScannerKey)symbolTable.get(lookupKey);
- }
-
- public void clearSymbolTable() {
- symbolTable.clear();
- }
-
- public int peekNextToken() throws IOException {
- if (nextToken == TOKEN_NONE) {
- readAToken();
-
- switch(nextToken) {
- case TOKEN_SYMBOL:
- if (symbol2Token) {
- nextToken = (int)nextValue.longVal;
- }
- break;
- case TOKEN_IDENTIFIER:
- if (identifier2String) {
- nextToken = TOKEN_STRING;
- }
- break;
- case TOKEN_HEX:
- case TOKEN_OCTAL:
- case TOKEN_BINARY:
- if (numbers2Int) {
- nextToken = TOKEN_INT;
- }
- break;
- }
-
- if (nextToken == TOKEN_INT && int2Float) {
- nextToken = TOKEN_FLOAT;
- nextValue.doubleVal = nextValue.longVal;
- }
- }
-
- return nextToken;
- }
-
- public int getToken() throws IOException {
- currToken = peekNextToken();
- currValue.copyFrom(nextValue);
- currLine = nextLine;
- currPosition = nextPosition;
-
- if (currToken != TOKEN_EOF) {
- nextToken = TOKEN_NONE;
- }
-
- return currToken;
- }
-
- private int peekNextChar() throws IOException {
- if (peekedChar == CHAR_NONE) {
- peekedChar = reader.read();
- }
-
- return peekedChar;
- }
-
- private int getChar() throws IOException {
- int ch = peekNextChar();
-
- if (ch != CHAR_EOF) {
- peekedChar = CHAR_NONE;
-
- if (ch == '\n') {
- nextPosition = 0;
- nextLine++;
- } else {
- nextPosition++;
- }
- }
-
- return ch;
- }
-
-
- // ----- scanning methods and variables ----- //
-
- private StringBuffer sb;
- private TokenValue value = new TokenValue();
- private int token;
- private int ch;
-
- private boolean skipSpaceAndComments() throws IOException {
- while(ch != CHAR_EOF) {
- if (whiteSpaceChars.indexOf(ch) != -1) {
- // continue
- } else if (scanCommentMulti && ch == '/' && peekNextChar() == '*') {
- getChar();
-
- while((ch = getChar()) != CHAR_EOF) {
- if (ch == '*' && peekNextChar() == '/') {
- getChar();
- break;
- }
- }
-
- if (ch == CHAR_EOF) {
- return false;
- }
- } else if (commentSingle.length() == 2 && ch == commentSingle.charAt(0)) {
- while((ch = getChar()) != CHAR_EOF) {
- if (ch == commentSingle.charAt(1)) {
- break;
- }
- }
-
- if (ch == CHAR_EOF) {
- return false;
- }
- } else {
- break;
- }
-
- ch = getChar();
- }
-
- return true;
- }
-
- private void readAToken() throws IOException {
- boolean inString = false;
-
- nextValue.clear();
- sb = null;
-
- do {
- value.clear();
- token = TOKEN_NONE;
-
- ch = getChar();
-
- if (!skipSpaceAndComments()) {
- token = TOKEN_ERROR;
- value.longVal = ERR_UNEXP_EOF_IN_COMMENT;
- } else if (scanIdentifier && ch != CHAR_EOF && identifierFirst.indexOf(ch) != -1) {
- checkForIdentifier();
- handleOrdinaryChar();
- } else {
- switch(ch) {
- case CHAR_EOF:
- token = TOKEN_EOF;
- break;
- case '"':
- if (!scanStringDq) {
- handleOrdinaryChar();
- } else {
- token = TOKEN_STRING;
- inString = true;
-
- sb = new StringBuffer();
-
- while ((ch = getChar()) != CHAR_EOF) {
- if (ch == '"') {
- inString = false;
- break;
- } else {
- if (ch == '\\') {
- ch = getChar();
- switch(ch) {
- case CHAR_EOF:
- break;
- case '\\':
- sb.append('\\');
- break;
- case 'n':
- sb.append('\n');
- break;
- case 'r':
- sb.append('\r');
- break;
- case 't':
- sb.append('\t');
- break;
- case 'f':
- sb.append('\f');
- break;
- case 'b':
- sb.append('\b');
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- int i = ch - '0';
- int nextCh = peekNextChar();
-
- if (nextCh >= '0' && nextCh <= '7') {
- ch = getChar();
- i = i * 8 + ch - '0';
- nextCh = peekNextChar();
- if (nextCh >= '0' && nextCh <= '7') {
- ch = getChar();
- i = i * 8 + ch - '0';
- }
- }
-
- sb.append((char)i);
- break;
- default:
- sb.append((char)ch);
- break;
- }
- } else {
- sb.append((char)ch);
- }
- }
- }
-
- ch = CHAR_EOF;
- }
-
- break;
- case '\'':
- if (!scanStringSq) {
- handleOrdinaryChar();
- } else {
- token = TOKEN_STRING;
- inString = true;
-
- sb = new StringBuffer();
-
- while ((ch = getChar()) != CHAR_EOF) {
- if (ch == '\'') {
- inString = false;
- break;
- } else {
- sb.append((char)ch);
- }
- }
-
- ch = CHAR_EOF;
- }
-
- break;
- case '$':
- if (!scanHexDollar) {
- handleOrdinaryChar();
- } else {
- token = TOKEN_HEX;
- ch = getChar();
- scanNumber(false);
- }
-
- break;
- case '.':
- if (!scanFloat) {
- handleOrdinaryChar();
- } else {
- token = TOKEN_FLOAT;
- ch = getChar();
- scanNumber(true);
- }
-
- break;
- case '0':
- if (scanOctal) {
- token = TOKEN_OCTAL;
- } else {
- token = TOKEN_INT;
- }
-
- ch = peekNextChar();
-
- if (scanHex && (ch == 'x' || ch == 'X')) {
- token = TOKEN_HEX;
- getChar();
- ch = getChar();
- if (ch == CHAR_EOF) {
- token = TOKEN_ERROR;
- value.longVal = ERR_UNEXP_EOF;
- break;
- }
-
- if (char2int(ch, 16) < 0) {
- token = TOKEN_ERROR;
- value.longVal = ERR_DIGIT_RADIX;
- ch = CHAR_EOF;
- break;
- }
- } else if (scanBinary && (ch == 'b' || ch == 'B')) {
- token = TOKEN_BINARY;
- getChar();
- ch = getChar();
- if (ch == CHAR_EOF) {
- token = TOKEN_ERROR;
- value.longVal = ERR_UNEXP_EOF;
- break;
- }
-
- if (char2int(ch, 2) < 0) {
- token = TOKEN_ERROR;
- value.longVal = ERR_NON_DIGIT_IN_CONST;
- ch = CHAR_EOF;
- break;
- }
- } else {
- ch = '0';
- }
-
- // purposely fall through
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- scanNumber(false);
- break;
- default:
- handleOrdinaryChar();
- break;
- }
- }
- } while (ch != CHAR_EOF);
-
- if (inString) {
- token = TOKEN_ERROR;
- value.longVal = ERR_UNEXP_EOF_IN_STRING;
- sb = null;
- }
-
- if (sb != null) {
- value.stringVal = sb.toString();
- sb = null;
- }
-
- if (token == TOKEN_IDENTIFIER) {
- if (scanSymbols) {
- int scope = currScope;
- ScannerKey key = lookupSymbol(value.stringVal);
-
- if (key != null) {
- value.stringVal = null;
- token = TOKEN_SYMBOL;
- value.longVal = key.value;
- }
- }
-
- if (token == TOKEN_IDENTIFIER && scanIdentifierNULL & value.stringVal.length() == 4) {
- if ("NULL".equals(caseSensitive ? value.stringVal : value.stringVal.toUpperCase())) {
- token = TOKEN_IDENTIFIER_NULL;
- }
- }
- }
-
- nextToken = token;
- nextValue.copyFrom(value);
- }
-
- private void handleOrdinaryChar() throws IOException {
- if (ch != CHAR_EOF) {
- if (char2Token) {
- token = ch;
- } else {
- token = TOKEN_CHAR;
- value.charVal = (char)ch;
- }
-
- ch = CHAR_EOF;
- }
- }
-
- private void checkForIdentifier() throws IOException {
- if (ch != CHAR_EOF && identifierNth.indexOf(peekNextChar()) != -1) {
- token = TOKEN_IDENTIFIER;
-
- sb = new StringBuffer();
- sb.append((char)ch);
-
- do {
- ch = getChar();
- sb.append((char)ch);
- ch = peekNextChar();
- } while (ch != CHAR_EOF && identifierNth.indexOf(ch) != -1);
-
- ch = CHAR_EOF;
- } else if (scanIdentifier1Char) {
- token = TOKEN_IDENTIFIER;
- value.stringVal = String.valueOf((char)ch);
-
- ch = CHAR_EOF;
- }
- }
-
- private static int char2int(int c, int base) {
- if (c >= '0' && c <= '9') {
- c -= '0';
- } else if (c >= 'A' && c <= 'Z') {
- c -= 'A' - 10;
- } else if (c >= 'a' && c <= 'z') {
- c -= 'a' - 10;
- } else {
- return -1;
- }
-
- return c < base ? c : -1;
- }
-
- private void scanNumber(boolean seenDot) throws IOException {
- boolean inNumber = true;
-
- if (token == TOKEN_NONE) {
- token = TOKEN_INT;
- }
-
- sb = new StringBuffer(seenDot ? "0." : "");
- sb.append((char)ch);
-
- do {
- boolean isExponent = (token == TOKEN_FLOAT && (ch == 'e' || ch == 'E'));
-
- ch = peekNextChar();
-
- if (char2int(ch, 36) >= 0
- || (scanFloat && ch == '.')
- || (isExponent && (ch == '+' || ch == '-'))) {
- ch = getChar();
-
- switch(ch) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- sb.append((char)ch);
- break;
- case '.':
- if (token != TOKEN_INT && token != TOKEN_OCTAL) {
- value.longVal = (token == TOKEN_FLOAT ? ERR_FLOAT_MALFORMED : ERR_FLOAT_RADIX);
- token = TOKEN_ERROR;
- inNumber = false;
- } else {
- token = TOKEN_FLOAT;
- sb.append((char)ch);
- }
- break;
- case '+':
- case '-':
- if (token != TOKEN_FLOAT) {
- token = TOKEN_ERROR;
- value.longVal = ERR_NON_DIGIT_IN_CONST;
- inNumber = false;
- } else {
- sb.append((char)ch);
- }
- break;
- case 'E':
- case 'e':
- if ((token != TOKEN_HEX && !scanFloat)
- || (token != TOKEN_HEX
- && token != TOKEN_OCTAL
- && token != TOKEN_FLOAT
- && token != TOKEN_INT)) {
- token = TOKEN_ERROR;
- value.longVal = ERR_NON_DIGIT_IN_CONST;
- inNumber = false;
- } else {
- if (token != TOKEN_HEX) {
- token = TOKEN_FLOAT;
- }
- sb.append((char)ch);
- }
- break;
- default:
- if (token != TOKEN_HEX) {
- token = TOKEN_ERROR;
- value.longVal = ERR_NON_DIGIT_IN_CONST;
- } else {
- sb.append((char)ch);
- }
- break;
- }
- } else {
- inNumber = false;
- }
- } while (inNumber);
-
- try {
- switch(token) {
- case TOKEN_INT:
- value.longVal = Long.parseLong(sb.toString(), 10);
- break;
- case TOKEN_FLOAT:
- value.doubleVal = Double.parseDouble(sb.toString());
- break;
- case TOKEN_HEX:
- value.longVal = Long.parseLong(sb.toString(), 16);
- break;
- case TOKEN_OCTAL:
- value.longVal = Long.parseLong(sb.toString(), 8);
- break;
- case TOKEN_BINARY:
- value.longVal = Long.parseLong(sb.toString(), 2);
- break;
- }
- } catch (NumberFormatException nfe) {
- // PENDING(shannonh) - in some cases this could actually be ERR_DIGIT_RADIX
- token = TOKEN_ERROR;
- value.longVal = ERR_NON_DIGIT_IN_CONST;
- }
-
- sb = null;
- ch = CHAR_EOF;
- }
-
- public void printMessage(String message, boolean isError) {
- System.err.print(inputName + ":" + currLine + ": ");
-
- if (isError) {
- System.err.print("error: ");
- }
-
- System.err.println(message);
- }
-
- // PENDING(shannonh) - a good implementation of this method is needed
- public void unexpectedToken(int expected, String symbolName, String message, boolean isError) {
- String prefix = "lexical error or unexpected token, expected valid token";
-
- if (message != null) {
- prefix += " - " + message;
- }
-
- printMessage(prefix, isError);
- }
-
- }