1 | // Scintilla source code edit control |
2 | /** @file LexCLW.cxx |
3 | ** Lexer for Clarion. |
4 | ** 2004/12/17 Updated Lexer |
5 | **/ |
6 | // Copyright 2003-2004 by Ron Schofield <ron@schofieldcomputer.com> |
7 | // The License.txt file describes the conditions under which this software may be distributed. |
8 | |
9 | #include <stdlib.h> |
10 | #include <string.h> |
11 | #include <stdio.h> |
12 | #include <stdarg.h> |
13 | #include <assert.h> |
14 | #include <ctype.h> |
15 | |
16 | #include <string> |
17 | #include <string_view> |
18 | |
19 | #include "ILexer.h" |
20 | #include "Scintilla.h" |
21 | #include "SciLexer.h" |
22 | |
23 | #include "WordList.h" |
24 | #include "LexAccessor.h" |
25 | #include "Accessor.h" |
26 | #include "StyleContext.h" |
27 | #include "CharacterSet.h" |
28 | #include "LexerModule.h" |
29 | |
30 | using namespace Lexilla; |
31 | |
32 | // Is an end of line character |
33 | inline bool IsEOL(const int ch) { |
34 | |
35 | return(ch == '\n'); |
36 | } |
37 | |
38 | // Convert character to uppercase |
39 | static char CharacterUpper(char chChar) { |
40 | |
41 | if (chChar < 'a' || chChar > 'z') { |
42 | return(chChar); |
43 | } |
44 | else { |
45 | return(static_cast<char>(chChar - 'a' + 'A')); |
46 | } |
47 | } |
48 | |
49 | // Convert string to uppercase |
50 | static void StringUpper(char *szString) { |
51 | |
52 | while (*szString) { |
53 | *szString = CharacterUpper(*szString); |
54 | szString++; |
55 | } |
56 | } |
57 | |
58 | // Is a label start character |
59 | inline bool IsALabelStart(const int iChar) { |
60 | |
61 | return(isalpha(iChar) || iChar == '_'); |
62 | } |
63 | |
64 | // Is a label character |
65 | inline bool IsALabelCharacter(const int iChar) { |
66 | |
67 | return(isalnum(iChar) || iChar == '_' || iChar == ':'); |
68 | } |
69 | |
70 | // Is the character is a ! and the the next character is not a ! |
71 | inline bool (const int iChar) { |
72 | |
73 | return(iChar == '!'); |
74 | } |
75 | |
76 | // Is the character a Clarion hex character (ABCDEF) |
77 | inline bool IsAHexCharacter(const int iChar, bool bCaseSensitive) { |
78 | |
79 | // Case insensitive. |
80 | if (!bCaseSensitive) { |
81 | if (strchr("ABCDEFabcdef" , iChar) != NULL) { |
82 | return(true); |
83 | } |
84 | } |
85 | // Case sensitive |
86 | else { |
87 | if (strchr("ABCDEF" , iChar) != NULL) { |
88 | return(true); |
89 | } |
90 | } |
91 | return(false); |
92 | } |
93 | |
94 | // Is the character a Clarion base character (B=Binary, O=Octal, H=Hex) |
95 | inline bool IsANumericBaseCharacter(const int iChar, bool bCaseSensitive) { |
96 | |
97 | // Case insensitive. |
98 | if (!bCaseSensitive) { |
99 | // If character is a numeric base character |
100 | if (strchr("BOHboh" , iChar) != NULL) { |
101 | return(true); |
102 | } |
103 | } |
104 | // Case sensitive |
105 | else { |
106 | // If character is a numeric base character |
107 | if (strchr("BOH" , iChar) != NULL) { |
108 | return(true); |
109 | } |
110 | } |
111 | return(false); |
112 | } |
113 | |
114 | // Set the correct numeric constant state |
115 | inline bool SetNumericConstantState(StyleContext &scDoc) { |
116 | |
117 | int iPoints = 0; // Point counter |
118 | char cNumericString[512]; // Numeric string buffer |
119 | |
120 | // Buffer the current numberic string |
121 | scDoc.GetCurrent(cNumericString, sizeof(cNumericString)); |
122 | // Loop through the string until end of string (NULL termination) |
123 | for (int iIndex = 0; cNumericString[iIndex] != '\0'; iIndex++) { |
124 | // Depending on the character |
125 | switch (cNumericString[iIndex]) { |
126 | // Is a . (point) |
127 | case '.' : |
128 | // Increment point counter |
129 | iPoints++; |
130 | break; |
131 | default : |
132 | break; |
133 | } |
134 | } |
135 | // If points found (can be more than one for improper formatted number |
136 | if (iPoints > 0) { |
137 | return(true); |
138 | } |
139 | // Else no points found |
140 | else { |
141 | return(false); |
142 | } |
143 | } |
144 | |
145 | // Get the next word in uppercase from the current position (keyword lookahead) |
146 | inline bool GetNextWordUpper(Accessor &styler, Sci_PositionU uiStartPos, Sci_Position iLength, char *cWord) { |
147 | |
148 | Sci_PositionU iIndex = 0; // Buffer Index |
149 | |
150 | // Loop through the remaining string from the current position |
151 | for (Sci_Position iOffset = uiStartPos; iOffset < iLength; iOffset++) { |
152 | // Get the character from the buffer using the offset |
153 | char cCharacter = styler[iOffset]; |
154 | if (IsEOL(cCharacter)) { |
155 | break; |
156 | } |
157 | // If the character is alphabet character |
158 | if (isalpha(cCharacter)) { |
159 | // Add UPPERCASE character to the word buffer |
160 | cWord[iIndex++] = CharacterUpper(cCharacter); |
161 | } |
162 | } |
163 | // Add null termination |
164 | cWord[iIndex] = '\0'; |
165 | // If no word was found |
166 | if (iIndex == 0) { |
167 | // Return failure |
168 | return(false); |
169 | } |
170 | // Else word was found |
171 | else { |
172 | // Return success |
173 | return(true); |
174 | } |
175 | } |
176 | |
177 | // Clarion Language Colouring Procedure |
178 | static void ColouriseClarionDoc(Sci_PositionU uiStartPos, Sci_Position iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler, bool bCaseSensitive) { |
179 | |
180 | int iParenthesesLevel = 0; // Parenthese Level |
181 | int iColumn1Label = false; // Label starts in Column 1 |
182 | |
183 | WordList &wlClarionKeywords = *wlKeywords[0]; // Clarion Keywords |
184 | WordList &wlCompilerDirectives = *wlKeywords[1]; // Compiler Directives |
185 | WordList &wlRuntimeExpressions = *wlKeywords[2]; // Runtime Expressions |
186 | WordList &wlBuiltInProcsFuncs = *wlKeywords[3]; // Builtin Procedures and Functions |
187 | WordList &wlStructsDataTypes = *wlKeywords[4]; // Structures and Data Types |
188 | WordList &wlAttributes = *wlKeywords[5]; // Procedure Attributes |
189 | WordList &wlStandardEquates = *wlKeywords[6]; // Standard Equates |
190 | WordList &wlLabelReservedWords = *wlKeywords[7]; // Clarion Reserved Keywords (Labels) |
191 | WordList &wlProcLabelReservedWords = *wlKeywords[8]; // Clarion Reserved Keywords (Procedure Labels) |
192 | |
193 | const char wlProcReservedKeywordList[] = |
194 | "PROCEDURE FUNCTION" ; |
195 | WordList wlProcReservedKeywords; |
196 | wlProcReservedKeywords.Set(wlProcReservedKeywordList); |
197 | |
198 | const char wlCompilerKeywordList[] = |
199 | "COMPILE OMIT" ; |
200 | WordList wlCompilerKeywords; |
201 | wlCompilerKeywords.Set(wlCompilerKeywordList); |
202 | |
203 | const char wlLegacyStatementsList[] = |
204 | "BOF EOF FUNCTION POINTER SHARE" ; |
205 | WordList wlLegacyStatements; |
206 | wlLegacyStatements.Set(wlLegacyStatementsList); |
207 | |
208 | StyleContext scDoc(uiStartPos, iLength, iInitStyle, accStyler); |
209 | |
210 | // lex source code |
211 | for (; scDoc.More(); scDoc.Forward()) |
212 | { |
213 | // |
214 | // Determine if the current state should terminate. |
215 | // |
216 | |
217 | // Label State Handling |
218 | if (scDoc.state == SCE_CLW_LABEL) { |
219 | // If the character is not a valid label |
220 | if (!IsALabelCharacter(scDoc.ch)) { |
221 | // If the character is a . (dot syntax) |
222 | if (scDoc.ch == '.') { |
223 | // Turn off column 1 label flag as label now cannot be reserved work |
224 | iColumn1Label = false; |
225 | // Uncolour the . (dot) to default state, move forward one character, |
226 | // and change back to the label state. |
227 | scDoc.SetState(SCE_CLW_DEFAULT); |
228 | scDoc.Forward(); |
229 | scDoc.SetState(SCE_CLW_LABEL); |
230 | } |
231 | // Else check label |
232 | else { |
233 | char cLabel[512]; // Label buffer |
234 | // Buffer the current label string |
235 | scDoc.GetCurrent(cLabel,sizeof(cLabel)); |
236 | // If case insensitive, convert string to UPPERCASE to match passed keywords. |
237 | if (!bCaseSensitive) { |
238 | StringUpper(cLabel); |
239 | } |
240 | // Else if UPPERCASE label string is in the Clarion compiler keyword list |
241 | if (wlCompilerKeywords.InList(cLabel) && iColumn1Label){ |
242 | // change the label to error state |
243 | scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE); |
244 | } |
245 | // Else if UPPERCASE label string is in the Clarion reserved keyword list |
246 | else if (wlLabelReservedWords.InList(cLabel) && iColumn1Label){ |
247 | // change the label to error state |
248 | scDoc.ChangeState(SCE_CLW_ERROR); |
249 | } |
250 | // Else if UPPERCASE label string is |
251 | else if (wlProcLabelReservedWords.InList(cLabel) && iColumn1Label) { |
252 | char cWord[512]; // Word buffer |
253 | // Get the next word from the current position |
254 | if (GetNextWordUpper(accStyler,scDoc.currentPos,uiStartPos+iLength,cWord)) { |
255 | // If the next word is a procedure reserved word |
256 | if (wlProcReservedKeywords.InList(cWord)) { |
257 | // Change the label to error state |
258 | scDoc.ChangeState(SCE_CLW_ERROR); |
259 | } |
260 | } |
261 | } |
262 | // Else if label string is in the compiler directive keyword list |
263 | else if (wlCompilerDirectives.InList(cLabel)) { |
264 | // change the state to compiler directive state |
265 | scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE); |
266 | } |
267 | // Terminate the label state and set to default state |
268 | scDoc.SetState(SCE_CLW_DEFAULT); |
269 | } |
270 | } |
271 | } |
272 | // Keyword State Handling |
273 | else if (scDoc.state == SCE_CLW_KEYWORD) { |
274 | // If character is : (colon) |
275 | if (scDoc.ch == ':') { |
276 | char cEquate[512]; // Equate buffer |
277 | // Move forward to include : (colon) in buffer |
278 | scDoc.Forward(); |
279 | // Buffer the equate string |
280 | scDoc.GetCurrent(cEquate,sizeof(cEquate)); |
281 | // If case insensitive, convert string to UPPERCASE to match passed keywords. |
282 | if (!bCaseSensitive) { |
283 | StringUpper(cEquate); |
284 | } |
285 | // If statement string is in the equate list |
286 | if (wlStandardEquates.InList(cEquate)) { |
287 | // Change to equate state |
288 | scDoc.ChangeState(SCE_CLW_STANDARD_EQUATE); |
289 | } |
290 | } |
291 | // If the character is not a valid label character |
292 | else if (!IsALabelCharacter(scDoc.ch)) { |
293 | char cStatement[512]; // Statement buffer |
294 | // Buffer the statement string |
295 | scDoc.GetCurrent(cStatement,sizeof(cStatement)); |
296 | // If case insensitive, convert string to UPPERCASE to match passed keywords. |
297 | if (!bCaseSensitive) { |
298 | StringUpper(cStatement); |
299 | } |
300 | // If statement string is in the Clarion keyword list |
301 | if (wlClarionKeywords.InList(cStatement)) { |
302 | // Change the statement string to the Clarion keyword state |
303 | scDoc.ChangeState(SCE_CLW_KEYWORD); |
304 | } |
305 | // Else if statement string is in the compiler directive keyword list |
306 | else if (wlCompilerDirectives.InList(cStatement)) { |
307 | // Change the statement string to the compiler directive state |
308 | scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE); |
309 | } |
310 | // Else if statement string is in the runtime expressions keyword list |
311 | else if (wlRuntimeExpressions.InList(cStatement)) { |
312 | // Change the statement string to the runtime expressions state |
313 | scDoc.ChangeState(SCE_CLW_RUNTIME_EXPRESSIONS); |
314 | } |
315 | // Else if statement string is in the builtin procedures and functions keyword list |
316 | else if (wlBuiltInProcsFuncs.InList(cStatement)) { |
317 | // Change the statement string to the builtin procedures and functions state |
318 | scDoc.ChangeState(SCE_CLW_BUILTIN_PROCEDURES_FUNCTION); |
319 | } |
320 | // Else if statement string is in the tructures and data types keyword list |
321 | else if (wlStructsDataTypes.InList(cStatement)) { |
322 | // Change the statement string to the structures and data types state |
323 | scDoc.ChangeState(SCE_CLW_STRUCTURE_DATA_TYPE); |
324 | } |
325 | // Else if statement string is in the procedure attribute keyword list |
326 | else if (wlAttributes.InList(cStatement)) { |
327 | // Change the statement string to the procedure attribute state |
328 | scDoc.ChangeState(SCE_CLW_ATTRIBUTE); |
329 | } |
330 | // Else if statement string is in the standard equate keyword list |
331 | else if (wlStandardEquates.InList(cStatement)) { |
332 | // Change the statement string to the standard equate state |
333 | scDoc.ChangeState(SCE_CLW_STANDARD_EQUATE); |
334 | } |
335 | // Else if statement string is in the deprecated or legacy keyword list |
336 | else if (wlLegacyStatements.InList(cStatement)) { |
337 | // Change the statement string to the standard equate state |
338 | scDoc.ChangeState(SCE_CLW_DEPRECATED); |
339 | } |
340 | // Else the statement string doesn't match any work list |
341 | else { |
342 | // Change the statement string to the default state |
343 | scDoc.ChangeState(SCE_CLW_DEFAULT); |
344 | } |
345 | // Terminate the keyword state and set to default state |
346 | scDoc.SetState(SCE_CLW_DEFAULT); |
347 | } |
348 | } |
349 | // String State Handling |
350 | else if (scDoc.state == SCE_CLW_STRING) { |
351 | // If the character is an ' (single quote) |
352 | if (scDoc.ch == '\'') { |
353 | // Set the state to default and move forward colouring |
354 | // the ' (single quote) as default state |
355 | // terminating the string state |
356 | scDoc.SetState(SCE_CLW_DEFAULT); |
357 | scDoc.Forward(); |
358 | } |
359 | // If the next character is an ' (single quote) |
360 | if (scDoc.chNext == '\'') { |
361 | // Move forward one character and set to default state |
362 | // colouring the next ' (single quote) as default state |
363 | // terminating the string state |
364 | scDoc.ForwardSetState(SCE_CLW_DEFAULT); |
365 | scDoc.Forward(); |
366 | } |
367 | } |
368 | // Picture String State Handling |
369 | else if (scDoc.state == SCE_CLW_PICTURE_STRING) { |
370 | // If the character is an ( (open parenthese) |
371 | if (scDoc.ch == '(') { |
372 | // Increment the parenthese level |
373 | iParenthesesLevel++; |
374 | } |
375 | // Else if the character is a ) (close parenthese) |
376 | else if (scDoc.ch == ')') { |
377 | // If the parenthese level is set to zero |
378 | // parentheses matched |
379 | if (!iParenthesesLevel) { |
380 | scDoc.SetState(SCE_CLW_DEFAULT); |
381 | } |
382 | // Else parenthese level is greater than zero |
383 | // still looking for matching parentheses |
384 | else { |
385 | // Decrement the parenthese level |
386 | iParenthesesLevel--; |
387 | } |
388 | } |
389 | } |
390 | // Standard Equate State Handling |
391 | else if (scDoc.state == SCE_CLW_STANDARD_EQUATE) { |
392 | if (!isalnum(scDoc.ch)) { |
393 | scDoc.SetState(SCE_CLW_DEFAULT); |
394 | } |
395 | } |
396 | // Integer Constant State Handling |
397 | else if (scDoc.state == SCE_CLW_INTEGER_CONSTANT) { |
398 | // If the character is not a digit (0-9) |
399 | // or character is not a hexidecimal character (A-F) |
400 | // or character is not a . (point) |
401 | // or character is not a numberic base character (B,O,H) |
402 | if (!(isdigit(scDoc.ch) |
403 | || IsAHexCharacter(scDoc.ch, bCaseSensitive) |
404 | || scDoc.ch == '.' |
405 | || IsANumericBaseCharacter(scDoc.ch, bCaseSensitive))) { |
406 | // If the number was a real |
407 | if (SetNumericConstantState(scDoc)) { |
408 | // Colour the matched string to the real constant state |
409 | scDoc.ChangeState(SCE_CLW_REAL_CONSTANT); |
410 | } |
411 | // Else the number was an integer |
412 | else { |
413 | // Colour the matched string to an integer constant state |
414 | scDoc.ChangeState(SCE_CLW_INTEGER_CONSTANT); |
415 | } |
416 | // Terminate the integer constant state and set to default state |
417 | scDoc.SetState(SCE_CLW_DEFAULT); |
418 | } |
419 | } |
420 | |
421 | // |
422 | // Determine if a new state should be entered. |
423 | // |
424 | |
425 | // Beginning of Line Handling |
426 | if (scDoc.atLineStart) { |
427 | // Reset the column 1 label flag |
428 | iColumn1Label = false; |
429 | // If column 1 character is a label start character |
430 | if (IsALabelStart(scDoc.ch)) { |
431 | // Label character is found in column 1 |
432 | // so set column 1 label flag and clear last column 1 label |
433 | iColumn1Label = true; |
434 | // Set the state to label |
435 | scDoc.SetState(SCE_CLW_LABEL); |
436 | } |
437 | // else if character is a space or tab |
438 | else if (IsASpace(scDoc.ch)){ |
439 | // Set to default state |
440 | scDoc.SetState(SCE_CLW_DEFAULT); |
441 | } |
442 | // else if comment start (!) or is an * (asterisk) |
443 | else if (IsACommentStart(scDoc.ch) || scDoc.ch == '*' ) { |
444 | // then set the state to comment. |
445 | scDoc.SetState(SCE_CLW_COMMENT); |
446 | } |
447 | // else the character is a ? (question mark) |
448 | else if (scDoc.ch == '?') { |
449 | // Change to the compiler directive state, move forward, |
450 | // colouring the ? (question mark), change back to default state. |
451 | scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE); |
452 | scDoc.Forward(); |
453 | scDoc.SetState(SCE_CLW_DEFAULT); |
454 | } |
455 | // else an invalid character in column 1 |
456 | else { |
457 | // Set to error state |
458 | scDoc.SetState(SCE_CLW_ERROR); |
459 | } |
460 | } |
461 | // End of Line Handling |
462 | else if (scDoc.atLineEnd) { |
463 | // Reset to the default state at the end of each line. |
464 | scDoc.SetState(SCE_CLW_DEFAULT); |
465 | } |
466 | // Default Handling |
467 | else { |
468 | // If in default state |
469 | if (scDoc.state == SCE_CLW_DEFAULT) { |
470 | // If is a letter could be a possible statement |
471 | if (isalpha(scDoc.ch)) { |
472 | // Set the state to Clarion Keyword and verify later |
473 | scDoc.SetState(SCE_CLW_KEYWORD); |
474 | } |
475 | // else is a number |
476 | else if (isdigit(scDoc.ch)) { |
477 | // Set the state to Integer Constant and verify later |
478 | scDoc.SetState(SCE_CLW_INTEGER_CONSTANT); |
479 | } |
480 | // else if the start of a comment or a | (line continuation) |
481 | else if (IsACommentStart(scDoc.ch) || scDoc.ch == '|') { |
482 | // then set the state to comment. |
483 | scDoc.SetState(SCE_CLW_COMMENT); |
484 | } |
485 | // else if the character is a ' (single quote) |
486 | else if (scDoc.ch == '\'') { |
487 | // If the character is also a ' (single quote) |
488 | // Embedded Apostrophe |
489 | if (scDoc.chNext == '\'') { |
490 | // Move forward colouring it as default state |
491 | scDoc.ForwardSetState(SCE_CLW_DEFAULT); |
492 | } |
493 | else { |
494 | // move to the next character and then set the state to comment. |
495 | scDoc.ForwardSetState(SCE_CLW_STRING); |
496 | } |
497 | } |
498 | // else the character is an @ (ampersand) |
499 | else if (scDoc.ch == '@') { |
500 | // Case insensitive. |
501 | if (!bCaseSensitive) { |
502 | // If character is a valid picture token character |
503 | if (strchr("DEKNPSTdeknpst" , scDoc.chNext) != NULL) { |
504 | // Set to the picture string state |
505 | scDoc.SetState(SCE_CLW_PICTURE_STRING); |
506 | } |
507 | } |
508 | // Case sensitive |
509 | else { |
510 | // If character is a valid picture token character |
511 | if (strchr("DEKNPST" , scDoc.chNext) != NULL) { |
512 | // Set the picture string state |
513 | scDoc.SetState(SCE_CLW_PICTURE_STRING); |
514 | } |
515 | } |
516 | } |
517 | } |
518 | } |
519 | } |
520 | // lexing complete |
521 | scDoc.Complete(); |
522 | } |
523 | |
524 | // Clarion Language Case Sensitive Colouring Procedure |
525 | static void ColouriseClarionDocSensitive(Sci_PositionU uiStartPos, Sci_Position iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler) { |
526 | |
527 | ColouriseClarionDoc(uiStartPos, iLength, iInitStyle, wlKeywords, accStyler, true); |
528 | } |
529 | |
530 | // Clarion Language Case Insensitive Colouring Procedure |
531 | static void ColouriseClarionDocInsensitive(Sci_PositionU uiStartPos, Sci_Position iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler) { |
532 | |
533 | ColouriseClarionDoc(uiStartPos, iLength, iInitStyle, wlKeywords, accStyler, false); |
534 | } |
535 | |
536 | // Fill Buffer |
537 | |
538 | static void FillBuffer(Sci_PositionU uiStart, Sci_PositionU uiEnd, Accessor &accStyler, char *szBuffer, Sci_PositionU uiLength) { |
539 | |
540 | Sci_PositionU uiPos = 0; |
541 | |
542 | while ((uiPos < uiEnd - uiStart + 1) && (uiPos < uiLength-1)) { |
543 | szBuffer[uiPos] = static_cast<char>(toupper(accStyler[uiStart + uiPos])); |
544 | uiPos++; |
545 | } |
546 | szBuffer[uiPos] = '\0'; |
547 | } |
548 | |
549 | // Classify Clarion Fold Point |
550 | |
551 | static int ClassifyClarionFoldPoint(int iLevel, const char* szString) { |
552 | |
553 | if (!(isdigit(szString[0]) || (szString[0] == '.'))) { |
554 | if (strcmp(szString, "PROCEDURE" ) == 0) { |
555 | // iLevel = SC_FOLDLEVELBASE + 1; |
556 | } |
557 | else if (strcmp(szString, "MAP" ) == 0 || |
558 | strcmp(szString,"ACCEPT" ) == 0 || |
559 | strcmp(szString,"BEGIN" ) == 0 || |
560 | strcmp(szString,"CASE" ) == 0 || |
561 | strcmp(szString,"EXECUTE" ) == 0 || |
562 | strcmp(szString,"IF" ) == 0 || |
563 | strcmp(szString,"ITEMIZE" ) == 0 || |
564 | strcmp(szString,"INTERFACE" ) == 0 || |
565 | strcmp(szString,"JOIN" ) == 0 || |
566 | strcmp(szString,"LOOP" ) == 0 || |
567 | strcmp(szString,"MODULE" ) == 0 || |
568 | strcmp(szString,"RECORD" ) == 0) { |
569 | iLevel++; |
570 | } |
571 | else if (strcmp(szString, "APPLICATION" ) == 0 || |
572 | strcmp(szString, "CLASS" ) == 0 || |
573 | strcmp(szString, "DETAIL" ) == 0 || |
574 | strcmp(szString, "FILE" ) == 0 || |
575 | strcmp(szString, "FOOTER" ) == 0 || |
576 | strcmp(szString, "FORM" ) == 0 || |
577 | strcmp(szString, "GROUP" ) == 0 || |
578 | strcmp(szString, "HEADER" ) == 0 || |
579 | strcmp(szString, "INTERFACE" ) == 0 || |
580 | strcmp(szString, "MENU" ) == 0 || |
581 | strcmp(szString, "MENUBAR" ) == 0 || |
582 | strcmp(szString, "OLE" ) == 0 || |
583 | strcmp(szString, "OPTION" ) == 0 || |
584 | strcmp(szString, "QUEUE" ) == 0 || |
585 | strcmp(szString, "REPORT" ) == 0 || |
586 | strcmp(szString, "SHEET" ) == 0 || |
587 | strcmp(szString, "TAB" ) == 0 || |
588 | strcmp(szString, "TOOLBAR" ) == 0 || |
589 | strcmp(szString, "VIEW" ) == 0 || |
590 | strcmp(szString, "WINDOW" ) == 0) { |
591 | iLevel++; |
592 | } |
593 | else if (strcmp(szString, "END" ) == 0 || |
594 | strcmp(szString, "UNTIL" ) == 0 || |
595 | strcmp(szString, "WHILE" ) == 0) { |
596 | iLevel--; |
597 | } |
598 | } |
599 | return(iLevel); |
600 | } |
601 | |
602 | // Clarion Language Folding Procedure |
603 | static void FoldClarionDoc(Sci_PositionU uiStartPos, Sci_Position iLength, int iInitStyle, WordList *[], Accessor &accStyler) { |
604 | |
605 | Sci_PositionU uiEndPos = uiStartPos + iLength; |
606 | Sci_Position iLineCurrent = accStyler.GetLine(uiStartPos); |
607 | int iLevelPrev = accStyler.LevelAt(iLineCurrent) & SC_FOLDLEVELNUMBERMASK; |
608 | int iLevelCurrent = iLevelPrev; |
609 | char chNext = accStyler[uiStartPos]; |
610 | int iStyle = iInitStyle; |
611 | int iStyleNext = accStyler.StyleAt(uiStartPos); |
612 | int iVisibleChars = 0; |
613 | Sci_Position iLastStart = 0; |
614 | |
615 | for (Sci_PositionU uiPos = uiStartPos; uiPos < uiEndPos; uiPos++) { |
616 | |
617 | char chChar = chNext; |
618 | chNext = accStyler.SafeGetCharAt(uiPos + 1); |
619 | int iStylePrev = iStyle; |
620 | iStyle = iStyleNext; |
621 | iStyleNext = accStyler.StyleAt(uiPos + 1); |
622 | bool bEOL = (chChar == '\r' && chNext != '\n') || (chChar == '\n'); |
623 | |
624 | if (iStylePrev == SCE_CLW_DEFAULT) { |
625 | if (iStyle == SCE_CLW_KEYWORD || iStyle == SCE_CLW_STRUCTURE_DATA_TYPE) { |
626 | // Store last word start point. |
627 | iLastStart = uiPos; |
628 | } |
629 | } |
630 | |
631 | if (iStylePrev == SCE_CLW_KEYWORD || iStylePrev == SCE_CLW_STRUCTURE_DATA_TYPE) { |
632 | if(iswordchar(chChar) && !iswordchar(chNext)) { |
633 | char chBuffer[100]; |
634 | FillBuffer(iLastStart, uiPos, accStyler, chBuffer, sizeof(chBuffer)); |
635 | iLevelCurrent = ClassifyClarionFoldPoint(iLevelCurrent,chBuffer); |
636 | // if ((iLevelCurrent == SC_FOLDLEVELBASE + 1) && iLineCurrent > 1) { |
637 | // accStyler.SetLevel(iLineCurrent-1,SC_FOLDLEVELBASE); |
638 | // iLevelPrev = SC_FOLDLEVELBASE; |
639 | // } |
640 | } |
641 | } |
642 | |
643 | if (bEOL) { |
644 | int iLevel = iLevelPrev; |
645 | if ((iLevelCurrent > iLevelPrev) && (iVisibleChars > 0)) |
646 | iLevel |= SC_FOLDLEVELHEADERFLAG; |
647 | if (iLevel != accStyler.LevelAt(iLineCurrent)) { |
648 | accStyler.SetLevel(iLineCurrent,iLevel); |
649 | } |
650 | iLineCurrent++; |
651 | iLevelPrev = iLevelCurrent; |
652 | iVisibleChars = 0; |
653 | } |
654 | |
655 | if (!isspacechar(chChar)) |
656 | iVisibleChars++; |
657 | } |
658 | |
659 | // Fill in the real level of the next line, keeping the current flags |
660 | // as they will be filled in later. |
661 | int iFlagsNext = accStyler.LevelAt(iLineCurrent) & ~SC_FOLDLEVELNUMBERMASK; |
662 | accStyler.SetLevel(iLineCurrent, iLevelPrev | iFlagsNext); |
663 | } |
664 | |
665 | // Word List Descriptions |
666 | static const char * const rgWordListDescriptions[] = { |
667 | "Clarion Keywords" , |
668 | "Compiler Directives" , |
669 | "Built-in Procedures and Functions" , |
670 | "Runtime Expressions" , |
671 | "Structure and Data Types" , |
672 | "Attributes" , |
673 | "Standard Equates" , |
674 | "Reserved Words (Labels)" , |
675 | "Reserved Words (Procedure Labels)" , |
676 | 0, |
677 | }; |
678 | |
679 | // Case Sensitive Clarion Language Lexer |
680 | LexerModule lmClw(SCLEX_CLW, ColouriseClarionDocSensitive, "clarion" , FoldClarionDoc, rgWordListDescriptions); |
681 | |
682 | // Case Insensitive Clarion Language Lexer |
683 | LexerModule lmClwNoCase(SCLEX_CLWNOCASE, ColouriseClarionDocInsensitive, "clarionnocase" , FoldClarionDoc, rgWordListDescriptions); |
684 | |