--- /dev/null
+// Scintilla source code edit control\r
+/** @file LexBasic.cxx\r
+ ** Lexer for BlitzBasic and PureBasic.\r
+ **/\r
+// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>\r
+// The License.txt file describes the conditions under which this software may be distributed.\r
+\r
+// This tries to be a unified Lexer/Folder for all the BlitzBasic/BlitzMax/PurBasic basics\r
+// and derivatives. Once they diverge enough, might want to split it into multiple\r
+// lexers for more code clearity.\r
+//\r
+// Mail me (elias <at> users <dot> sf <dot> net) for any bugs.\r
+\r
+// Folding only works for simple things like functions or types.\r
+\r
+// You may want to have a look at my ctags lexer as well, if you additionally to coloring\r
+// and folding need to extract things like label tags in your editor.\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <stdio.h>\r
+#include <ctype.h>\r
+#include <stdarg.h>\r
+\r
+#include "Platform.h"\r
+\r
+#include "PropSet.h"\r
+#include "Accessor.h"\r
+#include "StyleContext.h"\r
+#include "KeyWords.h"\r
+#include "Scintilla.h"\r
+#include "SciLexer.h"\r
+\r
+#ifdef SCI_NAMESPACE\r
+using namespace Scintilla;\r
+#endif\r
+\r
+/* Bits:\r
+ * 1 - whitespace\r
+ * 2 - operator\r
+ * 4 - identifier\r
+ * 8 - decimal digit\r
+ * 16 - hex digit\r
+ * 32 - bin digit\r
+ */\r
+static int character_classification[128] =\r
+{\r
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,\r
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+ 1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 2,\r
+ 60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2,\r
+ 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,\r
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4,\r
+ 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,\r
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0\r
+};\r
+\r
+static bool IsSpace(int c) {\r
+ return c < 128 && (character_classification[c] & 1);\r
+}\r
+\r
+static bool IsOperator(int c) {\r
+ return c < 128 && (character_classification[c] & 2);\r
+}\r
+\r
+static bool IsIdentifier(int c) {\r
+ return c < 128 && (character_classification[c] & 4);\r
+}\r
+\r
+static bool IsDigit(int c) {\r
+ return c < 128 && (character_classification[c] & 8);\r
+}\r
+\r
+static bool IsHexDigit(int c) {\r
+ return c < 128 && (character_classification[c] & 16);\r
+}\r
+\r
+static bool IsBinDigit(int c) {\r
+ return c < 128 && (character_classification[c] & 32);\r
+}\r
+\r
+static int LowerCase(int c)\r
+{\r
+ if (c >= 'A' && c <= 'Z')\r
+ return 'a' + c - 'A';\r
+ return c;\r
+}\r
+\r
+static void ColouriseBasicDoc(unsigned int startPos, int length, int initStyle,\r
+ WordList *keywordlists[], Accessor &styler, char comment_char) {\r
+ bool wasfirst = true, isfirst = true; // true if first token in a line\r
+ styler.StartAt(startPos);\r
+\r
+ StyleContext sc(startPos, length, initStyle, styler);\r
+\r
+ // Can't use sc.More() here else we miss the last character\r
+ for (; ; sc.Forward()) {\r
+ if (sc.state == SCE_B_IDENTIFIER) {\r
+ if (!IsIdentifier(sc.ch)) {\r
+ // Labels\r
+ if (wasfirst && sc.Match(':')) {\r
+ sc.ChangeState(SCE_B_LABEL);\r
+ sc.ForwardSetState(SCE_B_DEFAULT);\r
+ } else {\r
+ char s[100];\r
+ int kstates[4] = {\r
+ SCE_B_KEYWORD,\r
+ SCE_B_KEYWORD2,\r
+ SCE_B_KEYWORD3,\r
+ SCE_B_KEYWORD4,\r
+ };\r
+ sc.GetCurrentLowered(s, sizeof(s));\r
+ for (int i = 0; i < 4; i++) {\r
+ if (keywordlists[i]->InList(s)) {\r
+ sc.ChangeState(kstates[i]);\r
+ }\r
+ }\r
+ // Types, must set them as operator else they will be\r
+ // matched as number/constant\r
+ if (sc.Match('.') || sc.Match('$') || sc.Match('%') ||\r
+ sc.Match('#')) {\r
+ sc.SetState(SCE_B_OPERATOR);\r
+ } else {\r
+ sc.SetState(SCE_B_DEFAULT);\r
+ }\r
+ }\r
+ }\r
+ } else if (sc.state == SCE_B_OPERATOR) {\r
+ if (!IsOperator(sc.ch) || sc.Match('#'))\r
+ sc.SetState(SCE_B_DEFAULT);\r
+ } else if (sc.state == SCE_B_LABEL) {\r
+ if (!IsIdentifier(sc.ch))\r
+ sc.SetState(SCE_B_DEFAULT);\r
+ } else if (sc.state == SCE_B_CONSTANT) {\r
+ if (!IsIdentifier(sc.ch))\r
+ sc.SetState(SCE_B_DEFAULT);\r
+ } else if (sc.state == SCE_B_NUMBER) {\r
+ if (!IsDigit(sc.ch))\r
+ sc.SetState(SCE_B_DEFAULT);\r
+ } else if (sc.state == SCE_B_HEXNUMBER) {\r
+ if (!IsHexDigit(sc.ch))\r
+ sc.SetState(SCE_B_DEFAULT);\r
+ } else if (sc.state == SCE_B_BINNUMBER) {\r
+ if (!IsBinDigit(sc.ch))\r
+ sc.SetState(SCE_B_DEFAULT);\r
+ } else if (sc.state == SCE_B_STRING) {\r
+ if (sc.ch == '"') {\r
+ sc.ForwardSetState(SCE_B_DEFAULT);\r
+ }\r
+ if (sc.atLineEnd) {\r
+ sc.ChangeState(SCE_B_ERROR);\r
+ sc.SetState(SCE_B_DEFAULT);\r
+ }\r
+ } else if (sc.state == SCE_B_COMMENT || sc.state == SCE_B_PREPROCESSOR) {\r
+ if (sc.atLineEnd) {\r
+ sc.SetState(SCE_B_DEFAULT);\r
+ }\r
+ }\r
+\r
+ if (sc.atLineStart)\r
+ isfirst = true;\r
+\r
+ if (sc.state == SCE_B_DEFAULT || sc.state == SCE_B_ERROR) {\r
+ if (isfirst && sc.Match('.')) {\r
+ sc.SetState(SCE_B_LABEL);\r
+ } else if (isfirst && sc.Match('#')) {\r
+ wasfirst = isfirst;\r
+ sc.SetState(SCE_B_IDENTIFIER);\r
+ } else if (sc.Match(comment_char)) {\r
+ // Hack to make deprecated QBASIC '$Include show\r
+ // up in freebasic with SCE_B_PREPROCESSOR.\r
+ if (comment_char == '\'' && sc.Match(comment_char, '$'))\r
+ sc.SetState(SCE_B_PREPROCESSOR);\r
+ else\r
+ sc.SetState(SCE_B_COMMENT);\r
+ } else if (sc.Match('"')) {\r
+ sc.SetState(SCE_B_STRING);\r
+ } else if (IsDigit(sc.ch)) {\r
+ sc.SetState(SCE_B_NUMBER);\r
+ } else if (sc.Match('$')) {\r
+ sc.SetState(SCE_B_HEXNUMBER);\r
+ } else if (sc.Match('%')) {\r
+ sc.SetState(SCE_B_BINNUMBER);\r
+ } else if (sc.Match('#')) {\r
+ sc.SetState(SCE_B_CONSTANT);\r
+ } else if (IsOperator(sc.ch)) {\r
+ sc.SetState(SCE_B_OPERATOR);\r
+ } else if (IsIdentifier(sc.ch)) {\r
+ wasfirst = isfirst;\r
+ sc.SetState(SCE_B_IDENTIFIER);\r
+ } else if (!IsSpace(sc.ch)) {\r
+ sc.SetState(SCE_B_ERROR);\r
+ }\r
+ }\r
+\r
+ if (!IsSpace(sc.ch))\r
+ isfirst = false;\r
+\r
+ if (!sc.More())\r
+ break;\r
+ }\r
+ sc.Complete();\r
+}\r
+\r
+static int CheckBlitzFoldPoint(char const *token, int &level) {\r
+ if (!strcmp(token, "function") ||\r
+ !strcmp(token, "type")) {\r
+ level |= SC_FOLDLEVELHEADERFLAG;\r
+ return 1;\r
+ }\r
+ if (!strcmp(token, "end function") ||\r
+ !strcmp(token, "end type")) {\r
+ return -1;\r
+ }\r
+ return 0;\r
+}\r
+\r
+static int CheckPureFoldPoint(char const *token, int &level) {\r
+ if (!strcmp(token, "procedure") ||\r
+ !strcmp(token, "enumeration") ||\r
+ !strcmp(token, "interface") ||\r
+ !strcmp(token, "structure")) {\r
+ level |= SC_FOLDLEVELHEADERFLAG;\r
+ return 1;\r
+ }\r
+ if (!strcmp(token, "endprocedure") ||\r
+ !strcmp(token, "endenumeration") ||\r
+ !strcmp(token, "endinterface") ||\r
+ !strcmp(token, "endstructure")) {\r
+ return -1;\r
+ }\r
+ return 0;\r
+}\r
+\r
+static int CheckFreeFoldPoint(char const *token, int &level) {\r
+ if (!strcmp(token, "function") ||\r
+ !strcmp(token, "sub") ||\r
+ !strcmp(token, "type")) {\r
+ level |= SC_FOLDLEVELHEADERFLAG;\r
+ return 1;\r
+ }\r
+ if (!strcmp(token, "end function") ||\r
+ !strcmp(token, "end sub") ||\r
+ !strcmp(token, "end type")) {\r
+ return -1;\r
+ }\r
+ return 0;\r
+}\r
+\r
+static void FoldBasicDoc(unsigned int startPos, int length,\r
+ Accessor &styler, int (*CheckFoldPoint)(char const *, int &)) {\r
+ int line = styler.GetLine(startPos);\r
+ int level = styler.LevelAt(line);\r
+ int go = 0, done = 0;\r
+ int endPos = startPos + length;\r
+ char word[256];\r
+ int wordlen = 0;\r
+ int i;\r
+ bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;\r
+ // Scan for tokens at the start of the line (they may include\r
+ // whitespace, for tokens like "End Function"\r
+ for (i = startPos; i < endPos; i++) {\r
+ int c = styler.SafeGetCharAt(i);\r
+ if (!done && !go) {\r
+ if (wordlen) { // are we scanning a token already?\r
+ word[wordlen] = static_cast<char>(LowerCase(c));\r
+ if (!IsIdentifier(c)) { // done with token\r
+ word[wordlen] = '\0';\r
+ go = CheckFoldPoint(word, level);\r
+ if (!go) {\r
+ // Treat any whitespace as single blank, for\r
+ // things like "End Function".\r
+ if (IsSpace(c) && IsIdentifier(word[wordlen - 1])) {\r
+ word[wordlen] = ' ';\r
+ if (wordlen < 255)\r
+ wordlen++;\r
+ }\r
+ else // done with this line\r
+ done = 1;\r
+ }\r
+ } else if (wordlen < 255) {\r
+ wordlen++;\r
+ }\r
+ } else { // start scanning at first non-whitespace character\r
+ if (!IsSpace(c)) {\r
+ if (IsIdentifier(c)) {\r
+ word[0] = static_cast<char>(LowerCase(c));\r
+ wordlen = 1;\r
+ } else // done with this line\r
+ done = 1;\r
+ }\r
+ }\r
+ }\r
+ if (c == '\n') { // line end\r
+ if (!done && wordlen == 0 && foldCompact) // line was only space\r
+ level |= SC_FOLDLEVELWHITEFLAG;\r
+ if (level != styler.LevelAt(line))\r
+ styler.SetLevel(line, level);\r
+ level += go;\r
+ line++;\r
+ // reset state\r
+ wordlen = 0;\r
+ level &= ~SC_FOLDLEVELHEADERFLAG;\r
+ level &= ~SC_FOLDLEVELWHITEFLAG;\r
+ go = 0;\r
+ done = 0;\r
+ }\r
+ }\r
+}\r
+\r
+static void ColouriseBlitzBasicDoc(unsigned int startPos, int length, int initStyle,\r
+ WordList *keywordlists[], Accessor &styler) {\r
+ ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, ';');\r
+}\r
+\r
+static void ColourisePureBasicDoc(unsigned int startPos, int length, int initStyle,\r
+ WordList *keywordlists[], Accessor &styler) {\r
+ ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, ';');\r
+}\r
+\r
+static void ColouriseFreeBasicDoc(unsigned int startPos, int length, int initStyle,\r
+ WordList *keywordlists[], Accessor &styler) {\r
+ ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, '\'');\r
+}\r
+\r
+static void FoldBlitzBasicDoc(unsigned int startPos, int length, int,\r
+ WordList *[], Accessor &styler) {\r
+ FoldBasicDoc(startPos, length, styler, CheckBlitzFoldPoint);\r
+}\r
+\r
+static void FoldPureBasicDoc(unsigned int startPos, int length, int,\r
+ WordList *[], Accessor &styler) {\r
+ FoldBasicDoc(startPos, length, styler, CheckPureFoldPoint);\r
+}\r
+\r
+static void FoldFreeBasicDoc(unsigned int startPos, int length, int,\r
+ WordList *[], Accessor &styler) {\r
+ FoldBasicDoc(startPos, length, styler, CheckFreeFoldPoint);\r
+}\r
+\r
+static const char * const blitzbasicWordListDesc[] = {\r
+ "BlitzBasic Keywords",\r
+ "user1",\r
+ "user2",\r
+ "user3",\r
+ 0\r
+};\r
+\r
+static const char * const purebasicWordListDesc[] = {\r
+ "PureBasic Keywords",\r
+ "PureBasic PreProcessor Keywords",\r
+ "user defined 1",\r
+ "user defined 2",\r
+ 0\r
+};\r
+\r
+static const char * const freebasicWordListDesc[] = {\r
+ "FreeBasic Keywords",\r
+ "FreeBasic PreProcessor Keywords",\r
+ "user defined 1",\r
+ "user defined 2",\r
+ 0\r
+};\r
+\r
+LexerModule lmBlitzBasic(SCLEX_BLITZBASIC, ColouriseBlitzBasicDoc, "blitzbasic",\r
+ FoldBlitzBasicDoc, blitzbasicWordListDesc);\r
+\r
+LexerModule lmPureBasic(SCLEX_PUREBASIC, ColourisePureBasicDoc, "purebasic",\r
+ FoldPureBasicDoc, purebasicWordListDesc);\r
+\r
+LexerModule lmFreeBasic(SCLEX_FREEBASIC, ColouriseFreeBasicDoc, "freebasic",\r
+ FoldFreeBasicDoc, freebasicWordListDesc);\r
+\r