diff options
Diffstat (limited to 'src/LexCLW.cpp')
-rwxr-xr-x | src/LexCLW.cpp | 675 |
1 files changed, 675 insertions, 0 deletions
diff --git a/src/LexCLW.cpp b/src/LexCLW.cpp new file mode 100755 index 0000000..e28e4b1 --- /dev/null +++ b/src/LexCLW.cpp @@ -0,0 +1,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); |