1 // Scintilla source code edit control
5 // Copyright 2003 by Ron Schofield <ron@schofieldcomputer.com>
6 // The License.txt file describes the conditions under which this software may be distributed.
18 #include "StyleContext.h"
20 #include "Scintilla.h"
23 static char MakeUpperCase(char ch
) {
24 if (ch
< 'a' || ch
> 'z')
27 return static_cast<char>(ch
- 'a' + 'A');
30 static void MakeUpperCaseString(char *s
) {
32 *s
= MakeUpperCase(*s
);
37 // Is a label start character
38 inline bool IsALabelStart(const int iChar
) {
39 return(isalpha(iChar
) || iChar
== '_');
42 // Is a label character
43 inline bool IsALabelCharacter(const int iChar
) {
44 return(isalnum(iChar
) || iChar
== '_' || iChar
== ':');
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
!= '!');
52 // Is the character a Clarion hex character (ABCDEF)
53 inline bool IsAHexCharacter(const int iChar
, bool bCaseSensitive
) {
55 if (!bCaseSensitive
) {
56 if (strchr("ABCDEFabcdef", iChar
) != NULL
) {
62 if (strchr("ABCDEF", iChar
) != NULL
) {
69 // Is the character a Clarion base character (B=Binary, O=Octal, H=Hex)
70 inline bool IsANumericBaseCharacter(const int iChar
, bool bCaseSensitive
) {
72 if (!bCaseSensitive
) {
73 // If character is a numeric base character
74 if (strchr("BOHboh", iChar
) != NULL
) {
80 // If character is a numeric base character
81 if (strchr("BOH", iChar
) != NULL
) {
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
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
]) {
101 // Increment point counter
108 // If points found (can be more than one for improper formatted number
112 // Else no points found
118 // Clarion Language Colouring Procedure
119 static void ColouriseClwDoc(unsigned int uiStartPos
, int iLength
, int iInitStyle
, WordList
*wlKeywords
[], Accessor
&accStyler
, bool bCaseSensitive
) {
121 int iParenthesesLevel
=0; // Parenthese Level
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
131 StyleContext
scDoc(uiStartPos
, iLength
, iInitStyle
, accStyler
);
134 for (; scDoc
.More(); scDoc
.Forward())
137 // Determine if the current state should terminate.
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
);
150 scDoc
.SetState(SCE_CLW_LABEL
);
152 // Else terminate the label state
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
);
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
);
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
);
171 // Terminate the label state and set to default state
172 scDoc
.SetState(SCE_CLW_DEFAULT
);
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
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
234 // Terminate the keyword state and set to default state
235 scDoc
.SetState(SCE_CLW_DEFAULT
);
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
);
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
);
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
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
);
271 // Else parenthese level is greater than zero
272 // still looking for matching parentheses
274 // Decrement the parenthese level
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
);
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
)
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
);
300 // Else the number was an integer
302 // Colour the matched string to an integer constant state
303 scDoc
.ChangeState(SCE_CLW_INTEGER_CONSTANT
);
305 // Terminate the integer constant state and set to default state
306 scDoc
.SetState(SCE_CLW_DEFAULT
);
311 // Determine if a new state should be entered.
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
);
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
);
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
);
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
);
337 scDoc
.SetState(SCE_CLW_DEFAULT
);
339 // else an invalid character in column 1
341 // Set to error state
342 scDoc
.SetState(SCE_CLW_ERROR
);
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
);
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
);
360 else if (isdigit(scDoc
.ch
)) {
361 // Set the state to Integer Constant and verify later
362 scDoc
.SetState(SCE_CLW_INTEGER_CONSTANT
);
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
);
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
);
378 // move to the next character and then set the state to comment.
379 scDoc
.ForwardSetState(SCE_CLW_STRING
);
382 // else the character is an @ (apersand)
383 else if (scDoc
.ch
== '@') {
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
);
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
);
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);
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);
418 // Clarion Language Folding Procedure
419 #ifdef FOLDING_IMPLEMENTED
420 static void FoldClwDoc(unsigned int uiStartPos
, int iLength
, int iInitStyle
, WordList
*wlKeywords
[], Accessor
&accStyler
) {
425 // Word List Descriptions
426 static const char * const rgWordListDescriptions
[] = {
428 "Compiler Directives",
429 "Built-in Procedures and Functions",
430 "Structure and Data Types",
437 // Case Sensitive Clarion Language Lexer
438 LexerModule
lmClw(SCLEX_CLW
, ColouriseClwDocSensitive
, "clw", NULL
, rgWordListDescriptions
);
440 // Case Insensitive Clarion Language Lexer
441 LexerModule
lmClwNoCase(SCLEX_CLWNOCASE
, ColouriseClwDocInsensitive
, "clwnocase", NULL
, rgWordListDescriptions
);