summaryrefslogtreecommitdiffstats
path: root/src/LexCLW.cpp
blob: e28e4b13b48a259978240410066f416850a25a47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
// Scintilla source code edit control
/** @file LexClw.cxx
 ** Lexer for Clarion.
 ** 2004/12/17 Updated Lexer
 **/
// Copyright 2003-2004 by Ron Schofield <ron@schofieldcomputer.com>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

// Is an end of line character
inline bool IsEOL(const int ch) {

	return(ch == '\n');
}

// Convert character to uppercase
static char CharacterUpper(char chChar) {

	if (chChar < 'a' || chChar > 'z') {
		return(chChar);
	}
	else {
		return(static_cast<char>(chChar - 'a' + 'A'));
	}
}

// Convert string to uppercase
static void StringUpper(char *szString) {

	while (*szString) {
		*szString = CharacterUpper(*szString);
		szString++;
	}
}

// Is a label start character
inline bool IsALabelStart(const int iChar) {

	return(isalpha(iChar) || iChar == '_');
}

// Is a label character
inline bool IsALabelCharacter(const int iChar) {

	return(isalnum(iChar) || iChar == '_' || iChar == ':'); 
}

// Is the character is a ! and the the next character is not a ! 
inline bool IsACommentStart(const int iChar) {

	return(iChar == '!');
}

// Is the character a Clarion hex character (ABCDEF)
inline bool IsAHexCharacter(const int iChar, bool bCaseSensitive) {

	// Case insensitive.
	if (!bCaseSensitive) {
		if (strchr("ABCDEFabcdef", iChar) != NULL) {
			return(true);
		}
	}
	// Case sensitive
	else {
		if (strchr("ABCDEF", iChar) != NULL) {
			return(true);
		}
	}
	return(false);
}

// Is the character a Clarion base character (B=Binary, O=Octal, H=Hex)
inline bool IsANumericBaseCharacter(const int iChar, bool bCaseSensitive) {

	// Case insensitive.
	if (!bCaseSensitive) {
		// If character is a numeric base character
		if (strchr("BOHboh", iChar) != NULL) {
			return(true);
		}
	}
	// Case sensitive
	else {
		// If character is a numeric base character
		if (strchr("BOH", iChar) != NULL) {
			return(true);
		}
	}
	return(false);
}

// Set the correct numeric constant state
inline bool SetNumericConstantState(StyleContext &scDoc) {

	int iPoints = 0;			// Point counter
	char cNumericString[512];	// Numeric string buffer

	// Buffer the current numberic string
	scDoc.GetCurrent(cNumericString, sizeof(cNumericString));
	// Loop through the string until end of string (NULL termination)
	for (int iIndex = 0; cNumericString[iIndex] != '\0'; iIndex++) {
		// Depending on the character
		switch (cNumericString[iIndex]) {
			// Is a . (point)
			case '.' :
				// Increment point counter
				iPoints++;
				break;
			default :
				break;
		}	
	}
	// If points found (can be more than one for improper formatted number
	if (iPoints > 0) {
		return(true);
	}
	// Else no points found
	else {
		return(false);
	}
}

// Get the next word in uppercase from the current position (keyword lookahead)
inline bool GetNextWordUpper(Accessor &styler, unsigned int uiStartPos, int iLength, char *cWord) {

	unsigned int iIndex = 0;		// Buffer Index

	// Loop through the remaining string from the current position
	for (int iOffset = uiStartPos; iOffset < iLength; iOffset++) {
		// Get the character from the buffer using the offset
		char cCharacter = styler[iOffset];
		if (IsEOL(cCharacter)) {
			break;
		}
		// If the character is alphabet character
		if (isalpha(cCharacter)) {
			// Add UPPERCASE character to the word buffer
			cWord[iIndex++] = CharacterUpper(cCharacter);
		}
	}
	// Add null termination
	cWord[iIndex] = '\0';
	// If no word was found
	if (iIndex == 0) {
		// Return failure
		return(false);
	}
	// Else word was found
	else {
		// Return success
		return(true);
	}
}

