1 package org.apache.torque.engine.sql;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23 import java.io.Reader;
24 import java.util.List;
25 import java.util.ArrayList;
26
27 /***
28 * A simple Scanner implementation that scans an
29 * sql file into usable tokens. Used by SQLToAppData.
30 *
31 * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
32 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
33 * @author <a href="mailto:andyhot@di.uoa.gr">Andreas Andreou</a>
34 * @version $Id: SQLScanner.java 473814 2006-11-11 22:30:30Z tv $
35 */
36 public class SQLScanner
37 {
38 /*** white spaces */
39 private static final String WHITE = "\f\r\t\n ";
40 /*** alphabetic characters */
41 private static final String ALFA
42 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
43 /*** numbers */
44 private static final String NUMER = "0123456789";
45 /*** alphanumeric */
46 private static final String ALFANUM = ALFA + NUMER;
47 /*** special characters */
48 private static final String SPECIAL = ";(),'";
49 /*** comment */
50 private static final char COMMENT_POUND = '#';
51 /*** comment */
52 private static final char COMMENT_SLASH = '/';
53 /*** comment */
54 private static final char COMMENT_STAR = '*';
55 /*** comment */
56 private static final char COMMENT_DASH = '-';
57
58 /*** the input reader */
59 private Reader in;
60 /*** character */
61 private int chr;
62 /*** token */
63 private String token;
64 /*** list of tokens */
65 private List tokens;
66 /*** line */
67 private int line;
68 /*** column */
69 private int col;
70
71 /***
72 * Creates a new scanner with no Reader
73 */
74 public SQLScanner()
75 {
76 this(null);
77 }
78
79 /***
80 * Creates a new scanner with an Input Reader
81 *
82 * @param input the input reader
83 */
84 public SQLScanner(Reader input)
85 {
86 setInput(input);
87 }
88
89 /***
90 * Set the Input
91 *
92 * @param input the input reader
93 */
94 public void setInput(Reader input)
95 {
96 in = input;
97 }
98
99
100 /***
101 * Reads the next character and increments the line and column counters.
102 *
103 * @throws IOException If an I/O error occurs
104 */
105 private void readChar() throws IOException
106 {
107 boolean wasLine = (char) chr == '\r';
108 chr = in.read();
109 if ((char) chr == '\n' || (char) chr == '\r' || (char) chr == '\f')
110 {
111 col = 0;
112 if (!wasLine || (char) chr != '\n')
113 {
114 line++;
115 }
116 }
117 else
118 {
119 col++;
120 }
121 }
122
123 /***
124 * Scans an identifier.
125 *
126 * @throws IOException If an I/O error occurs
127 */
128 private void scanIdentifier () throws IOException
129 {
130 token = "";
131 char c = (char) chr;
132 while (chr != -1 && WHITE.indexOf(c) == -1 && SPECIAL.indexOf(c) == -1)
133 {
134 token = token + (char) chr;
135 readChar();
136 c = (char) chr;
137 }
138 int start = col - token.length();
139 tokens.add(new Token(token, line, start));
140 }
141
142 /***
143 * Scans an identifier which had started with the negative sign.
144 *
145 * @throws IOException If an I/O error occurs
146 */
147 private void scanNegativeIdentifier () throws IOException
148 {
149 token = "-";
150 char c = (char) chr;
151 while (chr != -1 && WHITE.indexOf(c) == -1 && SPECIAL.indexOf(c) == -1)
152 {
153 token = token + (char) chr;
154 readChar();
155 c = (char) chr;
156 }
157 int start = col - token.length();
158 tokens.add(new Token(token, line, start));
159 }
160
161 /***
162 * Scan the input Reader and returns a list of tokens.
163 *
164 * @return a list of tokens
165 * @throws IOException If an I/O error occurs
166 */
167 public List scan () throws IOException
168 {
169 line = 1;
170 col = 0;
171 boolean inComment = false;
172 boolean inCommentSlashStar = false;
173 boolean inCommentDash = false;
174
175 boolean inNegative;
176
177 tokens = new ArrayList();
178 readChar();
179 while (chr != -1)
180 {
181 char c = (char) chr;
182 inNegative = false;
183
184 if (c == COMMENT_DASH)
185 {
186 readChar();
187 if ((char) chr == COMMENT_DASH)
188 {
189 inCommentDash = true;
190 }
191 else
192 {
193 inNegative = true;
194 c = (char) chr;
195 }
196 }
197
198 if (inCommentDash)
199 {
200 if (c == '\n' || c == '\r')
201 {
202 inCommentDash = false;
203 }
204 readChar();
205 }
206 else if (c == COMMENT_POUND)
207 {
208 inComment = true;
209 readChar();
210 }
211 else if (c == COMMENT_SLASH)
212 {
213 readChar();
214 if ((char) chr == COMMENT_STAR)
215 {
216 inCommentSlashStar = true;
217 }
218 }
219 else if (inComment || inCommentSlashStar)
220 {
221 if (c == '*')
222 {
223 readChar();
224 if ((char) chr == COMMENT_SLASH)
225 {
226 inCommentSlashStar = false;
227 }
228 }
229 else if (c == '\n' || c == '\r')
230 {
231 inComment = false;
232 }
233 readChar();
234 }
235 else if (ALFANUM.indexOf(c) >= 0)
236 {
237 if (inNegative)
238 {
239 scanNegativeIdentifier();
240 }
241 else
242 {
243 scanIdentifier();
244 }
245 }
246 else if (SPECIAL.indexOf(c) >= 0)
247 {
248 tokens.add(new Token("" + c, line, col));
249 readChar();
250 }
251 else
252 {
253 readChar();
254 }
255 }
256 return tokens;
257 }
258 }