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