KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > db > sql > editor > SQLSyntax


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.db.sql.editor;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.StringTokenizer JavaDoc;
27 import org.netbeans.editor.Syntax;
28 import org.netbeans.editor.TokenID;
29 import org.netbeans.modules.db.api.sql.SQLKeywords;
30 import org.openide.util.NbBundle;
31
32 /**
33  * This class implements SQL syntax recognition
34  *
35  * @author Jesse Beaumont
36  */

37 public class SQLSyntax extends Syntax {
38
39     private static final int ISI_WHITESPACE = 2; // inside white space
40
private static final int ISI_LINE_COMMENT = 4; // inside line comment --
41
private static final int ISI_BLOCK_COMMENT = 5; // inside block comment /* ... */
42
private static final int ISI_STRING = 6; // inside string constant
43
private static final int ISI_STRING_A_QUOTE = 7; // inside string constant after '
44
private static final int ISI_IDENTIFIER = 10; // inside identifier
45
private static final int ISA_SLASH = 11; // slash char
46
private static final int ISA_OPERATOR = 12; // after '=', '/', '+'
47
private static final int ISA_MINUS = 13;
48     private static final int ISA_STAR = 20; // after '*'
49
private static final int ISA_STAR_I_BLOCK_COMMENT_END = 21; // after '*' in a block comment
50
private static final int ISA_EXCLAMATION = 26; // after '!'
51
private static final int ISA_ZERO = 27; // after '0'
52
private static final int ISI_INT = 28; // integer number
53
private static final int ISI_DOUBLE = 30; // double number
54
private static final int ISA_DOT = 33; // after '.'
55
private static final int ISA_COMMA = 34; // after ','
56
private static final int ISA_SEMICOLON = 35; //after ';'
57
private static final int ISA_LPAREN = 36; //after (
58
private static final int ISA_RPAREN = 37; //after )
59

60     /**
61      * Creates a new instance of SQLSyntax
62      */

63     public SQLSyntax() {
64         tokenContextPath = SQLTokenContext.contextPath;
65     }
66     
67     /**
68      * Parse the next token
69      */

70     protected TokenID parseToken() {
71         char actChar; //the current character
72

73         //while we still have stuff to parse, do so
74
while(offset < stopOffset) {
75             actChar = buffer[offset];
76
77             //do the appropriate stuff based on what state the parser is in
78
switch (state) {
79                 //the initial state (start of a new token)
80
case INIT:
81                     switch (actChar) {
82                         case '\'': // NOI18N
83
state = ISI_STRING;
84                             break;
85                         case '/':
86                             state = ISA_SLASH;
87                             break;
88                         case '=':
89                         case '>':
90                         case '<':
91                         case '+':
92                         case ',':
93                         case ')':
94                         case '(':
95                         case ';':
96                         case '*':
97                         case '!':
98                             offset++;
99                             state = INIT;
100                             return SQLTokenContext.OPERATOR;
101                         case '-':
102                             state = ISA_MINUS;
103                             break;
104                         case '0':
105                             state = ISA_ZERO;
106                             break;
107                         case '.':
108                             state = ISA_DOT;
109                             break;
110                         default:
111                             // Check for whitespace
112
if (Character.isWhitespace(actChar)) {
113                                 state = ISI_WHITESPACE;
114                                 break;
115                             }
116
117                             // Check for digit
118
if (Character.isDigit(actChar)) {
119                                 state = ISI_INT;
120                                 break;
121                             }
122
123                             // otherwise it's an identifier
124
state = ISI_IDENTIFIER;
125                             break;
126                     }
127                     break;
128                 //if we are currently in a whitespace token
129
case ISI_WHITESPACE: // white space
130
if (!Character.isWhitespace(actChar)) {
131                         state = INIT;
132                         return SQLTokenContext.WHITESPACE;
133                     }
134                     break;
135
136                 //if we are currently in a line comment
137
case ISI_LINE_COMMENT:
138                     if (actChar == '\n') {
139                         state = INIT;
140                         return SQLTokenContext.LINE_COMMENT;
141                     }
142                     break;
143
144                 //if we are currently in a block comment
145
case ISI_BLOCK_COMMENT:
146                     if(actChar =='*') {
147                         state = ISA_STAR_I_BLOCK_COMMENT_END;
148                     }
149                     break;
150                 
151                 //if we are currently in a string literal
152
case ISI_STRING:
153                     switch (actChar) {
154                         case '\n':
155                             state = INIT;
156                             return SQLTokenContext.INCOMPLETE_STRING;
157                         case '\'': // NOI18N
158
offset++;
159                             state = INIT;
160                             return SQLTokenContext.STRING;
161                     }
162                     break;
163
164                 //if we are currently in an identifier (e.g. a variable name)
165
case ISI_IDENTIFIER:
166                     if (!Character.isLetterOrDigit(actChar) && actChar != '_') {
167                         state = INIT;
168                         TokenID tid = matchKeyword(buffer, tokenOffset, offset - tokenOffset);
169                         if (tid != null) {
170                             return tid;
171                         } else {
172                             return SQLTokenContext.IDENTIFIER;
173                         }
174                     }
175                     break;
176
177                 //if we are after a slash (/)
178
case ISA_SLASH:
179                     switch (actChar) {
180                         case '*':
181                             state = ISI_BLOCK_COMMENT;
182                             break;
183                         default:
184                             if(Character.isWhitespace(actChar) ||
185                                     actChar == '(') {
186                                 state = INIT;
187                                 return SQLTokenContext.OPERATOR;
188                             }
189                     }
190                     break;
191
192                 //if we are after a -
193
case ISA_MINUS:
194                     switch (actChar) {
195                         case '-':
196                             state = ISI_LINE_COMMENT;
197                             break;
198                         default:
199                             state = INIT;
200                             return SQLTokenContext.OPERATOR;
201                     }
202                     break;
203                 
204                 //if we are in the middle of a possible block comment end token
205
case ISA_STAR_I_BLOCK_COMMENT_END:
206                     switch (actChar) {
207                         case '/':
208                             offset++;
209                             state = INIT;
210                             return SQLTokenContext.BLOCK_COMMENT;
211                         default:
212                             offset--;
213                             state = ISI_BLOCK_COMMENT;
214                             break;
215                     }
216                     break;
217                        
218                 //if we are after a 0
219
case ISA_ZERO:
220                     switch (actChar) {
221                         case '.':
222                             state = ISI_DOUBLE;
223                             break;
224                         default:
225                             if (Character.isDigit(actChar)) {
226                                 state = ISI_INT;
227                                 break;
228                             } else {
229                                 state = INIT;
230                                 return SQLTokenContext.INT_LITERAL;
231                             }
232                     }
233                     break;
234
235                 //if we are after an integer
236
case ISI_INT:
237                     switch (actChar) {
238                         case '.':
239                             state = ISI_DOUBLE;
240                             break;
241                         default:
242                             if (Character.isDigit(actChar)) {
243                                 state = ISI_INT;
244                                 break;
245                             } else {
246                                 state = INIT;
247                                 return SQLTokenContext.INT_LITERAL;
248                             }
249                     }
250                     break;
251
252                 //if we are in the middle of what we believe is a floating point
253
//number
254
case ISI_DOUBLE:
255                     if (actChar >= '0' && actChar <= '9') {
256                         state = ISI_DOUBLE;
257                         break;
258                     } else {
259                         state = INIT;
260                         return SQLTokenContext.DOUBLE_LITERAL;
261                     }
262
263                 //if we are after a period
264
case ISA_DOT:
265                     if (Character.isDigit(actChar)) {
266                         state = ISI_DOUBLE;
267                     } else { // only single dot
268
state = INIT;
269                         return SQLTokenContext.DOT;
270                     }
271                     break;
272
273             } // end of switch(state)
274

275             offset++;
276         } // end of while(offset...)
277

278         /*
279          * At this stage there's no more text in the scanned buffer.
280          * Scanner first checks whether this is completely the last
281          * available buffer.
282          */

283         if (lastBuffer) {
284             switch(state) {
285             case ISI_WHITESPACE:
286                 state = INIT;
287                     return SQLTokenContext.WHITESPACE;
288             case ISI_IDENTIFIER:
289                 state = INIT;
290                 TokenID tid =
291                         matchKeyword(buffer, tokenOffset, offset - tokenOffset);
292                 if(tid != null) {
293                     return tid;
294                 }
295                 else {
296                     return SQLTokenContext.IDENTIFIER;
297                 }
298             case ISI_LINE_COMMENT:
299                 // stay in line-comment state
300
return SQLTokenContext.LINE_COMMENT;
301             case ISI_BLOCK_COMMENT:
302             case ISA_STAR_I_BLOCK_COMMENT_END:
303                 // stay in block-comment state
304
return SQLTokenContext.BLOCK_COMMENT;
305             case ISI_STRING:
306                 return SQLTokenContext.STRING; // hold the state
307
case ISA_ZERO:
308             case ISI_INT:
309                 state = INIT;
310                 return SQLTokenContext.INT_LITERAL;
311             case ISI_DOUBLE:
312                 state = INIT;
313                 return SQLTokenContext.DOUBLE_LITERAL;
314             case ISA_DOT:
315                 state = INIT;
316                 return SQLTokenContext.DOT;
317             case ISA_SLASH:
318                 state = INIT;
319                 return SQLTokenContext.OPERATOR;
320             }
321         }
322
323         /*
324          * At this stage there's no more text in the scanned buffer, but
325          * this buffer is not the last so the
326          * scan will continue on another buffer.
327          * The scanner tries to minimize the amount of characters
328          * that will be prescanned in the next buffer by returning the token
329          * where possible.
330          */

331
332         switch (state) {
333             case ISI_WHITESPACE:
334                     return SQLTokenContext.WHITESPACE;
335         }
336
337         return null; // nothing found
338
}
339
340     /**
341      * Returns the state name for the state id
342      */

343     public String JavaDoc getStateName(int stateNumber) {
344         switch(stateNumber) {
345         case ISI_WHITESPACE:
346             return "ISI_WHITESPACE"; // NOI18N
347
case ISI_LINE_COMMENT:
348             return "ISI_LINE_COMMENT"; // NOI18N
349
case ISI_BLOCK_COMMENT:
350             return "ISI_BLOCK_COMMENT"; // NOI18N
351
case ISI_STRING:
352             return "ISI_STRING"; // NOI18N
353
case ISI_STRING_A_QUOTE:
354             return "ISI_STRING_A_QUOTE"; // NOI18N
355
case ISI_IDENTIFIER:
356             return "ISI_IDENTIFIER"; // NOI18N
357
case ISA_SLASH:
358             return "ISA_SLASH"; // NOI18N
359
case ISA_OPERATOR:
360             return "ISA_OPERATOR"; // NOI18N
361
case ISA_MINUS:
362             return "ISA_MINUS"; // NOI18N
363
case ISA_STAR:
364             return "ISA_STAR"; // NOI18N
365
case ISA_STAR_I_BLOCK_COMMENT_END:
366             return "ISA_STAR_I_BLOCK_COMMENT_END"; // NOI18N
367
case ISA_ZERO:
368             return "ISA_ZERO"; // NOI18N
369
case ISI_INT:
370             return "ISI_INT"; // NOI18N
371
case ISI_DOUBLE:
372             return "ISI_DOUBLE"; // NOI18N
373
case ISA_DOT:
374             return "ISA_DOT"; // NOI18N
375
case ISA_COMMA:
376             return "ISA_COMMA"; // NOI18N
377

378         default:
379             return super.getStateName(stateNumber);
380         }
381     }
382
383     /**
384      * Tries to match the specified sequence of characters to a SQL
385      * keyword.
386      *
387      * @return the KEYWORD id or null if no match was found
388      */

389     public TokenID matchKeyword(char[] buffer, int offset, int len) {
390         String JavaDoc keywordCandidate = new String JavaDoc(buffer, offset, len);
391         
392         if (SQLKeywords.isSQL99Keyword(keywordCandidate)) {
393             return SQLTokenContext.KEYWORD;
394         }
395         
396         return null;
397     }
398 }
399
Popular Tags