001: package org.apache.torque.engine.sql;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.io.IOException;
023: import java.io.Reader;
024: import java.util.List;
025: import java.util.ArrayList;
026:
027: /**
028: * A simple Scanner implementation that scans an
029: * sql file into usable tokens. Used by SQLToAppData.
030: *
031: * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
032: * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
033: * @author <a href="mailto:andyhot@di.uoa.gr">Andreas Andreou</a>
034: * @version $Id: SQLScanner.java 473814 2006-11-11 22:30:30Z tv $
035: */
036: public class SQLScanner {
037: /** white spaces */
038: private static final String WHITE = "\f\r\t\n ";
039: /** alphabetic characters */
040: private static final String ALFA = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
041: /** numbers */
042: private static final String NUMER = "0123456789";
043: /** alphanumeric */
044: private static final String ALFANUM = ALFA + NUMER;
045: /** special characters */
046: private static final String SPECIAL = ";(),'";
047: /** comment */
048: private static final char COMMENT_POUND = '#';
049: /** comment */
050: private static final char COMMENT_SLASH = '/';
051: /** comment */
052: private static final char COMMENT_STAR = '*';
053: /** comment */
054: private static final char COMMENT_DASH = '-';
055:
056: /** the input reader */
057: private Reader in;
058: /** character */
059: private int chr;
060: /** token */
061: private String token;
062: /** list of tokens */
063: private List tokens;
064: /** line */
065: private int line;
066: /** column */
067: private int col;
068:
069: /**
070: * Creates a new scanner with no Reader
071: */
072: public SQLScanner() {
073: this (null);
074: }
075:
076: /**
077: * Creates a new scanner with an Input Reader
078: *
079: * @param input the input reader
080: */
081: public SQLScanner(Reader input) {
082: setInput(input);
083: }
084:
085: /**
086: * Set the Input
087: *
088: * @param input the input reader
089: */
090: public void setInput(Reader input) {
091: in = input;
092: }
093:
094: /**
095: * Reads the next character and increments the line and column counters.
096: *
097: * @throws IOException If an I/O error occurs
098: */
099: private void readChar() throws IOException {
100: boolean wasLine = (char) chr == '\r';
101: chr = in.read();
102: if ((char) chr == '\n' || (char) chr == '\r'
103: || (char) chr == '\f') {
104: col = 0;
105: if (!wasLine || (char) chr != '\n') {
106: line++;
107: }
108: } else {
109: col++;
110: }
111: }
112:
113: /**
114: * Scans an identifier.
115: *
116: * @throws IOException If an I/O error occurs
117: */
118: private void scanIdentifier() throws IOException {
119: token = "";
120: char c = (char) chr;
121: while (chr != -1 && WHITE.indexOf(c) == -1
122: && SPECIAL.indexOf(c) == -1) {
123: token = token + (char) chr;
124: readChar();
125: c = (char) chr;
126: }
127: int start = col - token.length();
128: tokens.add(new Token(token, line, start));
129: }
130:
131: /**
132: * Scans an identifier which had started with the negative sign.
133: *
134: * @throws IOException If an I/O error occurs
135: */
136: private void scanNegativeIdentifier() throws IOException {
137: token = "-";
138: char c = (char) chr;
139: while (chr != -1 && WHITE.indexOf(c) == -1
140: && SPECIAL.indexOf(c) == -1) {
141: token = token + (char) chr;
142: readChar();
143: c = (char) chr;
144: }
145: int start = col - token.length();
146: tokens.add(new Token(token, line, start));
147: }
148:
149: /**
150: * Scan the input Reader and returns a list of tokens.
151: *
152: * @return a list of tokens
153: * @throws IOException If an I/O error occurs
154: */
155: public List scan() throws IOException {
156: line = 1;
157: col = 0;
158: boolean inComment = false;
159: boolean inCommentSlashStar = false;
160: boolean inCommentDash = false;
161:
162: boolean inNegative;
163:
164: tokens = new ArrayList();
165: readChar();
166: while (chr != -1) {
167: char c = (char) chr;
168: inNegative = false;
169:
170: if (c == COMMENT_DASH) {
171: readChar();
172: if ((char) chr == COMMENT_DASH) {
173: inCommentDash = true;
174: } else {
175: inNegative = true;
176: c = (char) chr;
177: }
178: }
179:
180: if (inCommentDash) {
181: if (c == '\n' || c == '\r') {
182: inCommentDash = false;
183: }
184: readChar();
185: } else if (c == COMMENT_POUND) {
186: inComment = true;
187: readChar();
188: } else if (c == COMMENT_SLASH) {
189: readChar();
190: if ((char) chr == COMMENT_STAR) {
191: inCommentSlashStar = true;
192: }
193: } else if (inComment || inCommentSlashStar) {
194: if (c == '*') {
195: readChar();
196: if ((char) chr == COMMENT_SLASH) {
197: inCommentSlashStar = false;
198: }
199: } else if (c == '\n' || c == '\r') {
200: inComment = false;
201: }
202: readChar();
203: } else if (ALFANUM.indexOf(c) >= 0) {
204: if (inNegative) {
205: scanNegativeIdentifier();
206: } else {
207: scanIdentifier();
208: }
209: } else if (SPECIAL.indexOf(c) >= 0) {
210: tokens.add(new Token("" + c, line, col));
211: readChar();
212: } else {
213: readChar();
214: }
215: }
216: return tokens;
217: }
218: }
|