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