// Clarion Language Colouring Procedure
static void ColouriseClarionDoc(unsigned int uiStartPos, int iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler, bool bCaseSensitive) {

	int iParenthesesLevel = 0;		// Parenthese Level
	int iColumn1Label = false;		// Label starts in Column 1

	WordList &wlClarionKeywords = *wlKeywords[0];			// Clarion Keywords
	WordList &wlCompilerDirectives = *wlKeywords[1];		// Compiler Directives
	WordList &wlRuntimeExpressions = *wlKeywords[2];		// Runtime Expressions
	WordList &wlBuiltInProcsFuncs = *wlKeywords[3];			// Builtin Procedures and Functions
	WordList &wlStructsDataTypes = *wlKeywords[4];			// Structures and Data Types
	WordList &wlAttributes = *wlKeywords[5];				// Procedure Attributes
	WordList &wlStandardEquates = *wlKeywords[6];			// Standard Equates
	WordList &wlLabelReservedWords = *wlKeywords[7];		// Clarion Reserved Keywords (Labels)
	WordList &wlProcLabelReservedWords = *wlKeywords[8];	// Clarion Reserved Keywords (Procedure Labels)

	const char wlProcReservedKeywordList[] = 
	"PROCEDURE FUNCTION";
	WordList wlProcReservedKeywords;
	wlProcReservedKeywords.Set(wlProcReservedKeywordList);

	const char wlCompilerKeywordList[] = 
	"COMPILE OMIT";
	WordList wlCompilerKeywords;
	wlCompilerKeywords.Set(wlCompilerKeywordList);

	const char wlLegacyStatementsList[] =
	"BOF EOF FUNCTION POINTER SHARE";
	WordList wlLegacyStatements;
	wlLegacyStatements.Set(wlLegacyStatementsList);

	StyleContext scDoc(uiStartPos, iLength, iInitStyle, accStyler);

	// lex source code
    for (; scDoc.More(); scDoc.Forward())
	{
		//
		// Determine if the current state should terminate.
		//

		// Label State Handling
		if (scDoc.state == SCE_CLW_LABEL) {
			// If the character is not a valid label
			if (!IsALabelCharacter(scDoc.ch)) {
				// If the character is a . (dot syntax)
				if (scDoc.ch == '.') {
					// Turn off column 1 label flag as label now cannot be reserved work
					iColumn1Label = false;
					// Uncolour the . (dot) to default state, move forward one character,
					// and change back to the label state.
					scDoc.SetState(SCE_CLW_DEFAULT);
					scDoc.Forward();
					scDoc.SetState(SCE_CLW_LABEL);
				}
				// Else check label
				else {
					char cLabel[512];		// Label buffer
					// Buffer the current label string
					scDoc.GetCurrent(cLabel,sizeof(cLabel));
					// If case insensitive, convert string to UPPERCASE to match passed keywords.
					if (!bCaseSensitive) {
						StringUpper(cLabel);
					}
					// Else if UPPERCASE label string is in the Clarion compiler keyword list
					if (wlCompilerKeywords.InList(cLabel) && iColumn1Label){
						// change the label to error state
						scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE);
					}
					// Else if UPPERCASE label string is in the Clarion reserved keyword list
					else if (wlLabelReservedWords.InList(cLabel) && iColumn1Label){
						// change the label to error state
						scDoc.ChangeState(SCE_CLW_ERROR);
					}
					// Else if UPPERCASE label string is 
					else if (wlProcLabelReservedWords.InList(cLabel) && iColumn1Label) {
						char cWord[512];	// Word buffer
						// Get the next word from the current position
						if (GetNextWordUpper(accStyler,scDoc.currentPos,uiStartPos+iLength,cWord)) {
							// If the next word is a procedure reserved word
							if (wlProcReservedKeywords.InList(cWord)) {
								// Change the label to error state
								scDoc.ChangeState(SCE_CLW_ERROR);
							}
						}
					}
					// Else if label string is in the compiler directive keyword list
					else if (wlCompilerDirectives.InList(cLabel)) {
						// change the state to compiler directive state
						scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE);
					}
					// Terminate the label state and set to default state
					scDoc.SetState(SCE_CLW_DEFAULT);
				}
			}
		}
		// Keyword State Handling
		else if (scDoc.state == SCE_CLW_KEYWORD) {
			// If character is : (colon)
			if (scDoc.ch == ':') {
				char cEquate[512];		// Equate buffer
				// Move forward to include : (colon) in buffer
				scDoc.Forward();
				// Buffer the equate string
				scDoc.GetCurrent(cEquate,sizeof(cEquate));
				// If case insensitive, convert string to UPPERCASE to match passed keywords.
				if (!bCaseSensitive) {
					StringUpper(cEquate);
				}
				// If statement string is in the equate list
				if (wlStandardEquates.InList(cEquate)) {
					// Change to equate state
					scDoc.ChangeState(SCE_CLW_STANDARD_EQUATE);
				}
			}
			// If the character is not a valid label character
			else if (!IsALabelCharacter(scDoc.ch)) {
				char cStatement[512];		// Statement buffer
				// Buffer the statement string
				scDoc.GetCurrent(cStatement,sizeof(cStatement));
				// If case insensitive, convert string to UPPERCASE to match passed keywords.
				if (!bCaseSensitive) {
					StringUpper(cStatement);
				}
				// If statement string is in the Clarion keyword list
				if (wlClarionKeywords.InList(cStatement)) {
					// Change the statement string to the Clarion keyword state
					scDoc.ChangeState(SCE_CLW_KEYWORD);
				}
				// Else if statement string is in the compiler directive keyword list
				else if (wlCompilerDirectives.InList(cStatement)) {
					// Change the statement string to the compiler directive state
					scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE);
				}
				// Else if statement string is in the runtime expressions keyword list
				else if (wlRuntimeExpressions.InList(cStatement)) {
					// Change the statement string to the runtime expressions state
					scDoc.ChangeState(SCE_CLW_RUNTIME_EXPRESSIONS);
				}
				// Else if statement string is in the builtin procedures and functions keyword list
				else if (wlBuiltInProcsFuncs.InList(cStatement)) {
					// Change the statement string to the builtin procedures and functions state
					scDoc.ChangeState(SCE_CLW_BUILTIN_PROCEDURES_FUNCTION);
				}
				// Else if statement string is in the tructures and data types keyword list
				else if (wlStructsDataTypes.InList(cStatement)) {
					// Change the statement string to the structures and data types state
					scDoc.ChangeState(SCE_CLW_STRUCTURE_DATA_TYPE);
				}
				// Else if statement string is in the procedure attribute keyword list
				else if (wlAttributes.InList(cStatement)) {
					// Change the statement string to the procedure attribute state
					scDoc.ChangeState(SCE_CLW_ATTRIBUTE);
				}
				// Else if statement string is in the standard equate keyword list
				else if (wlStandardEquates.InList(cStatement)) {
					// Change the statement string to the standard equate state
					scDoc.ChangeState(SCE_CLW_STANDARD_EQUATE);
				}
				// Else if statement string is in the deprecated or legacy keyword list
				else if (wlLegacyStatements.InList(cStatement)) {
					// Change the statement string to the standard equate state
					scDoc.ChangeState(SCE_CLW_DEPRECATED);
				}
				// Else the statement string doesn't match any work list
				else {
					// Change the statement string to the default state
					scDoc.ChangeState(SCE_CLW_DEFAULT);
				}
				// Terminate the keyword state and set to default state
				scDoc.SetState(SCE_CLW_DEFAULT);
			}
		}
		// String State Handling
		else if (scDoc.state == SCE_CLW_STRING) {
			// If the character is an ' (single quote)
			if (scDoc.ch == '\'') {
				// Set the state to default and move forward colouring
				// the ' (single quote) as default state
				// terminating the string state
				scDoc.SetState(SCE_CLW_DEFAULT);
				scDoc.Forward();
			}
			// If the next character is an ' (single quote)
			if (scDoc.chNext == '\'') {
				// Move forward one character and set to default state
				// colouring the next ' (single quote) as default state
				// terminating the string state
				scDoc.ForwardSetState(SCE_CLW_DEFAULT);
				scDoc.Forward();
			}
		}
		// Picture String State Handling
		else if (scDoc.state == SCE_CLW_PICTURE_STRING) {
			// If the character is an ( (open parenthese)
			if (scDoc.ch == '(') {
				// Increment the parenthese level
				iParenthesesLevel++;
			}
			// Else if the character is a ) (close parenthese) 
			else if (scDoc.ch == ')') {
				// If the parenthese level is set to zero
				// parentheses matched
				if (!iParenthesesLevel) {
					scDoc.SetState(SCE_CLW_DEFAULT);
				} 
				// Else parenthese level is greater than zero
				// still looking for matching parentheses
				else {
					// Decrement the parenthese level
					iParenthesesLevel--;
				}
			}
		}
		// Standard Equate State Handling
		else if (scDoc.state == SCE_CLW_STANDARD_EQUATE) {
			if (!isalnum(scDoc.ch)) {
				scDoc.SetState(SCE_CLW_DEFAULT);
			}
		}
		// Integer Constant State Handling
		else if (scDoc.state == SCE_CLW_INTEGER_CONSTANT) {
			// If the character is not a digit (0-9)
			// or character is not a hexidecimal character (A-F)
			// or character is not a . (point)
			// or character is not a numberic base character (B,O,H)
			if (!(isdigit(scDoc.ch)
			|| IsAHexCharacter(scDoc.ch, bCaseSensitive)
			|| scDoc.ch == '.'
			|| IsANumericBaseCharacter(scDoc.ch, bCaseSensitive))) {
				// If the number was a real 
				if (SetNumericConstantState(scDoc)) {
					// Colour the matched string to the real constant state
					scDoc.ChangeState(SCE_CLW_REAL_CONSTANT);
				}
				// Else the number was an integer
				else {
					// Colour the matched string to an integer constant state
					scDoc.ChangeState(SCE_CLW_INTEGER_CONSTANT);
				}
				// Terminate the integer constant state and set to default state
				scDoc.SetState(SCE_CLW_DEFAULT);
			}
		}

		//
		// Determine if a new state should be entered.
		//

		// Beginning of Line Handling
		if (scDoc.atLineStart) {
			// Reset the column 1 label flag
			iColumn1Label = false;
			// If column 1 character is a label start character
			if (IsALabelStart(scDoc.ch)) {
				// Label character is found in column 1
				// so set column 1 label flag and clear last column 1 label
				iColumn1Label = true;
				// Set the state to label
				scDoc.SetState(SCE_CLW_LABEL);
			}
			// else if character is a space or tab
			else if (IsASpace(scDoc.ch)){
				// Set to default state
				scDoc.SetState(SCE_CLW_DEFAULT);
			}
			// else if comment start (!) or is an * (asterisk)
			else if (IsACommentStart(scDoc.ch) || scDoc.ch == '*' ) {
				// then set the state to comment.
				scDoc.SetState(SCE_CLW_COMMENT);
			}
			// else the character is a ? (question mark)
			else if (scDoc.ch == '?') {
				// Change to the compiler directive state, move forward,
				// colouring the ? (question mark), change back to default state.
				scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE);
				scDoc.Forward();
				scDoc.SetState(SCE_CLW_DEFAULT);
			}
			// else an invalid character in column 1
			else {
				// Set to error state
				scDoc.SetState(SCE_CLW_ERROR);
			}
		}
		// End of Line Handling
		else if (scDoc.atLineEnd) {
			// Reset to the default state at the end of each line.
			scDoc.SetState(SCE_CLW_DEFAULT);
		}
		// Default Handling
		else {
			// If in default state 
			if (scDoc.state == SCE_CLW_DEFAULT) {
				// If is a letter could be a possible statement
				if (isalpha(scDoc.ch)) {
					// Set the state to Clarion Keyword and verify later
					scDoc.SetState(SCE_CLW_KEYWORD);
				}
				// else is a number
				else if (isdigit(scDoc.ch)) {
					// Set the state to Integer Constant and verify later
					scDoc.SetState(SCE_CLW_INTEGER_CONSTANT);
				}
				// else if the start of a comment or a | (line continuation)
				else if (IsACommentStart(scDoc.ch) || scDoc.ch == '|') {
					// then set the state to comment.
					scDoc.SetState(SCE_CLW_COMMENT);
				}		
				// else if the character is a ' (single quote)
				else if (scDoc.ch == '\'') {
					// If the character is also a ' (single quote) 
					// Embedded Apostrophe
					if (scDoc.chNext == '\'') {
						// Move forward colouring it as default state
						scDoc.ForwardSetState(SCE_CLW_DEFAULT);
					}
					else {
						// move to the next character and then set the state to comment.
						scDoc.ForwardSetState(SCE_CLW_STRING);
					}
				}		
				// else the character is an @ (ampersand)
				else if (scDoc.ch == '@') {
					// Case insensitive.
					if (!bCaseSensitive) {
						// If character is a valid picture token character
						if (strchr("DEKNPSTdeknpst", scDoc.chNext) != NULL) {
							// Set to the picture string state
							scDoc.SetState(SCE_CLW_PICTURE_STRING);
						}
					}
					// Case sensitive
					else {
						// If character is a valid picture token character
						if (strchr("DEKNPST", scDoc.chNext) != NULL) {
							// Set the picture string state
							scDoc.SetState(SCE_CLW_PICTURE_STRING);
						}
					}
				}		
			}
		}
	}
	// lexing complete
	scDoc.Complete();
}

