]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexBasic.cxx
1 // Scintilla source code edit control
3 ** Lexer for BlitzBasic and PureBasic.
5 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
8 // This tries to be a unified Lexer/Folder for all the BlitzBasic/BlitzMax/PurBasic basics
9 // and derivatives. Once they diverge enough, might want to split it into multiple
10 // lexers for more code clearity.
12 // Mail me (elias <at> users <dot> sf <dot> net) for any bugs.
14 // Folding only works for simple things like functions or types.
16 // You may want to have a look at my ctags lexer as well, if you additionally to coloring
17 // and folding need to extract things like label tags in your editor.
29 #include "StyleContext.h"
31 #include "Scintilla.h"
35 using namespace Scintilla
;
46 static int character_classification
[128] =
48 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
49 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50 1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 2,
51 60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2,
52 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
53 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4,
54 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
55 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0
58 static bool IsSpace(int c
) {
59 return c
< 128 && (character_classification
[c
] & 1);
62 static bool IsOperator(int c
) {
63 return c
< 128 && (character_classification
[c
] & 2);
66 static bool IsIdentifier(int c
) {
67 return c
< 128 && (character_classification
[c
] & 4);
70 static bool IsDigit(int c
) {
71 return c
< 128 && (character_classification
[c
] & 8);
74 static bool IsHexDigit(int c
) {
75 return c
< 128 && (character_classification
[c
] & 16);
78 static bool IsBinDigit(int c
) {
79 return c
< 128 && (character_classification
[c
] & 32);
82 static int LowerCase(int c
)
84 if (c
>= 'A' && c
<= 'Z')
89 static void ColouriseBasicDoc(unsigned int startPos
, int length
, int initStyle
,
90 WordList
*keywordlists
[], Accessor
&styler
, char comment_char
) {
91 bool wasfirst
= true, isfirst
= true; // true if first token in a line
92 styler
.StartAt(startPos
);
94 StyleContext
sc(startPos
, length
, initStyle
, styler
);
96 // Can't use sc.More() here else we miss the last character
97 for (; ; sc
.Forward()) {
98 if (sc
.state
== SCE_B_IDENTIFIER
) {
99 if (!IsIdentifier(sc
.ch
)) {
101 if (wasfirst
&& sc
.Match(':')) {
102 sc
.ChangeState(SCE_B_LABEL
);
103 sc
.ForwardSetState(SCE_B_DEFAULT
);
112 sc
.GetCurrentLowered(s
, sizeof(s
));
113 for (int i
= 0; i
< 4; i
++) {
114 if (keywordlists
[i
]->InList(s
)) {
115 sc
.ChangeState(kstates
[i
]);
118 // Types, must set them as operator else they will be
119 // matched as number/constant
120 if (sc
.Match('.') || sc
.Match('$') || sc
.Match('%') ||
122 sc
.SetState(SCE_B_OPERATOR
);
124 sc
.SetState(SCE_B_DEFAULT
);
128 } else if (sc
.state
== SCE_B_OPERATOR
) {
129 if (!IsOperator(sc
.ch
) || sc
.Match('#'))
130 sc
.SetState(SCE_B_DEFAULT
);
131 } else if (sc
.state
== SCE_B_LABEL
) {
132 if (!IsIdentifier(sc
.ch
))
133 sc
.SetState(SCE_B_DEFAULT
);
134 } else if (sc
.state
== SCE_B_CONSTANT
) {
135 if (!IsIdentifier(sc
.ch
))
136 sc
.SetState(SCE_B_DEFAULT
);
137 } else if (sc
.state
== SCE_B_NUMBER
) {
139 sc
.SetState(SCE_B_DEFAULT
);
140 } else if (sc
.state
== SCE_B_HEXNUMBER
) {
141 if (!IsHexDigit(sc
.ch
))
142 sc
.SetState(SCE_B_DEFAULT
);
143 } else if (sc
.state
== SCE_B_BINNUMBER
) {
144 if (!IsBinDigit(sc
.ch
))
145 sc
.SetState(SCE_B_DEFAULT
);
146 } else if (sc
.state
== SCE_B_STRING
) {
148 sc
.ForwardSetState(SCE_B_DEFAULT
);
151 sc
.ChangeState(SCE_B_ERROR
);
152 sc
.SetState(SCE_B_DEFAULT
);
154 } else if (sc
.state
== SCE_B_COMMENT
|| sc
.state
== SCE_B_PREPROCESSOR
) {
156 sc
.SetState(SCE_B_DEFAULT
);
163 if (sc
.state
== SCE_B_DEFAULT
|| sc
.state
== SCE_B_ERROR
) {
164 if (isfirst
&& sc
.Match('.')) {
165 sc
.SetState(SCE_B_LABEL
);
166 } else if (isfirst
&& sc
.Match('#')) {
168 sc
.SetState(SCE_B_IDENTIFIER
);
169 } else if (sc
.Match(comment_char
)) {
170 // Hack to make deprecated QBASIC '$Include show
171 // up in freebasic with SCE_B_PREPROCESSOR.
172 if (comment_char
== '\'' && sc
.Match(comment_char
, '$'))
173 sc
.SetState(SCE_B_PREPROCESSOR
);
175 sc
.SetState(SCE_B_COMMENT
);
176 } else if (sc
.Match('"')) {
177 sc
.SetState(SCE_B_STRING
);
178 } else if (IsDigit(sc
.ch
)) {
179 sc
.SetState(SCE_B_NUMBER
);
180 } else if (sc
.Match('$')) {
181 sc
.SetState(SCE_B_HEXNUMBER
);
182 } else if (sc
.Match('%')) {
183 sc
.SetState(SCE_B_BINNUMBER
);
184 } else if (sc
.Match('#')) {
185 sc
.SetState(SCE_B_CONSTANT
);
186 } else if (IsOperator(sc
.ch
)) {
187 sc
.SetState(SCE_B_OPERATOR
);
188 } else if (IsIdentifier(sc
.ch
)) {
190 sc
.SetState(SCE_B_IDENTIFIER
);
191 } else if (!IsSpace(sc
.ch
)) {
192 sc
.SetState(SCE_B_ERROR
);
205 static int CheckBlitzFoldPoint(char const *token
, int &level
) {
206 if (!strcmp(token
, "function") ||
207 !strcmp(token
, "type")) {
208 level
|= SC_FOLDLEVELHEADERFLAG
;
211 if (!strcmp(token
, "end function") ||
212 !strcmp(token
, "end type")) {
218 static int CheckPureFoldPoint(char const *token
, int &level
) {
219 if (!strcmp(token
, "procedure") ||
220 !strcmp(token
, "enumeration") ||
221 !strcmp(token
, "interface") ||
222 !strcmp(token
, "structure")) {
223 level
|= SC_FOLDLEVELHEADERFLAG
;
226 if (!strcmp(token
, "endprocedure") ||
227 !strcmp(token
, "endenumeration") ||
228 !strcmp(token
, "endinterface") ||
229 !strcmp(token
, "endstructure")) {
235 static int CheckFreeFoldPoint(char const *token
, int &level
) {
236 if (!strcmp(token
, "function") ||
237 !strcmp(token
, "sub") ||
238 !strcmp(token
, "type")) {
239 level
|= SC_FOLDLEVELHEADERFLAG
;
242 if (!strcmp(token
, "end function") ||
243 !strcmp(token
, "end sub") ||
244 !strcmp(token
, "end type")) {
250 static void FoldBasicDoc(unsigned int startPos
, int length
,
251 Accessor
&styler
, int (*CheckFoldPoint
)(char const *, int &)) {
252 int line
= styler
.GetLine(startPos
);
253 int level
= styler
.LevelAt(line
);
254 int go
= 0, done
= 0;
255 int endPos
= startPos
+ length
;
259 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
260 // Scan for tokens at the start of the line (they may include
261 // whitespace, for tokens like "End Function"
262 for (i
= startPos
; i
< endPos
; i
++) {
263 int c
= styler
.SafeGetCharAt(i
);
265 if (wordlen
) { // are we scanning a token already?
266 word
[wordlen
] = static_cast<char>(LowerCase(c
));
267 if (!IsIdentifier(c
)) { // done with token
268 word
[wordlen
] = '\0';
269 go
= CheckFoldPoint(word
, level
);
271 // Treat any whitespace as single blank, for
272 // things like "End Function".
273 if (IsSpace(c
) && IsIdentifier(word
[wordlen
- 1])) {
278 else // done with this line
281 } else if (wordlen
< 255) {
284 } else { // start scanning at first non-whitespace character
286 if (IsIdentifier(c
)) {
287 word
[0] = static_cast<char>(LowerCase(c
));
289 } else // done with this line
294 if (c
== '\n') { // line end
295 if (!done
&& wordlen
== 0 && foldCompact
) // line was only space
296 level
|= SC_FOLDLEVELWHITEFLAG
;
297 if (level
!= styler
.LevelAt(line
))
298 styler
.SetLevel(line
, level
);
303 level
&= ~SC_FOLDLEVELHEADERFLAG
;
304 level
&= ~SC_FOLDLEVELWHITEFLAG
;
311 static void ColouriseBlitzBasicDoc(unsigned int startPos
, int length
, int initStyle
,
312 WordList
*keywordlists
[], Accessor
&styler
) {
313 ColouriseBasicDoc(startPos
, length
, initStyle
, keywordlists
, styler
, ';');
316 static void ColourisePureBasicDoc(unsigned int startPos
, int length
, int initStyle
,
317 WordList
*keywordlists
[], Accessor
&styler
) {
318 ColouriseBasicDoc(startPos
, length
, initStyle
, keywordlists
, styler
, ';');
321 static void ColouriseFreeBasicDoc(unsigned int startPos
, int length
, int initStyle
,
322 WordList
*keywordlists
[], Accessor
&styler
) {
323 ColouriseBasicDoc(startPos
, length
, initStyle
, keywordlists
, styler
, '\'');
326 static void FoldBlitzBasicDoc(unsigned int startPos
, int length
, int,
327 WordList
*[], Accessor
&styler
) {
328 FoldBasicDoc(startPos
, length
, styler
, CheckBlitzFoldPoint
);
331 static void FoldPureBasicDoc(unsigned int startPos
, int length
, int,
332 WordList
*[], Accessor
&styler
) {
333 FoldBasicDoc(startPos
, length
, styler
, CheckPureFoldPoint
);
336 static void FoldFreeBasicDoc(unsigned int startPos
, int length
, int,
337 WordList
*[], Accessor
&styler
) {
338 FoldBasicDoc(startPos
, length
, styler
, CheckFreeFoldPoint
);
341 static const char * const blitzbasicWordListDesc
[] = {
342 "BlitzBasic Keywords",
349 static const char * const purebasicWordListDesc
[] = {
350 "PureBasic Keywords",
351 "PureBasic PreProcessor Keywords",
357 static const char * const freebasicWordListDesc
[] = {
358 "FreeBasic Keywords",
359 "FreeBasic PreProcessor Keywords",
365 LexerModule
lmBlitzBasic(SCLEX_BLITZBASIC
, ColouriseBlitzBasicDoc
, "blitzbasic",
366 FoldBlitzBasicDoc
, blitzbasicWordListDesc
);
368 LexerModule
lmPureBasic(SCLEX_PUREBASIC
, ColourisePureBasicDoc
, "purebasic",
369 FoldPureBasicDoc
, purebasicWordListDesc
);
371 LexerModule
lmFreeBasic(SCLEX_FREEBASIC
, ColouriseFreeBasicDoc
, "freebasic",
372 FoldFreeBasicDoc
, freebasicWordListDesc
);