diff options
author | nyamatongwe <unknown> | 2002-10-05 01:59:43 +0000 |
---|---|---|
committer | nyamatongwe <unknown> | 2002-10-05 01:59:43 +0000 |
commit | 6184b2808a10717d98a05ff7f5d933e026842f8e (patch) | |
tree | b726a23c25babc295c89fb7c565b26eff459a089 | |
parent | bebf2d4f9d96b217b03cb0eddb43b588035ae41b (diff) | |
download | scintilla-mirror-6184b2808a10717d98a05ff7f5d933e026842f8e.tar.gz |
More comprehensive Ada support.
-rw-r--r-- | include/SciLexer.h | 21 | ||||
-rw-r--r-- | include/Scintilla.iface | 21 | ||||
-rw-r--r-- | src/LexAda.cxx | 674 |
3 files changed, 533 insertions, 183 deletions
diff --git a/include/SciLexer.h b/include/SciLexer.h index 26d559902..390ab4ef2 100644 --- a/include/SciLexer.h +++ b/include/SciLexer.h @@ -319,14 +319,19 @@ #define SCE_AVE_IDENTIFIER 9 #define SCE_AVE_OPERATOR 10 #define SCE_ADA_DEFAULT 0 -#define SCE_ADA_COMMENT 1 -#define SCE_ADA_NUMBER 2 -#define SCE_ADA_WORD 3 -#define SCE_ADA_STRING 4 -#define SCE_ADA_CHARACTER 5 -#define SCE_ADA_OPERATOR 6 -#define SCE_ADA_IDENTIFIER 7 -#define SCE_ADA_STRINGEOL 8 +#define SCE_ADA_WORD 1 +#define SCE_ADA_IDENTIFIER 2 +#define SCE_ADA_BADIDENTIFIER 3 +#define SCE_ADA_NUMBER 4 +#define SCE_ADA_BADNUMBER 5 +#define SCE_ADA_DELIMITER 6 +#define SCE_ADA_CHARACTER 7 +#define SCE_ADA_CHARACTEREOL 8 +#define SCE_ADA_STRING 9 +#define SCE_ADA_STRINGEOL 10 +#define SCE_ADA_LABEL 11 +#define SCE_ADA_BADLABEL 12 +#define SCE_ADA_COMMENTLINE 13 #define SCE_BAAN_DEFAULT 0 #define SCE_BAAN_COMMENT 1 #define SCE_BAAN_COMMENTDOC 2 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index 7957b64a1..b592fd062 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -1779,14 +1779,19 @@ val SCE_AVE_OPERATOR=10 # Lexical states for SCLEX_ADA lex Ada=SCLEX_ADA SCE_ADA_ val SCE_ADA_DEFAULT=0 -val SCE_ADA_COMMENT=1 -val SCE_ADA_NUMBER=2 -val SCE_ADA_WORD=3 -val SCE_ADA_STRING=4 -val SCE_ADA_CHARACTER=5 -val SCE_ADA_OPERATOR=6 -val SCE_ADA_IDENTIFIER=7 -val SCE_ADA_STRINGEOL=8 +val SCE_ADA_WORD=1 +val SCE_ADA_IDENTIFIER=2 +val SCE_ADA_BADIDENTIFIER=3 +val SCE_ADA_NUMBER=4 +val SCE_ADA_BADNUMBER=5 +val SCE_ADA_DELIMITER=6 +val SCE_ADA_CHARACTER=7 +val SCE_ADA_CHARACTEREOL=8 +val SCE_ADA_STRING=9 +val SCE_ADA_STRINGEOL=10 +val SCE_ADA_LABEL=11 +val SCE_ADA_BADLABEL=12 +val SCE_ADA_COMMENTLINE=13 # Lexical states for SCLEX_BAAN lex Baan=SCLEX_BAAN SCE_BAAN_ val SCE_BAAN_DEFAULT=0 diff --git a/src/LexAda.cxx b/src/LexAda.cxx index 0d8fb9d5d..657218eef 100644 --- a/src/LexAda.cxx +++ b/src/LexAda.cxx @@ -1,198 +1,538 @@ -// SciTE - Scintilla based Text Editor -// LexAda.cxx - lexer for Ada95 -// by Tahir Karaca <tahir@bigfoot.de> -// The License.txt file describes the conditions under which this software may be distributed. +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <stdio.h> -#include <stdarg.h> - -#include "Platform.h" - -#include "PropSet.h" #include "Accessor.h" +#include "StyleContext.h" +#include "PropSet.h" #include "KeyWords.h" -#include "Scintilla.h" #include "SciLexer.h" +#include "SString.h" + +/* + * Interface + */ + +static void ColouriseDocument( + unsigned int startPos, + int length, + int initStyle, + WordList *keywordlists[], + Accessor &styler); + +LexerModule lmAda(SCLEX_ADA, ColouriseDocument, "ada"); + +/* + * Implementation + */ + +static void ColouriseCharacter (StyleContext& sc); +static void ColouriseContext (StyleContext& sc, char chEnd, int stateEOL); +static void ColouriseComment (StyleContext& sc); +static void ColouriseDelimiter (StyleContext& sc); +static void ColouriseLabel (StyleContext& sc, WordList& keywords); +static void ColouriseNumber (StyleContext& sc); +static void ColouriseString (StyleContext& sc); +static void ColouriseWhiteSpace (StyleContext& sc); +static void ColouriseWord (StyleContext& sc, WordList& keywords); -inline void classifyWordAda(unsigned int start, unsigned int end, - WordList &keywords, Accessor &styler) { +static inline bool isDelimiterCharacter (int ch); +static inline bool isNumberStartCharacter (int ch); +static inline bool isNumberCharacter (int ch); +static inline bool isSeparatorOrDelimiter (int ch); +static bool isValidIdentifier (const SString& identifier); +static bool isValidNumber (const SString& number); +static inline bool isWordStartCharacter (int ch); +static inline bool isWordCharacter (int ch); - static const unsigned KEWORD_LEN_MAX = 30; +static void ColouriseCharacter (StyleContext& sc) +{ + sc.SetState (SCE_ADA_CHARACTER); + + // Skip the apostrophe and one more character (so that '' is shown as non-terminated and ''' + // is handled correctly) + sc.Forward (); + sc.Forward (); + + ColouriseContext (sc, '\'', SCE_ADA_CHARACTEREOL); +} + +static void ColouriseContext (StyleContext& sc, char chEnd, int stateEOL) +{ + while (!sc.atLineEnd && !sc.Match (chEnd)) + { + sc.Forward (); + } - char wordLower[KEWORD_LEN_MAX + 1]; - unsigned i; - for(i = 0; ( i < KEWORD_LEN_MAX ) && ( i < end - start + 1 ); i++) { - wordLower[i] = static_cast<char>(tolower(styler[start + i])); + if (!sc.atLineEnd) + { + sc.ForwardSetState (SCE_ADA_DEFAULT); } - wordLower[i] = '\0'; + else + { + sc.ChangeState (stateEOL); + } +} + +static void ColouriseComment (StyleContext& sc) +{ + sc.SetState (SCE_ADA_COMMENTLINE); + + while (!sc.atLineEnd) + { + sc.Forward (); + } +} + +static void ColouriseDelimiter (StyleContext& sc) +{ + sc.SetState (SCE_ADA_DELIMITER); + sc.ForwardSetState (SCE_ADA_DEFAULT); +} + +static void ColouriseLabel (StyleContext& sc, WordList& keywords) +{ + sc.SetState (SCE_ADA_LABEL); + + // Skip "<<" + sc.Forward (); + sc.Forward (); + + SString identifier; + + while (!sc.atLineEnd && !isSeparatorOrDelimiter (sc.ch)) + { + identifier += (char) tolower (sc.ch); + sc.Forward (); + } + + // Skip ">>" + if (sc.Match ('>', '>')) + { + sc.Forward (); + sc.Forward (); + } + else + { + sc.ChangeState (SCE_ADA_BADLABEL); + } + + if (!isValidIdentifier (identifier) || keywords.InList (identifier.c_str ())) + { + sc.ChangeState (SCE_ADA_BADLABEL); + } + + sc.SetState (SCE_ADA_DEFAULT); +} + +static void ColouriseNumber (StyleContext& sc) +{ + SString number; + sc.SetState (SCE_ADA_NUMBER); + + while (!isSeparatorOrDelimiter (sc.ch)) + { + number += (char) sc.ch; + sc.Forward (); + } + + // Special case: exponent with sign + if (tolower (sc.chPrev) == 'e' + && (sc.Match ('+') || sc.Match ('-')) + && isdigit (sc.chNext)) + { + number += (char) sc.ch; + sc.Forward (); -// int levelChange = 0; - char chAttr = SCE_ADA_IDENTIFIER; - if (keywords.InList(wordLower)) { - chAttr = SCE_ADA_WORD; - -// Folding doesn't work this way since the semantics of some keywords depends -// on the current context. -// E.g. - "cond1 and THEN cond2" <-> "if ... THEN ..." -// - "procedure X IS ... end X;" <-> "procedure X IS new Y;" -// if (strcmp(wordLower, "is") == 0 || strcmp(wordLower, "then") == 0) -// levelChange=1; -// else if (strcmp(wordLower, "end") == 0) -// levelChange=-1; - } - styler.ColourTo(end, chAttr); + while (!isSeparatorOrDelimiter (sc.ch)) + { + number += (char) sc.ch; + sc.Forward (); + } + } -// return levelChange; + if (!isValidNumber (number)) + { + sc.ChangeState (SCE_ADA_BADNUMBER); + } + + sc.SetState (SCE_ADA_DEFAULT); } +static void ColouriseString (StyleContext& sc) +{ + sc.SetState (SCE_ADA_STRING); + sc.Forward (); -static inline bool isAdaOperator(char ch) { - - if (ch == '&' || ch == '\'' || ch == '(' || ch == ')' || - ch == '*' || ch == '+' || ch == ',' || ch == '-' || - ch == '.' || ch == '/' || ch == ':' || ch == ';' || - ch == '<' || ch == '=' || ch == '>') - return true; - return false; + ColouriseContext (sc, '"', SCE_ADA_STRINGEOL); } +static void ColouriseWhiteSpace (StyleContext& sc) +{ + sc.SetState (SCE_ADA_DEFAULT); + sc.ForwardSetState (SCE_ADA_DEFAULT); +} -inline void styleTokenBegin(char beginChar, unsigned int pos, int &state, - Accessor &styler) { - - if (isalpha(beginChar)) { - styler.ColourTo(pos-1, state); - state = SCE_ADA_IDENTIFIER; - } else if (isdigit(beginChar)) { - styler.ColourTo(pos-1, state); - state = SCE_ADA_NUMBER; - } else if (beginChar == '-' && styler.SafeGetCharAt(pos + 1) == '-') { - styler.ColourTo(pos-1, state); - state = SCE_ADA_COMMENT; - } else if (beginChar == '\"') { - styler.ColourTo(pos-1, state); - state = SCE_ADA_STRING; - } else if (beginChar == '\'' && styler.SafeGetCharAt(pos + 2) == '\'') { - styler.ColourTo(pos-1, state); - state = SCE_ADA_CHARACTER; - } else if (isAdaOperator(beginChar)) { - styler.ColourTo(pos-1, state); - styler.ColourTo(pos, SCE_ADA_OPERATOR); - } -} - - -static void ColouriseAdaDoc(unsigned int startPos, int length, int initStyle, - WordList *keywordlists[], Accessor &styler) { +static void ColouriseWord (StyleContext& sc, WordList& keywords) +{ + SString identifier; + sc.SetState (SCE_ADA_IDENTIFIER); + + while (!sc.atLineEnd && isWordCharacter (sc.ch)) + { + identifier += (char) tolower (sc.ch); + sc.Forward (); + } + + if (!isValidIdentifier (identifier)) + { + sc.ChangeState (SCE_ADA_BADIDENTIFIER); + } + else if (keywords.InList (identifier.c_str ())) + { + sc.ChangeState (SCE_ADA_WORD); + } + sc.SetState (SCE_ADA_DEFAULT); +} + +// +// ColouriseDocument +// + +static void ColouriseDocument( + unsigned int startPos, + int length, + int initStyle, + WordList *keywordlists[], + Accessor &styler) +{ WordList &keywords = *keywordlists[0]; + + StyleContext sc(startPos, length, initStyle, styler); + + // Apostrophe can start either an attribute or a character constant. Which + int lineCurrent = styler.GetLine (startPos); + int lineState = styler.GetLineState (lineCurrent); + + bool apostropheStartsAttribute = (lineState & 1) != 0; + + while (sc.More ()) + { + if (sc.atLineEnd) + { + sc.Forward (); + lineCurrent++; + + // Remember the apostrophe setting + styler.SetLineState (lineCurrent, apostropheStartsAttribute ? 1 : 0); + + // Don't leak any styles onto the next line + sc.SetState (SCE_ADA_DEFAULT); + } + + // Comments + if (sc.Match ('-', '-')) + { + ColouriseComment (sc); + } + + // Strings + else if (sc.Match ('"')) + { + apostropheStartsAttribute = false; + ColouriseString (sc); + } + + // Characters + else if (sc.Match ('\'') && !apostropheStartsAttribute) + { + apostropheStartsAttribute = false; + ColouriseCharacter (sc); + } + + // Labels + else if (sc.Match ('<', '<')) + { + apostropheStartsAttribute = false; + ColouriseLabel (sc, keywords); + } + + // Whitespace + else if (isspace (sc.ch)) + { + ColouriseWhiteSpace (sc); + } + + // Delimiters + else if (isDelimiterCharacter (sc.ch)) + { + apostropheStartsAttribute = sc.ch == ')'; + ColouriseDelimiter (sc); + } + + // Numbers + else if (isdigit (sc.ch)) + { + apostropheStartsAttribute = false; + ColouriseNumber (sc); + } + + // Keywords or identifiers + else + { + apostropheStartsAttribute = true; + ColouriseWord (sc, keywords); + } + } + + sc.Complete (); +} + +static inline bool isDelimiterCharacter (int ch) +{ + switch (ch) + { + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case '-': + case '.': + case '/': + case ':': + case ';': + case '<': + case '=': + case '>': + case '|': + return true; + default: + return false; + } +} + +static inline bool isNumberCharacter (int ch) +{ + return isNumberStartCharacter (ch) + || ch == '_' + || ch == '.' + || ch == '#' + || (ch >= 'a' && ch <= 'f') + || (ch >= 'A' && ch <= 'F'); +} + +static inline bool isNumberStartCharacter (int ch) +{ + return isdigit (ch) != 0; +} + +static inline bool isSeparatorOrDelimiter (int ch) +{ + return isspace (ch) || isDelimiterCharacter (ch); +} + +static bool isValidIdentifier (const SString& identifier) +{ + // First character can't be '_', so we set the variable to true initially + bool lastWasUnderscore = true; + + int length = identifier.length (); - styler.StartAt(startPos); + // Zero-length identifiers are not valid (these can occur inside labels) + if (length == 0) return false; + + if (!isWordStartCharacter (identifier[0])) return false; + + // Check for only valid characters and no double underscores + for (int i = 0; i < length; i++) + { + if (!isWordCharacter (identifier[i])) return false; + else if (identifier[i] == '_' && lastWasUnderscore) return false; + lastWasUnderscore = identifier[i] == '_'; + } + + // Check for underscore at the end + if (lastWasUnderscore == true) return false; + + // All checks passed + return true; +} + +static bool isValidNumber (const SString& number) +{ + int hashPos = number.search ("#"); + bool seenDot = false; -// bool fold = styler.GetPropertyInt("fold"); -// int lineCurrent = styler.GetLine(startPos); -// int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; -// int levelCurrent = levelPrev; - - int state = initStyle; - if (state == SCE_ADA_STRINGEOL) // Does not leak onto next line - state = SCE_ADA_DEFAULT; - char chNext = styler[startPos]; - const unsigned int lengthDoc = startPos + length; - //int visibleChars = 0; - styler.StartSegment(startPos); - for (unsigned int i = startPos; i < lengthDoc; i++) { - char ch = chNext; - chNext = styler.SafeGetCharAt(i + 1); - - if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { - // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix) - // Avoid triggering two times on Dos/Win - if (state == SCE_ADA_STRINGEOL) { - styler.ColourTo(i, state); - state = SCE_ADA_DEFAULT; - } -// if (fold) { -// int lev = levelPrev; -// if (visibleChars == 0) -// lev |= SC_FOLDLEVELWHITEFLAG; -// if ((levelCurrent > levelPrev) && (visibleChars > 0)) -// lev |= SC_FOLDLEVELHEADERFLAG; -// styler.SetLevel(lineCurrent, lev); -// lineCurrent++; -// levelPrev = levelCurrent; -// } - //visibleChars = 0; + int i = 0; + int length = number.length (); + + if (length == 0) return false; // Just in case + + // Decimal number + if (hashPos == -1) + { + bool canBeSpecial = false; + + for (; i < length; i++) + { + if (number[i] == '_') + { + if (!canBeSpecial) return false; + canBeSpecial = false; + } + else if (number[i] == '.') + { + if (!canBeSpecial || seenDot) return false; + canBeSpecial = false; + seenDot = true; + } + else if (isdigit (number[i])) + { + canBeSpecial = true; + } + else if (number[i] != 'e' && number[i] != 'E') + { + return false; + } } - //if (!isspacechar(ch)) - // visibleChars++; + + if (!canBeSpecial) return false; + } + + // Based number + else + { + bool canBeSpecial = false; + int base = 0; - if (styler.IsLeadByte(ch)) { - chNext = styler.SafeGetCharAt(i + 2); - i += 1; - continue; + // Parse base + for (; i < length; i++) + { + int ch = number[i]; + if (ch == '_') + { + if (!canBeSpecial) return false; + canBeSpecial = false; + } + else if (isdigit (ch)) + { + base = base * 10 + (ch - '0'); + if (base > 16) return false; + canBeSpecial = true; + } + else if (ch == '#' && canBeSpecial) + { + break; + } + else + { + return false; + } } - if (state == SCE_ADA_DEFAULT) { - styleTokenBegin(ch, i, state, styler); - } else if (state == SCE_ADA_IDENTIFIER) { - if (!iswordchar(ch)) { - classifyWordAda(styler.GetStartSegment(), - i - 1, - keywords, - styler); - state = SCE_ADA_DEFAULT; - styleTokenBegin(ch, i, state, styler); - } - } else if (state == SCE_ADA_COMMENT) { - if (ch == '\r' || ch == '\n') { - styler.ColourTo(i-1, state); - state = SCE_ADA_DEFAULT; - } - } else if (state == SCE_ADA_STRING) { - if (ch == '"' ) { - if( chNext == '"' ) { - i++; - chNext = styler.SafeGetCharAt(i + 1); - } else { - styler.ColourTo(i, state); - state = SCE_ADA_DEFAULT; - } - } else if (chNext == '\r' || chNext == '\n') { - styler.ColourTo(i-1, SCE_ADA_STRINGEOL); - state = SCE_ADA_STRINGEOL; - } - } else if (state == SCE_ADA_CHARACTER) { - if (ch == '\r' || ch == '\n') { - styler.ColourTo(i-1, SCE_ADA_STRINGEOL); - state = SCE_ADA_STRINGEOL; - } else if (ch == '\'' && styler.SafeGetCharAt(i - 2) == '\'') { - styler.ColourTo(i, state); - state = SCE_ADA_DEFAULT; - } - } else if (state == SCE_ADA_NUMBER) { - if ( !( isdigit(ch) || ch == '.' || ch == '_' || ch == '#' - || ch == 'A' || ch == 'B' || ch == 'C' || ch == 'D' - || ch == 'E' || ch == 'F' - || ch == 'a' || ch == 'b' || ch == 'c' || ch == 'd' - || ch == 'e' || ch == 'f' ) ) { - styler.ColourTo(i-1, SCE_ADA_NUMBER); - state = SCE_ADA_DEFAULT; - styleTokenBegin(ch, i, state, styler); + if (base < 2) return false; + if (i == length) return false; + + i++; // Skip over '#' + + // Parse number + canBeSpecial = false; + + for (; i < length; i++) + { + int ch = tolower (number[i]); + if (ch == '_') + { + if (!canBeSpecial) return false; + canBeSpecial = false; + } + else if (ch == '.') + { + if (!canBeSpecial || seenDot) return false; + canBeSpecial = false; + seenDot = true; + } + else if (isdigit (ch)) + { + if (ch - '0' >= base) return false; + canBeSpecial = true; + } + else if (ch >= 'a' && ch <= 'f') + { + if (ch - 'a' + 10 >= base) return false; + canBeSpecial = true; + } + else if (ch == '#' && canBeSpecial) + { + break; + } + else + { + return false; } } + + if (i == length) return false; + i++; + } + + // Exponent (optional) + if (i < length) + { + if (number[i] != 'e' && number[i] != 'E') return false; + + i++; + + if (i == length) return false; + + if (number[i] == '+') + i++; + else if (number[i] == '-') + { + if (seenDot) + i++; + else + return false; // Integer literals should not have negative exponents + } + + if (i == length) return false; + + bool canBeSpecial = false; + for (; i < length; i++) + { + if (number[i] == '_') + { + if (!canBeSpecial) return false; + canBeSpecial = false; + } + else if (isdigit (number[i])) + { + canBeSpecial = true; + } + else + { + return false; + } + } + + if (!canBeSpecial) return false; } - styler.ColourTo(lengthDoc - 1, state); -// // Fill in the real level of the next line, keeping the current flags as they will be filled in later -// if (fold) { -// int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; -// styler.SetLevel(lineCurrent, levelPrev | flagsNext); -// } + return i == length; // if i == length, number was parsed successfully. +} + +static inline bool isWordCharacter (int ch) +{ + return isWordStartCharacter (ch) || isdigit (ch); } -LexerModule lmAda(SCLEX_ADA, ColouriseAdaDoc, "ada"); +static inline bool isWordStartCharacter (int ch) +{ + return isalpha (ch) || ch == '_'; +} |