]>
Commit | Line | Data |
---|---|---|
8e54aaed RD |
1 | // Scintilla source code edit control |
2 | /** @file LexClw.cxx | |
3 | ** Lexer for Clarion. | |
4 | **/ | |
5 | // Copyright 2003 by Ron Schofield <ron@schofieldcomputer.com> | |
6 | // The License.txt file describes the conditions under which this software may be distributed. | |
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 "StyleContext.h" | |
19 | #include "KeyWords.h" | |
20 | #include "Scintilla.h" | |
21 | #include "SciLexer.h" | |
22 | ||
23 | static char MakeUpperCase(char ch) { | |
24 | if (ch < 'a' || ch > 'z') | |
25 | return ch; | |
26 | else | |
27 | return static_cast<char>(ch - 'a' + 'A'); | |
28 | } | |
29 | ||
30 | static void MakeUpperCaseString(char *s) { | |
31 | while (*s) { | |
32 | *s = MakeUpperCase(*s); | |
33 | s++; | |
34 | } | |
35 | } | |
36 | ||
37 | // Is a label start character | |
38 | inline bool IsALabelStart(const int iChar) { | |
39 | return(isalpha(iChar) || iChar == '_'); | |
40 | } | |
41 | ||
42 | // Is a label character | |
43 | inline bool IsALabelCharacter(const int iChar) { | |
44 | return(isalnum(iChar) || iChar == '_' || iChar == ':'); | |
45 | } | |
46 | ||
47 | // Is the character is a ! and the the next character is not a ! | |
48 | inline bool IsACommentStart(StyleContext &scDoc) { | |
49 | return(scDoc.ch == '!' && scDoc.chNext != '!'); | |
50 | } | |
51 | ||
52 | // Is the character a Clarion hex character (ABCDEF) | |
53 | inline bool IsAHexCharacter(const int iChar, bool bCaseSensitive) { | |
54 | // Case insensitive. | |
55 | if (!bCaseSensitive) { | |
56 | if (strchr("ABCDEFabcdef", iChar) != NULL) { | |
57 | return(true); | |
58 | } | |
59 | } | |
60 | // Case sensitive | |
61 | else { | |
62 | if (strchr("ABCDEF", iChar) != NULL) { | |
63 | return(true); | |
64 | } | |
65 | } | |
66 | return(false); | |
67 | } | |
68 | ||
69 | // Is the character a Clarion base character (B=Binary, O=Octal, H=Hex) | |
70 | inline bool IsANumericBaseCharacter(const int iChar, bool bCaseSensitive) { | |
71 | // Case insensitive. | |
72 | if (!bCaseSensitive) { | |
73 | // If character is a numeric base character | |
74 | if (strchr("BOHboh", iChar) != NULL) { | |
75 | return(true); | |
76 | } | |
77 | } | |
78 | // Case sensitive | |
79 | else { | |
80 | // If character is a numeric base character | |
81 | if (strchr("BOH", iChar) != NULL) { | |
82 | return(true); | |
83 | } | |
84 | } | |
85 | return(false); | |
86 | } | |
87 | ||
88 | // Set the correct numeric constant state | |
89 | inline bool SetNumericConstantState(StyleContext &scDoc) { | |
90 | int iPoints = 0; // Point counter | |
91 | char cNumericString[100]; // Numeric string buffer | |
92 | ||
93 | // Buffer the current numberic string | |
94 | scDoc.GetCurrent(cNumericString, sizeof(cNumericString)); | |
95 | // Loop through the string until end of string (NULL termination) | |
96 | for (int iIndex = 0; cNumericString[iIndex] != '\0'; iIndex++) { | |
97 | // Depending on the character | |
98 | switch (cNumericString[iIndex]) { | |
99 | // Is a . (point) | |
100 | case '.' : | |
101 | // Increment point counter | |
102 | iPoints++; | |
103 | break; | |
104 | default : | |
105 | break; | |
106 | } | |
107 | } | |
108 | // If points found (can be more than one for improper formatted number | |
109 | if (iPoints > 0) { | |
110 | return(true); | |
111 | } | |
112 | // Else no points found | |
113 | else { | |
114 | return(false); | |
115 | } | |
116 | } | |
117 | ||
118 | // Clarion Language Colouring Procedure | |
119 | static void ColouriseClwDoc(unsigned int uiStartPos, int iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler, bool bCaseSensitive) { | |
120 | ||
121 | int iParenthesesLevel=0; // Parenthese Level | |
122 | ||
123 | WordList &wlClarionKeywords = *wlKeywords[0]; // Clarion Keywords | |
124 | WordList &wlCompilerDirectives = *wlKeywords[1]; // Compiler Directives | |
125 | WordList &wlBuiltInProcsFuncs = *wlKeywords[2]; // Builtin Procedures and Functions | |
126 | WordList &wlStructsDataTypes = *wlKeywords[3]; // Structures and Data Types | |
127 | WordList &wlAttributes = *wlKeywords[4]; // Procedure Attributes | |
128 | WordList &wlStandardEquates = *wlKeywords[5]; // Standard Equates | |
129 | WordList &wlReservedWords = *wlKeywords[6]; // Clarion Reserved Keywords | |
130 | ||
131 | StyleContext scDoc(uiStartPos, iLength, iInitStyle, accStyler); | |
132 | ||
133 | // lex source code | |
134 | for (; scDoc.More(); scDoc.Forward()) | |
135 | { | |
136 | // | |
137 | // Determine if the current state should terminate. | |
138 | // | |
139 | ||
140 | // Label State Handling | |
141 | if (scDoc.state == SCE_CLW_LABEL) { | |
142 | // If the character is not a valid label | |
143 | if (!IsALabelCharacter(scDoc.ch)) { | |
144 | // If the character is a . (dot syntax) | |
145 | if (scDoc.ch == '.') { | |
146 | // Uncolour the . (dot) to default state, move forward one character, | |
147 | // and change back to the label state. | |
148 | scDoc.SetState(SCE_CLW_DEFAULT); | |
149 | scDoc.Forward(); | |
150 | scDoc.SetState(SCE_CLW_LABEL); | |
151 | } | |
152 | // Else terminate the label state | |
153 | else { | |
154 | char cLabel[100]; // Label buffer | |
155 | // Buffer the current label string | |
156 | scDoc.GetCurrent(cLabel,sizeof(cLabel)); | |
157 | // If case insensitive, convert string to UPPERCASE to match passed keywords. | |
158 | if (!bCaseSensitive) { | |
159 | MakeUpperCaseString(cLabel); | |
160 | } | |
161 | // If label string is in the Clarion reserved keyword list | |
162 | if (wlReservedWords.InList(cLabel)){ | |
163 | // change to error state | |
164 | scDoc.ChangeState(SCE_CLW_ERROR); | |
165 | } | |
166 | // Else if label string is in the compiler directive keyword list | |
167 | else if (wlCompilerDirectives.InList(cLabel)) { | |
168 | // change the state to compiler directive state | |
169 | scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE); | |
170 | } | |
171 | // Terminate the label state and set to default state | |
172 | scDoc.SetState(SCE_CLW_DEFAULT); | |
173 | } | |
174 | } | |
175 | } | |
176 | // Keyword State Handling | |
177 | else if (scDoc.state == SCE_CLW_KEYWORD) { | |
178 | // If character is : (colon) | |
179 | if (scDoc.ch == ':') { | |
180 | char cEquate[100]; // Equate buffer | |
181 | // Move forward to include : (colon) in buffer | |
182 | scDoc.Forward(); | |
183 | // Buffer the equate string | |
184 | scDoc.GetCurrent(cEquate,sizeof(cEquate)); | |
185 | // If case insensitive, convert string to UPPERCASE to match passed keywords. | |
186 | if (!bCaseSensitive) { | |
187 | MakeUpperCaseString(cEquate); | |
188 | } | |
189 | // If statement string is in the equate list | |
190 | if (wlStandardEquates.InList(cEquate)) { | |
191 | // Change to equate state | |
192 | scDoc.ChangeState(SCE_CLW_STANDARD_EQUATE); | |
193 | } | |
194 | } | |
195 | // If the character is not a valid label character | |
196 | else if (!IsALabelCharacter(scDoc.ch)) { | |
197 | char cStatement[100]; // Statement buffer | |
198 | // Buffer the statement string | |
199 | scDoc.GetCurrent(cStatement,sizeof(cStatement)); | |
200 | // If case insensitive, convert string to UPPERCASE to match passed keywords. | |
201 | if (!bCaseSensitive) { | |
202 | MakeUpperCaseString(cStatement); | |
203 | } | |
204 | // If statement string is in the Clarion keyword list | |
205 | if (wlClarionKeywords.InList(cStatement)) { | |
206 | // Set to the Clarion keyword state | |
207 | scDoc.ChangeState(SCE_CLW_KEYWORD); | |
208 | } | |
209 | // Else if statement string is in the compiler directive keyword list | |
210 | else if (wlCompilerDirectives.InList(cStatement)) { | |
211 | // Set to the compiler directive state | |
212 | scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE); | |
213 | } | |
214 | // Else if statement string is in the builtin procedures and functions keyword list | |
215 | else if (wlBuiltInProcsFuncs.InList(cStatement)) { | |
216 | // Set to the builtin procedures and functions state | |
217 | scDoc.ChangeState(SCE_CLW_BUILTIN_PROCEDURES_FUNCTION); | |
218 | } | |
219 | // Else if statement string is in the tructures and data types keyword list | |
220 | else if (wlStructsDataTypes.InList(cStatement)) { | |
221 | // Set to the structures and data types state | |
222 | scDoc.ChangeState(SCE_CLW_STRUCTURE_DATA_TYPE); | |
223 | } | |
224 | // Else if statement string is in the procedure attribute keyword list | |
225 | else if (wlAttributes.InList(cStatement)) { | |
226 | // Set to the procedure attribute state | |
227 | scDoc.ChangeState(SCE_CLW_ATTRIBUTE); | |
228 | } | |
229 | // Else if statement string is in the standard equate keyword list | |
230 | else if (wlStandardEquates.InList(cStatement)) { | |
231 | // Set to the standard equate state | |
232 | scDoc.ChangeState(SCE_CLW_STANDARD_EQUATE); | |
233 | } | |
234 | // Terminate the keyword state and set to default state | |
235 | scDoc.SetState(SCE_CLW_DEFAULT); | |
236 | } | |
237 | } | |
238 | // String State Handling | |
239 | else if (scDoc.state == SCE_CLW_STRING) { | |
240 | // If the character is an ' (single quote) | |
241 | if (scDoc.ch == '\'') { | |
242 | // Set the state to default and move forward colouring | |
243 | // the ' (single quote) as default state | |
244 | // terminating the string state | |
245 | scDoc.SetState(SCE_CLW_DEFAULT); | |
246 | scDoc.Forward(); | |
247 | } | |
248 | // If the next character is an ' (single quote) | |
249 | if (scDoc.chNext == '\'') { | |
250 | // Move forward one character and set to default state | |
251 | // colouring the next ' (single quote) as default state | |
252 | // terminating the string state | |
253 | scDoc.ForwardSetState(SCE_CLW_DEFAULT); | |
254 | scDoc.Forward(); | |
255 | } | |
256 | } | |
257 | // Picture String State Handling | |
258 | else if (scDoc.state == SCE_CLW_PICTURE_STRING) { | |
259 | // If the character is an ( (open parenthese) | |
260 | if (scDoc.ch == '(') { | |
261 | // Increment the parenthese level | |
262 | iParenthesesLevel++; | |
263 | } | |
264 | // Else if the character is a ) (close parenthese) | |
265 | else if (scDoc.ch == ')') { | |
266 | // If the parenthese level is set to zero | |
267 | // parentheses matched | |
268 | if (!iParenthesesLevel) { | |
269 | scDoc.SetState(SCE_CLW_DEFAULT); | |
270 | } | |
271 | // Else parenthese level is greater than zero | |
272 | // still looking for matching parentheses | |
273 | else { | |
274 | // Decrement the parenthese level | |
275 | iParenthesesLevel--; | |
276 | } | |
277 | } | |
278 | } | |
279 | // Standard Equate State Handling | |
280 | else if (scDoc.state == SCE_CLW_STANDARD_EQUATE) { | |
281 | if (!isalnum(scDoc.ch)) { | |
282 | scDoc.SetState(SCE_CLW_DEFAULT); | |
283 | } | |
284 | } | |
285 | // Integer Constant State Handling | |
286 | else if (scDoc.state == SCE_CLW_INTEGER_CONSTANT) { | |
287 | // If the character is not a digit (0-9) | |
288 | // or character is not a hexidecimal character (A-F) | |
289 | // or character is not a . (point) | |
290 | // or character is not a numberic base character (B,O,H) | |
291 | if (!(isdigit(scDoc.ch) | |
292 | || IsAHexCharacter(scDoc.ch, bCaseSensitive) | |
293 | || scDoc.ch == '.' | |
294 | || IsANumericBaseCharacter(scDoc.ch, bCaseSensitive))) { | |
295 | // If the number was a real | |
296 | if (SetNumericConstantState(scDoc)) { | |
297 | // Colour the matched string to the real constant state | |
298 | scDoc.ChangeState(SCE_CLW_REAL_CONSTANT); | |
299 | } | |
300 | // Else the number was an integer | |
301 | else { | |
302 | // Colour the matched string to an integer constant state | |
303 | scDoc.ChangeState(SCE_CLW_INTEGER_CONSTANT); | |
304 | } | |
305 | // Terminate the integer constant state and set to default state | |
306 | scDoc.SetState(SCE_CLW_DEFAULT); | |
307 | } | |
308 | } | |
309 | ||
310 | // | |
311 | // Determine if a new state should be entered. | |
312 | // | |
313 | ||
314 | // Beginning of Line Handling | |
315 | if (scDoc.atLineStart) { | |
316 | // If column 1 character is a label start character | |
317 | if (IsALabelStart(scDoc.ch)) { | |
318 | // Set the state to label | |
319 | scDoc.SetState(SCE_CLW_LABEL); | |
320 | } | |
321 | // else if character is a space or tab | |
322 | else if (IsASpace(scDoc.ch)){ | |
323 | // Set to default state | |
324 | scDoc.SetState(SCE_CLW_DEFAULT); | |
325 | } | |
326 | // else if the start of a comment or is an * (asterisk) | |
327 | else if (IsACommentStart(scDoc) || scDoc.ch == '*' ) { | |
328 | // then set the state to comment. | |
329 | scDoc.SetState(SCE_CLW_COMMENT); | |
330 | } | |
331 | // else the character is a ? (question mark) | |
332 | else if (scDoc.ch == '?') { | |
333 | // Change to the compiler directive state, move forward, | |
334 | // colouring the ? (question mark), change back to default state. | |
335 | scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE); | |
336 | scDoc.Forward(); | |
337 | scDoc.SetState(SCE_CLW_DEFAULT); | |
338 | } | |
339 | // else an invalid character in column 1 | |
340 | else { | |
341 | // Set to error state | |
342 | scDoc.SetState(SCE_CLW_ERROR); | |
343 | } | |
344 | } | |
345 | // End of Line Handling | |
346 | else if (scDoc.atLineEnd) { | |
347 | // Reset to the default state at the end of each line. | |
348 | scDoc.SetState(SCE_CLW_DEFAULT); | |
349 | } | |
350 | // Default Handling | |
351 | else { | |
352 | // If in default state | |
353 | if (scDoc.state == SCE_CLW_DEFAULT) { | |
354 | // If is a letter could be a possible statement | |
355 | if (isalpha(scDoc.ch)) { | |
356 | // Set the state to Clarion Keyword and verify later | |
357 | scDoc.SetState(SCE_CLW_KEYWORD); | |
358 | } | |
359 | // else is a number | |
360 | else if (isdigit(scDoc.ch)) { | |
361 | // Set the state to Integer Constant and verify later | |
362 | scDoc.SetState(SCE_CLW_INTEGER_CONSTANT); | |
363 | } | |
364 | // else if the start of a comment or a | (line continuation) | |
365 | else if (IsACommentStart(scDoc) || scDoc.ch == '|') { | |
366 | // then set the state to comment. | |
367 | scDoc.SetState(SCE_CLW_COMMENT); | |
368 | } | |
369 | // else if the character is a ' (single quote) | |
370 | else if (scDoc.ch == '\'') { | |
371 | // If the character is also a ' (single quote) | |
372 | // Embedded Apostrophe | |
373 | if (scDoc.chNext == '\'') { | |
374 | // Move forward colouring it as default state | |
375 | scDoc.ForwardSetState(SCE_CLW_DEFAULT); | |
376 | } | |
377 | else { | |
378 | // move to the next character and then set the state to comment. | |
379 | scDoc.ForwardSetState(SCE_CLW_STRING); | |
380 | } | |
381 | } | |
382 | // else the character is an @ (apersand) | |
383 | else if (scDoc.ch == '@') { | |
384 | // Case insensitive. | |
385 | if (!bCaseSensitive) { | |
386 | // If character is a valid picture token character | |
387 | if (strchr("DEKNPSTdeknpst", scDoc.chNext) != NULL) { | |
388 | // Set to the picture string state | |
389 | scDoc.SetState(SCE_CLW_PICTURE_STRING); | |
390 | } | |
391 | } | |
392 | // Case sensitive | |
393 | else { | |
394 | // If character is a valid picture token character | |
395 | if (strchr("DEKNPST", scDoc.chNext) != NULL) { | |
396 | // Set the picture string state | |
397 | scDoc.SetState(SCE_CLW_PICTURE_STRING); | |
398 | } | |
399 | } | |
400 | } | |
401 | } | |
402 | } | |
403 | } | |
404 | // lexing complete | |
405 | scDoc.Complete(); | |
406 | } | |
407 | ||
408 | // Clarion Language Case Sensitive Colouring Procedure | |
409 | static void ColouriseClwDocSensitive(unsigned int uiStartPos, int iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler) { | |
410 | ColouriseClwDoc(uiStartPos, iLength, iInitStyle, wlKeywords, accStyler, true); | |
411 | } | |
412 | ||
413 | // Clarion Language Case Insensitive Colouring Procedure | |
414 | static void ColouriseClwDocInsensitive(unsigned int uiStartPos, int iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler) { | |
415 | ColouriseClwDoc(uiStartPos, iLength, iInitStyle, wlKeywords, accStyler, false); | |
416 | } | |
417 | ||
418 | // Clarion Language Folding Procedure | |
419 | #ifdef FOLDING_IMPLEMENTED | |
420 | static void FoldClwDoc(unsigned int uiStartPos, int iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler) { | |
421 | ||
422 | } | |
423 | #endif | |
424 | ||
425 | // Word List Descriptions | |
426 | static const char * const rgWordListDescriptions[] = { | |
427 | "Clarion Keywords", | |
428 | "Compiler Directives", | |
429 | "Built-in Procedures and Functions", | |
430 | "Structure and Data Types", | |
431 | "Attributes", | |
432 | "Standard Equates", | |
433 | "Reserved Words", | |
434 | 0, | |
435 | }; | |
436 | ||
437 | // Case Sensitive Clarion Language Lexer | |
438 | LexerModule lmClw(SCLEX_CLW, ColouriseClwDocSensitive, "clw", NULL, rgWordListDescriptions); | |
439 | ||
440 | // Case Insensitive Clarion Language Lexer | |
441 | LexerModule lmClwNoCase(SCLEX_CLWNOCASE, ColouriseClwDocInsensitive, "clwnocase", NULL, rgWordListDescriptions); |