diff options
author | nyamatongwe <devnull@localhost> | 2006-03-02 23:49:20 +0000 |
---|---|---|
committer | nyamatongwe <devnull@localhost> | 2006-03-02 23:49:20 +0000 |
commit | a54c9ae0dfa333e6cb53bec8da19da5b2ffedea0 (patch) | |
tree | cb63b610066ff3b228eb1169a9f0cc1692315335 /src | |
parent | 3cb4b3336847b20e5ad85d5ebe8a5f92c9bdad91 (diff) | |
download | scintilla-mirror-a54c9ae0dfa333e6cb53bec8da19da5b2ffedea0.tar.gz |
INitial commit.
Diffstat (limited to 'src')
-rw-r--r-- | src/LexTCL.cxx | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/src/LexTCL.cxx b/src/LexTCL.cxx new file mode 100644 index 000000000..80bf51aaa --- /dev/null +++ b/src/LexTCL.cxx @@ -0,0 +1,317 @@ +// Scintilla source code edit control +/** @file LexTCL.cxx + ** Lexer for TCL language. + **/ +// Copyright 1998-2001 by Andre Arpin <arpin@kingston.net> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdarg.h> +#include <stdio.h> + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "KeyWords.h" +#include "Scintilla.h" +#include "SciLexer.h" + +// Extended to accept accented characters +static inline bool IsAWordChar(int ch) { + return ch >= 0x80 || + (isalnum(ch) || ch == '_' || ch ==':'); // : name space separator +} + +static inline bool IsAWordStart(int ch) { + return ch >= 0x80 || + (isalpha(ch) || ch == '_'); +} + +static inline bool IsANumberChar(int ch) { + // Not exactly following number definition (several dots are seen as OK, etc.) + // but probably enough in most cases. + return (ch < 0x80) && + (isdigit(ch) || toupper(ch) == 'E' || + ch == '.' || ch == '-' || ch == '+'); +} + +static void ColouriseTCLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { + bool foldComment = styler.GetPropertyInt("fold.comment") != 0; + bool commentLevel = false; + bool subBrace = false; // substitution begin with a brace ${.....} + enum tLineState {LS_DEFAULT, LS_OPEN_COMMENT, LS_OPEN_DOUBLE_QUOTE, LS_MASK_STATE = 0xf, + LS_COMMAND_EXPECTED = 16, LS_BRACE_ONLY = 32 } lineState = LS_DEFAULT; + bool prevSlash = false; + int currentLevel = 0; + bool expected = 0; + int subParen = 0; + + int currentLine = styler.GetLine(startPos); + length += startPos - styler.LineStart(currentLine); + // make sure lines overlap + startPos = styler.LineStart(currentLine); + + WordList &keywords = *keywordlists[0]; + WordList &keywords2 = *keywordlists[1]; + WordList &keywords3 = *keywordlists[2]; + WordList &keywords4 = *keywordlists[3]; + WordList &keywords5 = *keywordlists[4]; + WordList &keywords6 = *keywordlists[5]; + WordList &keywords7 = *keywordlists[6]; + WordList &keywords8 = *keywordlists[7]; + WordList &keywords9 = *keywordlists[8]; + + if (currentLine > 0) { + int ls = styler.GetLineState(currentLine - 1); + lineState = tLineState(ls & LS_MASK_STATE); + expected = LS_COMMAND_EXPECTED == tLineState(ls & LS_COMMAND_EXPECTED); + subBrace = LS_BRACE_ONLY == tLineState(ls & LS_BRACE_ONLY); + currentLevel = styler.LevelAt(currentLine - 1) >> 17; + commentLevel = (styler.LevelAt(currentLine - 1) >> 16) & 1; + } else + styler.SetLevel(0, SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG); + bool visibleChars = false; + + int previousLevel = currentLevel; + StyleContext sc(startPos, length, initStyle, styler); + for (; ; sc.Forward()) { + bool atEnd = !sc.More(); // make sure we process last word at end of file +next: + if (subBrace) { + if (sc.ch == '}') { + subBrace = false; + sc.SetState(SCE_TCL_OPERATOR); // } + sc.ForwardSetState(SCE_TCL_DEFAULT); + } + else + sc.SetState(SCE_TCL_SUB_BRACE); + if (!sc.atLineEnd) + continue; + } else if (sc.state == SCE_TCL_DEFAULT || sc.state ==SCE_TCL_OPERATOR) { + expected &= isspacechar(static_cast<unsigned char>(sc.ch)) || IsAWordStart(sc.ch); + } else if (sc.state == SCE_TCL_SUBSTITUTION) { + if (sc.ch == '(') + subParen++; + else if (sc.ch == ')') { + if (subParen) + subParen--; + else + sc.SetState(SCE_TCL_DEFAULT); // lets the code below fix it + } else if (!IsAWordChar(sc.ch)) { + sc.SetState(SCE_TCL_DEFAULT); + subParen = 0; + } + } + else + { + if (!IsAWordChar(sc.ch)) { + if (sc.state == SCE_TCL_IDENTIFIER || sc.state == SCE_TCL_MODIFIER || expected) { + char s[100]; + sc.GetCurrent(s, sizeof(s)); + bool quote = sc.state == SCE_TCL_IN_QUOTE; + if (commentLevel || expected) { + if (keywords.InList(s)) { + sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD); + } else if (keywords2.InList(s)) { + sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD2); + } else if (keywords3.InList(s)) { + sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD3); + } else if (keywords4.InList(s)) { + sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD4); + } else if (sc.GetRelative(-static_cast<int>(strlen(s))-1) == '{' && + keywords5.InList(s) && sc.ch == '}') { // {keyword} exactly no spaces + sc.ChangeState(SCE_TCL_EXPAND); + } + if (keywords6.InList(s)) { + sc.ChangeState(SCE_TCL_WORD5); + } else if (keywords7.InList(s)) { + sc.ChangeState(SCE_TCL_WORD6); + } else if (keywords8.InList(s)) { + sc.ChangeState(SCE_TCL_WORD7); + } else if (keywords9.InList(s)) { + sc.ChangeState(SCE_TCL_WORD8); + } + } + expected = false; + sc.SetState(quote ? SCE_TCL_IN_QUOTE : SCE_TCL_DEFAULT); + } else if (sc.state == SCE_TCL_MODIFIER || sc.state == SCE_TCL_SUBSTITUTION) { + sc.SetState(SCE_TCL_DEFAULT); + } + } + } + if (atEnd) + break; + if (sc.atLineEnd) { + currentLine = styler.GetLine(sc.currentPos); + if (foldComment && sc.state == SCE_TCL_COMMENTLINE) { + if (currentLevel == 0) { + ++currentLevel; + commentLevel = true; + } + } else { + if (visibleChars && commentLevel) { + --currentLevel; + --previousLevel; + commentLevel = false; + } + } + int flag = 0; + if (!visibleChars) + flag = SC_FOLDLEVELWHITEFLAG; + if (currentLevel > previousLevel) + flag = SC_FOLDLEVELHEADERFLAG; + styler.SetLevel(currentLine, flag + previousLevel + SC_FOLDLEVELBASE + (currentLevel << 17) + (commentLevel << 16)); + + // Update the line state, so it can be seen by next line + if (sc.state == SCE_TCL_IN_QUOTE) + lineState = LS_OPEN_DOUBLE_QUOTE; + else if (prevSlash) { + if (sc.state == SCE_TCL_COMMENT || sc.state == SCE_TCL_COMMENTLINE) + lineState = LS_OPEN_COMMENT; + } + styler.SetLineState(currentLine, + (subBrace ? LS_BRACE_ONLY : 0) | + (expected ? LS_COMMAND_EXPECTED : 0) | lineState); + sc.SetState(SCE_TCL_DEFAULT); + prevSlash = false; + previousLevel = currentLevel; + lineState = LS_DEFAULT; + continue; + } + + if (prevSlash) { + prevSlash = (sc.state == SCE_TCL_COMMENT || sc.state == SCE_TCL_COMMENTLINE) && isspacechar(static_cast<unsigned char>(sc.ch)); + continue; + } + + if (sc.atLineStart) { + visibleChars = false; + if (lineState == LS_OPEN_COMMENT) { + sc.SetState(SCE_TCL_COMMENT); + lineState = LS_DEFAULT; + continue; + } + if (lineState == LS_OPEN_DOUBLE_QUOTE) + sc.SetState(SCE_TCL_IN_QUOTE); + else + { + sc.SetState(SCE_TCL_DEFAULT); + expected = IsAWordStart(sc.ch)|| isspacechar(static_cast<unsigned char>(sc.ch)); + } + } + + switch (sc.state) { + case SCE_TCL_NUMBER: + if (!IsANumberChar(sc.ch)) + sc.SetState(SCE_TCL_DEFAULT); + break; + case SCE_TCL_IN_QUOTE: + if (sc.ch == '"') { + sc.ForwardSetState(SCE_TCL_DEFAULT); + visibleChars = true; // necessary for a " as the first and only character on a line + goto next; + } else if (sc.ch == '[' || sc.ch == ']' || sc.ch == '$') { + sc.SetState(SCE_TCL_OPERATOR); + expected = sc.ch == '['; + sc.ForwardSetState(SCE_TCL_IN_QUOTE); + goto next; + } + prevSlash = sc.ch == '\\'; + continue; + case SCE_TCL_OPERATOR: + sc.SetState(SCE_TCL_DEFAULT); + break; + } + + if (sc.ch == '#') { + if (visibleChars) { + if (sc.state != SCE_TCL_IN_QUOTE && expected) { + sc.SetState(SCE_TCL_COMMENT); + expected = false; + } + } else + sc.SetState(SCE_TCL_COMMENTLINE); + } + + if (!isspacechar(static_cast<unsigned char>(sc.ch))) { + visibleChars = true; + } + + if (sc.ch == '\\') { + prevSlash = true; + continue; + } + + // Determine if a new state should be entered. + if (sc.state == SCE_TCL_DEFAULT) { + if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { + sc.SetState(SCE_TCL_NUMBER); + } else if (IsAWordStart(sc.ch) & expected) { + sc.SetState(SCE_TCL_IDENTIFIER); + } else { + switch (sc.ch) { + case '\"': + sc.SetState(SCE_TCL_IN_QUOTE); + break; + case '{': + sc.SetState(SCE_TCL_OPERATOR); + expected = true; + ++currentLevel; + break; + case '}': + sc.SetState(SCE_TCL_OPERATOR); + --currentLevel; + break; + case '[': + case ']': + sc.SetState(SCE_TCL_OPERATOR); + expected = true; + break; + case '(': + case ')': + sc.SetState(SCE_TCL_OPERATOR); + break; + case ';': + expected = true; + break; + case '$': + subParen = 0; + if (sc.chNext != '{') { + sc.SetState(SCE_TCL_SUBSTITUTION); + } + else { + sc.ForwardSetState(SCE_TCL_OPERATOR); // { + sc.ForwardSetState(SCE_TCL_SUB_BRACE); + subBrace = true; + } + break; + case '-': + if (!IsADigit(sc.chNext)) + sc.SetState(SCE_TCL_MODIFIER); + break; + } + } + } + } + sc.Complete(); +} + +static const char * const tclWordListDesc[] = { + "TCL Keywords", + "TK Keywords", + "iTCL Keywords", + "tkCommands", + "expand" + "user1", + "user2", + "user3", + "user4", + 0 + }; + +// this code supports folding in the colourizer +LexerModule lmTCL(SCLEX_TCL, ColouriseTCLDoc, "tcl", 0, tclWordListDesc); |