/* * blanco Framework * Copyright (C) 2004-2006 WATANABE Yoshinori * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. */ package blanco.commons.sql.format; import java.util.ArrayList; import java.util.List; import blanco.commons.sql.format.valueobject.BlancoSqlToken; /** * http://homepage2.nifty.com/igat/igapyon/diary/2005/ig050613.html * * 2005.08.12 Tosiki Iga: * 2005.08.12 Tosiki Iga: * * @author WATANABE Yoshinori (a-san) : original version at 2005.07.04. * @author IGA Tosiki : marge into blanc Framework at 2005.07.04 */ public class BlancoSqlParser { private String fBefore; private char fChar; private int fPos; private static final String[] twoCharacterSymbol = { "<>", "<=", ">=", "||" }; public BlancoSqlParser() { } public static boolean isSpace(final char argChar) { // 2005.07.26 Tosiki Iga // 2005.08.12 Tosiki Iga return argChar == ' ' || argChar == '\t' || argChar == '\n' || argChar == '\r' || argChar == 65535; } public static boolean isLetter(final char argChar) { if (isSpace(argChar)) { return false; } if (isDigit(argChar)) { return false; } if (isSymbol(argChar)) { return false; } return true; } public static boolean isDigit(final char argChar) { return '0' <= argChar && argChar <= '9'; } public static boolean isSymbol(final char argChar) { switch (argChar) { case '"': // double quote case '?': // question mark case '%': // percent case '&': // ampersand case '\'': // quote case '(': // left paren case ')': // right paren case '|': // vertical bar case '*': // asterisk case '+': // plus sign case ',': // comma case '-': // minus sign case '.': // period case '/': // solidus case ':': // colon case ';': // semicolon case '<': // less than operator case '=': // equals operator case '>': // greater than operator // case '!': // case '$': // case '[': // case '\\': // case ']': // case '^': // case '{': // case '}': // case '~': return true; default: return false; } } BlancoSqlToken nextToken() { int start_pos = fPos; if (fPos >= fBefore.length()) { fPos++; return new BlancoSqlToken(BlancoSqlTokenConstants.END, "", start_pos); } fChar = fBefore.charAt(fPos); if (isSpace(fChar)) { String workString = ""; for (;;) { workString += fChar; fChar = fBefore.charAt(fPos); if (!isSpace(fChar)) { return new BlancoSqlToken(BlancoSqlTokenConstants.SPACE, workString, start_pos); } fPos++; if (fPos >= fBefore.length()) { return new BlancoSqlToken(BlancoSqlTokenConstants.SPACE, workString, start_pos); } } } else if (fChar == ';') { fPos++; return new BlancoSqlToken(BlancoSqlTokenConstants.SYMBOL, ";", start_pos); } else if (isDigit(fChar)) { String s = ""; while (isDigit(fChar) || fChar == '.') { // if (ch == '.') type = Token.REAL; s += fChar; fPos++; if (fPos >= fBefore.length()) { break; } fChar = fBefore.charAt(fPos); } return new BlancoSqlToken(BlancoSqlTokenConstants.VALUE, s, start_pos); } else if (isLetter(fChar)) { String s = ""; while (isLetter(fChar) || isDigit(fChar) || fChar == '.') { s += fChar; fPos++; if (fPos >= fBefore.length()) { break; } fChar = fBefore.charAt(fPos); } for (int i = 0; i < BlancoSqlConstants.SQL_RESERVED_WORDS.length; i++) { if (s .compareToIgnoreCase(BlancoSqlConstants.SQL_RESERVED_WORDS[i]) == 0) { return new BlancoSqlToken(BlancoSqlTokenConstants.KEYWORD, s, start_pos); } } return new BlancoSqlToken(BlancoSqlTokenConstants.NAME, s, start_pos); } // single line comment else if (fChar == '-') { fPos++; char ch2 = fBefore.charAt(fPos); if (ch2 != '-') { return new BlancoSqlToken(BlancoSqlTokenConstants.SYMBOL, "-", start_pos); } fPos++; String s = "--"; for (;;) { fChar = fBefore.charAt(fPos); s += fChar; fPos++; if (fChar == '\n' || fPos >= fBefore.length()) { return new BlancoSqlToken(BlancoSqlTokenConstants.COMMENT, s, start_pos); } } } else if (fChar == '/') { fPos++; char ch2 = fBefore.charAt(fPos); if (ch2 != '*') { return new BlancoSqlToken(BlancoSqlTokenConstants.SYMBOL, "/", start_pos); } String s = "/*"; fPos++; int ch0 = -1; for (;;) { ch0 = fChar; fChar = fBefore.charAt(fPos); s += fChar; fPos++; if (ch0 == '*' && fChar == '/') { return new BlancoSqlToken(BlancoSqlTokenConstants.COMMENT, s, start_pos); } } } else if (fChar == '\'') { fPos++; String s = "'"; for (;;) { fChar = fBefore.charAt(fPos); s += fChar; fPos++; if (fChar == '\'') { return new BlancoSqlToken(BlancoSqlTokenConstants.VALUE, s, start_pos); } } } else if (fChar == '\"') { fPos++; String s = "\""; for (;;) { fChar = fBefore.charAt(fPos); s += fChar; fPos++; if (fChar == '\"') { return new BlancoSqlToken(BlancoSqlTokenConstants.NAME, s, start_pos); } } } else if (isSymbol(fChar)) { String s = "" + fChar; fPos++; if (fPos >= fBefore.length()) { return new BlancoSqlToken(BlancoSqlTokenConstants.SYMBOL, s, start_pos); } char ch2 = fBefore.charAt(fPos); for (int i = 0; i < twoCharacterSymbol.length; i++) { if (twoCharacterSymbol[i].charAt(0) == fChar && twoCharacterSymbol[i].charAt(1) == ch2) { fPos++; s += ch2; break; } } return new BlancoSqlToken(BlancoSqlTokenConstants.SYMBOL, s, start_pos); } else { fPos++; return new BlancoSqlToken(BlancoSqlTokenConstants.UNKNOWN, "" + fChar, start_pos); } } public List<BlancoSqlToken> parse(final String argSql) { fPos = 0; fBefore = argSql; final List<BlancoSqlToken> list = new ArrayList<BlancoSqlToken>(); for (;;) { final BlancoSqlToken token = nextToken(); if (token.getType() == BlancoSqlTokenConstants.END) { break; } list.add(token); } return list; } }