// Clarion Language Case Sensitive Colouring Procedure
static void ColouriseClarionDocSensitive(unsigned int uiStartPos, int iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler) {

	ColouriseClarionDoc(uiStartPos, iLength, iInitStyle, wlKeywords, accStyler, true);
}

// Clarion Language Case Insensitive Colouring Procedure
static void ColouriseClarionDocInsensitive(unsigned int uiStartPos, int iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler) {

	ColouriseClarionDoc(uiStartPos, iLength, iInitStyle, wlKeywords, accStyler, false);
}

// Fill Buffer

static void FillBuffer(unsigned int uiStart, unsigned int uiEnd, Accessor &accStyler, char *szBuffer, unsigned int uiLength) {

	unsigned int uiPos = 0;

	while ((uiPos < uiEnd - uiStart + 1) && (uiPos < uiLength-1)) {
		szBuffer[uiPos] = static_cast<char>(toupper(accStyler[uiStart + uiPos]));
		uiPos++;
	}
	szBuffer[uiPos] = '\0';
}

// Classify Clarion Fold Point

static int ClassifyClarionFoldPoint(int iLevel, const char* szString) {

	if (!(isdigit(szString[0]) || (szString[0] == '.'))) {
		if (strcmp(szString, "PROCEDURE") == 0) {
	//		iLevel = SC_FOLDLEVELBASE + 1;
		}
		else if (strcmp(szString, "MAP") == 0 ||
			strcmp(szString,"ACCEPT") == 0 ||
			strcmp(szString,"BEGIN") == 0 ||
			strcmp(szString,"CASE") == 0 ||
			strcmp(szString,"EXECUTE") == 0 ||
			strcmp(szString,"IF") == 0 ||
			strcmp(szString,"ITEMIZE") == 0 ||
			strcmp(szString,"INTERFACE") == 0 ||
			strcmp(szString,"JOIN") == 0 ||
			strcmp(szString,"LOOP") == 0 ||
			strcmp(szString,"MODULE") == 0 ||
			strcmp(szString,"RECORD") == 0) {
			iLevel++;
		}
		else if (strcmp(szString, "APPLICATION") == 0 ||
			strcmp(szString, "CLASS") == 0 ||
			strcmp(szString, "DETAIL") == 0 ||
			strcmp(szString, "FILE") == 0 ||
			strcmp(szString, "FOOTER") == 0 ||
			strcmp(szString, "FORM") == 0 ||
			strcmp(szString, "GROUP") == 0 ||
			strcmp(szString, "HEADER") == 0 ||
			strcmp(szString, "INTERFACE") == 0 ||
			strcmp(szString, "MENU") == 0 ||
			strcmp(szString, "MENUBAR") == 0 ||
			strcmp(szString, "OLE") == 0 ||
			strcmp(szString, "OPTION") == 0 ||
			strcmp(szString, "QUEUE") == 0 ||
			strcmp(szString, "REPORT") == 0 ||
			strcmp(szString, "SHEET") == 0 ||
			strcmp(szString, "TAB") == 0 ||
			strcmp(szString, "TOOLBAR") == 0 ||
			strcmp(szString, "VIEW") == 0 ||
			strcmp(szString, "WINDOW") == 0) {
			iLevel++;
		}
		else if (strcmp(szString, "END") == 0 ||
			strcmp(szString, "UNTIL") == 0 ||
			strcmp(szString, "WHILE") == 0) {
			iLevel--;
		}
	}
	return(iLevel);
}

