]>
Commit | Line | Data |
---|---|---|
591d01be RD |
1 | // Scintilla source code edit control |
2 | /** @file LexMSSQL.cxx | |
3 | ** Lexer for MSSQL. | |
4 | **/ | |
5 | // Copyright 1998-2002 by Filip Yaghob <fy@eg.cz> | |
6 | ||
7 | ||
8 | #include <stdlib.h> | |
9 | #include <string.h> | |
10 | #include <ctype.h> | |
11 | #include <stdio.h> | |
12 | #include <stdarg.h> | |
13 | ||
14 | #include "Platform.h" | |
15 | ||
16 | #include "PropSet.h" | |
17 | #include "Accessor.h" | |
18 | #include "KeyWords.h" | |
19 | #include "Scintilla.h" | |
20 | #include "SciLexer.h" | |
21 | ||
22 | #define KW_MSSQL_STATEMENTS 0 | |
23 | #define KW_MSSQL_DATA_TYPES 1 | |
24 | #define KW_MSSQL_SYSTEM_TABLES 2 | |
25 | #define KW_MSSQL_GLOBAL_VARIABLES 3 | |
26 | #define KW_MSSQL_FUNCTIONS 4 | |
27 | #define KW_MSSQL_STORED_PROCEDURES 5 | |
28 | #define KW_MSSQL_OPERATORS 6 | |
29 | ||
30 | //~ val SCE_MSSQL_DEFAULT=0 | |
31 | //~ val SCE_MSSQL_COMMENT=1 | |
32 | //~ val SCE_MSSQL_LINE_COMMENT=2 | |
33 | //~ val SCE_MSSQL_NUMBER=3 | |
34 | //~ val SCE_MSSQL_STRING=4 | |
35 | //~ val SCE_MSSQL_OPERATOR=5 | |
36 | //~ val SCE_MSSQL_IDENTIFIER=6 | |
37 | //~ val SCE_MSSQL_VARIABLE=7 | |
38 | //~ val SCE_MSSQL_COLUMN_NAME=8 | |
39 | //~ val SCE_MSSQL_STATEMENT=9 | |
40 | //~ val SCE_MSSQL_DATATYPE=10 | |
41 | //~ val SCE_MSSQL_SYSTABLE=11 | |
42 | //~ val SCE_MSSQL_GLOBAL_VARIABLE=12 | |
43 | //~ val SCE_MSSQL_FUNCTION=13 | |
44 | //~ val SCE_MSSQL_STORED_PROCEDURE=14 | |
45 | //~ val SCE_MSSQL_DEFAULT_PREF_DATATYPE 15 | |
46 | //~ val SCE_MSSQL_COLUMN_NAME_2 16 | |
47 | ||
48 | static bool isMSSQLOperator(char ch) { | |
49 | if (isascii(ch) && isalnum(ch)) | |
50 | return false; | |
51 | // '.' left out as it is used to make up numbers | |
52 | if (ch == '%' || ch == '^' || ch == '&' || ch == '*' || | |
53 | ch == '-' || ch == '+' || ch == '=' || ch == '|' || | |
54 | ch == '<' || ch == '>' || ch == '/' || | |
55 | ch == '!' || ch == '~' || ch == '(' || ch == ')' || | |
56 | ch == ',') | |
57 | return true; | |
58 | return false; | |
59 | } | |
60 | ||
61 | static char classifyWordSQL(unsigned int start, | |
62 | unsigned int end, | |
63 | WordList *keywordlists[], | |
64 | Accessor &styler, | |
65 | unsigned int actualState, | |
66 | unsigned int prevState) { | |
67 | char s[256]; | |
68 | bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); | |
69 | ||
70 | WordList &kwStatements = *keywordlists[KW_MSSQL_STATEMENTS]; | |
71 | WordList &kwDataTypes = *keywordlists[KW_MSSQL_DATA_TYPES]; | |
72 | WordList &kwSystemTables = *keywordlists[KW_MSSQL_SYSTEM_TABLES]; | |
73 | WordList &kwGlobalVariables = *keywordlists[KW_MSSQL_GLOBAL_VARIABLES]; | |
74 | WordList &kwFunctions = *keywordlists[KW_MSSQL_FUNCTIONS]; | |
75 | WordList &kwStoredProcedures = *keywordlists[KW_MSSQL_STORED_PROCEDURES]; | |
76 | WordList &kwOperators = *keywordlists[KW_MSSQL_OPERATORS]; | |
77 | ||
78 | for (unsigned int i = 0; i < end - start + 1 && i < 128; i++) { | |
79 | s[i] = static_cast<char>(tolower(styler[start + i])); | |
80 | s[i + 1] = '\0'; | |
81 | } | |
82 | char chAttr = SCE_MSSQL_IDENTIFIER; | |
83 | ||
84 | if (actualState == SCE_MSSQL_GLOBAL_VARIABLE) { | |
85 | ||
86 | if (kwGlobalVariables.InList(&s[2])) | |
87 | chAttr = SCE_MSSQL_GLOBAL_VARIABLE; | |
88 | ||
89 | } else if (wordIsNumber) { | |
90 | chAttr = SCE_MSSQL_NUMBER; | |
91 | ||
92 | } else if (prevState == SCE_MSSQL_DEFAULT_PREF_DATATYPE) { | |
93 | // Look first in datatypes | |
94 | if (kwDataTypes.InList(s)) | |
95 | chAttr = SCE_MSSQL_DATATYPE; | |
96 | else if (kwOperators.InList(s)) | |
97 | chAttr = SCE_MSSQL_OPERATOR; | |
98 | else if (kwStatements.InList(s)) | |
99 | chAttr = SCE_MSSQL_STATEMENT; | |
100 | else if (kwSystemTables.InList(s)) | |
101 | chAttr = SCE_MSSQL_SYSTABLE; | |
102 | else if (kwFunctions.InList(s)) | |
103 | chAttr = SCE_MSSQL_FUNCTION; | |
104 | else if (kwStoredProcedures.InList(s)) | |
105 | chAttr = SCE_MSSQL_STORED_PROCEDURE; | |
106 | ||
107 | } else { | |
108 | if (kwOperators.InList(s)) | |
109 | chAttr = SCE_MSSQL_OPERATOR; | |
110 | else if (kwStatements.InList(s)) | |
111 | chAttr = SCE_MSSQL_STATEMENT; | |
112 | else if (kwSystemTables.InList(s)) | |
113 | chAttr = SCE_MSSQL_SYSTABLE; | |
114 | else if (kwFunctions.InList(s)) | |
115 | chAttr = SCE_MSSQL_FUNCTION; | |
116 | else if (kwStoredProcedures.InList(s)) | |
117 | chAttr = SCE_MSSQL_STORED_PROCEDURE; | |
118 | else if (kwDataTypes.InList(s)) | |
119 | chAttr = SCE_MSSQL_DATATYPE; | |
120 | } | |
121 | ||
122 | styler.ColourTo(end, chAttr); | |
123 | ||
124 | return chAttr; | |
125 | } | |
126 | ||
127 | static void ColouriseMSSQLDoc(unsigned int startPos, int length, | |
128 | int initStyle, WordList *keywordlists[], Accessor &styler) { | |
129 | ||
130 | ||
131 | styler.StartAt(startPos); | |
132 | ||
133 | bool fold = styler.GetPropertyInt("fold") != 0; | |
134 | int lineCurrent = styler.GetLine(startPos); | |
135 | int spaceFlags = 0; | |
136 | /* | |
137 | WordList &kwStatements = *keywordlists[KW_MSSQL_STATEMENTS]; | |
138 | WordList &kwDataTypes = *keywordlists[KW_MSSQL_DATA_TYPES]; | |
139 | WordList &kwSystemTables = *keywordlists[KW_MSSQL_SYSTEM_TABLES]; | |
140 | WordList &kwGlobalVariables = *keywordlists[KW_MSSQL_GLOBAL_VARIABLES]; | |
141 | WordList &kwFunctions = *keywordlists[KW_MSSQL_FUNCTIONS]; | |
142 | ||
143 | char s[100]; | |
144 | int iixx = 0; | |
145 | s[0] = 's'; s[1] = 'e'; s[2] = 'l'; s[3] = 'e'; s[4] = 'c'; s[5] = 't'; s[6] = 0; | |
146 | if (kwStatements.InList(s)) | |
147 | iixx = 1; | |
148 | s[0] = 's'; s[1] = 'e'; s[2] = 'r'; s[3] = 'v'; s[4] = 'e'; s[5] = 'r'; s[6] = 'n'; s[7] = 'a'; s[8] = 'm'; s[9] = 'e'; s[10] = 0; | |
149 | if (kwGlobalVariables.InList(s)) | |
150 | iixx += 2; | |
151 | */ | |
152 | int state = initStyle; | |
153 | int prevState = initStyle; | |
154 | char chPrev = ' '; | |
155 | char chNext = styler[startPos]; | |
156 | styler.StartSegment(startPos); | |
157 | unsigned int lengthDoc = startPos + length; | |
158 | for (unsigned int i = startPos; i < lengthDoc; i++) { | |
159 | char ch = chNext; | |
160 | chNext = styler.SafeGetCharAt(i + 1); | |
161 | ||
162 | if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { | |
163 | int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags); | |
164 | int lev = indentCurrent; | |
165 | if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { | |
166 | // Only non whitespace lines can be headers | |
167 | int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags); | |
168 | if (indentCurrent < (indentNext & ~SC_FOLDLEVELWHITEFLAG)) { | |
169 | lev |= SC_FOLDLEVELHEADERFLAG; | |
170 | } | |
171 | } | |
172 | if (fold) { | |
173 | styler.SetLevel(lineCurrent, lev); | |
174 | } | |
175 | } | |
176 | ||
177 | if (styler.IsLeadByte(ch)) { | |
178 | chNext = styler.SafeGetCharAt(i + 2); | |
179 | chPrev = ' '; | |
180 | i += 1; | |
181 | continue; | |
182 | } | |
183 | ||
184 | // When the last char isn't part of the state (have to deal with it too)... | |
185 | if ( (state == SCE_MSSQL_IDENTIFIER) || | |
186 | (state == SCE_MSSQL_STORED_PROCEDURE) || | |
187 | (state == SCE_MSSQL_DATATYPE) || | |
188 | //~ (state == SCE_MSSQL_COLUMN_NAME) || | |
189 | (state == SCE_MSSQL_FUNCTION) || | |
190 | //~ (state == SCE_MSSQL_GLOBAL_VARIABLE) || | |
191 | (state == SCE_MSSQL_VARIABLE)) { | |
192 | if (!iswordchar(ch)) { | |
193 | int stateTmp; | |
194 | ||
195 | if ((state == SCE_MSSQL_VARIABLE) || (state == SCE_MSSQL_COLUMN_NAME)) { | |
196 | styler.ColourTo(i - 1, state); | |
197 | stateTmp = state; | |
198 | } else | |
199 | stateTmp = classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState); | |
200 | ||
201 | prevState = state; | |
202 | ||
203 | if (stateTmp == SCE_MSSQL_IDENTIFIER || stateTmp == SCE_MSSQL_VARIABLE) | |
204 | state = SCE_MSSQL_DEFAULT_PREF_DATATYPE; | |
205 | else | |
206 | state = SCE_MSSQL_DEFAULT; | |
207 | } | |
208 | } else if (state == SCE_MSSQL_LINE_COMMENT) { | |
209 | if (ch == '\r' || ch == '\n') { | |
210 | styler.ColourTo(i - 1, state); | |
211 | prevState = state; | |
212 | state = SCE_MSSQL_DEFAULT; | |
213 | } | |
214 | } else if (state == SCE_MSSQL_GLOBAL_VARIABLE) { | |
215 | if ((ch != '@') && !iswordchar(ch)) { | |
216 | classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState); | |
217 | prevState = state; | |
218 | state = SCE_MSSQL_DEFAULT; | |
219 | } | |
220 | } | |
221 | ||
222 | // If is the default or one of the above succeeded | |
223 | if (state == SCE_MSSQL_DEFAULT || state == SCE_MSSQL_DEFAULT_PREF_DATATYPE) { | |
224 | if (iswordstart(ch)) { | |
225 | styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); | |
226 | prevState = state; | |
227 | state = SCE_MSSQL_IDENTIFIER; | |
228 | } else if (ch == '/' && chNext == '*') { | |
229 | styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); | |
230 | prevState = state; | |
231 | state = SCE_MSSQL_COMMENT; | |
232 | } else if (ch == '-' && chNext == '-') { | |
233 | styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); | |
234 | prevState = state; | |
235 | state = SCE_MSSQL_LINE_COMMENT; | |
236 | } else if (ch == '\'') { | |
237 | styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); | |
238 | prevState = state; | |
239 | state = SCE_MSSQL_STRING; | |
240 | } else if (ch == '"') { | |
241 | styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); | |
242 | prevState = state; | |
243 | state = SCE_MSSQL_COLUMN_NAME; | |
244 | } else if (ch == '[') { | |
245 | styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); | |
246 | prevState = state; | |
247 | state = SCE_MSSQL_COLUMN_NAME_2; | |
248 | } else if (isMSSQLOperator(ch)) { | |
249 | styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); | |
250 | styler.ColourTo(i, SCE_MSSQL_OPERATOR); | |
251 | //~ style = SCE_MSSQL_DEFAULT; | |
252 | prevState = state; | |
253 | state = SCE_MSSQL_DEFAULT; | |
254 | } else if (ch == '@') { | |
255 | styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); | |
256 | prevState = state; | |
257 | if (chNext == '@') { | |
258 | state = SCE_MSSQL_GLOBAL_VARIABLE; | |
259 | // i += 2; | |
260 | } else | |
261 | state = SCE_MSSQL_VARIABLE; | |
262 | } | |
263 | ||
264 | ||
265 | // When the last char is part of the state... | |
266 | } else if (state == SCE_MSSQL_COMMENT) { | |
267 | if (ch == '/' && chPrev == '*') { | |
268 | if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_MSSQL_COMMENT) && | |
269 | (styler.GetStartSegment() == startPos)))) { | |
270 | styler.ColourTo(i, state); | |
271 | //~ state = SCE_MSSQL_COMMENT; | |
272 | prevState = state; | |
273 | state = SCE_MSSQL_DEFAULT; | |
274 | } | |
275 | } | |
276 | } else if (state == SCE_MSSQL_STRING) { | |
277 | if (ch == '\'') { | |
278 | if ( chNext == '\'' ) { | |
279 | i++; | |
280 | ch = chNext; | |
281 | chNext = styler.SafeGetCharAt(i + 1); | |
282 | } else { | |
283 | styler.ColourTo(i, state); | |
284 | prevState = state; | |
285 | state = SCE_MSSQL_DEFAULT; | |
286 | //i++; | |
287 | } | |
288 | //ch = chNext; | |
289 | //chNext = styler.SafeGetCharAt(i + 1); | |
290 | } | |
291 | } else if (state == SCE_MSSQL_COLUMN_NAME) { | |
292 | if (ch == '"') { | |
293 | if (chNext == '"') { | |
294 | i++; | |
295 | ch = chNext; | |
296 | chNext = styler.SafeGetCharAt(i + 1); | |
297 | } else { | |
298 | styler.ColourTo(i, state); | |
299 | prevState = state; | |
300 | state = SCE_MSSQL_DEFAULT_PREF_DATATYPE; | |
301 | //i++; | |
302 | } | |
303 | } | |
304 | } else if (state == SCE_MSSQL_COLUMN_NAME_2) { | |
305 | if (ch == ']') { | |
306 | styler.ColourTo(i, state); | |
307 | prevState = state; | |
308 | state = SCE_MSSQL_DEFAULT_PREF_DATATYPE; | |
309 | //i++; | |
310 | } | |
311 | } | |
312 | ||
313 | chPrev = ch; | |
314 | } | |
315 | styler.ColourTo(lengthDoc - 1, state); | |
316 | } | |
317 | ||
318 | static const char * const sqlWordListDesc[] = { | |
319 | "Statements", | |
320 | "Data Types", | |
321 | "System tables", | |
322 | "Global variables", | |
323 | "Functions", | |
324 | "System Stored Procedures", | |
325 | "Operators", | |
326 | 0, | |
327 | }; | |
328 | ||
329 | LexerModule lmMSSQL(SCLEX_MSSQL, ColouriseMSSQLDoc, "mssql", 0, sqlWordListDesc); |