// Clarion Language Folding Procedure
static void FoldClarionDoc(unsigned int uiStartPos, int iLength, int iInitStyle, WordList *[], Accessor &accStyler) {

	unsigned int uiEndPos = uiStartPos + iLength;
	int iLineCurrent = accStyler.GetLine(uiStartPos);
	int iLevelPrev = accStyler.LevelAt(iLineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int iLevelCurrent = iLevelPrev;
	char chNext = accStyler[uiStartPos];
	int iStyle = iInitStyle;
	int iStyleNext = accStyler.StyleAt(uiStartPos);
	int iVisibleChars = 0;
	int iLastStart = 0;

	for (unsigned int uiPos = uiStartPos; uiPos < uiEndPos; uiPos++) {

		char chChar = chNext;
		chNext = accStyler.SafeGetCharAt(uiPos + 1);
		int iStylePrev = iStyle;
		iStyle = iStyleNext;
		iStyleNext = accStyler.StyleAt(uiPos + 1);
		bool bEOL = (chChar == '\r' && chNext != '\n') || (chChar == '\n');
	
		if (iStylePrev == SCE_CLW_DEFAULT) {
			if (iStyle == SCE_CLW_KEYWORD || iStyle == SCE_CLW_STRUCTURE_DATA_TYPE) {
				// Store last word start point.
				iLastStart = uiPos;
			}
		}

		if (iStylePrev == SCE_CLW_KEYWORD || iStylePrev == SCE_CLW_STRUCTURE_DATA_TYPE) {
			if(iswordchar(chChar) && !iswordchar(chNext)) {
				char chBuffer[100];
				FillBuffer(iLastStart, uiPos, accStyler, chBuffer, sizeof(chBuffer));
				iLevelCurrent = ClassifyClarionFoldPoint(iLevelCurrent,chBuffer);
			//	if ((iLevelCurrent == SC_FOLDLEVELBASE + 1) && iLineCurrent > 1) {
			//		accStyler.SetLevel(iLineCurrent-1,SC_FOLDLEVELBASE);
			//		iLevelPrev = SC_FOLDLEVELBASE;
			//	}
			}
		}

		if (bEOL) {
			int iLevel = iLevelPrev;
			if ((iLevelCurrent > iLevelPrev) && (iVisibleChars > 0))
				iLevel |= SC_FOLDLEVELHEADERFLAG;
			if (iLevel != accStyler.LevelAt(iLineCurrent)) {
				accStyler.SetLevel(iLineCurrent,iLevel);
			}
			iLineCurrent++;
			iLevelPrev = iLevelCurrent;
			iVisibleChars = 0;
		}
		
		if (!isspacechar(chChar))
			iVisibleChars++;
	}

	// Fill in the real level of the next line, keeping the current flags
	// as they will be filled in later.
	int iFlagsNext = accStyler.LevelAt(iLineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	accStyler.SetLevel(iLineCurrent, iLevelPrev | iFlagsNext);
}

// Word List Descriptions
static const char * const rgWordListDescriptions[] = {
	"Clarion Keywords",
	"Compiler Directives",
	"Built-in Procedures and Functions",
	"Runtime Expressions",
	"Structure and Data Types",
	"Attributes",
	"Standard Equates",
	"Reserved Words (Labels)",
	"Reserved Words (Procedure Labels)",
	0,
};

// Case Sensitive Clarion Language Lexer
LexerModule lmClw(SCLEX_CLW, ColouriseClarionDocSensitive, "clarion", FoldClarionDoc, rgWordListDescriptions);

// Case Insensitive Clarion Language Lexer
LexerModule lmClwNoCase(SCLEX_CLWNOCASE, ColouriseClarionDocInsensitive, "clarionnocase", FoldClarionDoc, rgWordListDescriptions);