]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexBasic.cxx
79ba2b89116bc5199f7ed385d524204f6b6d31c4
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"
42 static int character_classification
[128] =
44 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
46 1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 2,
47 60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2,
48 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
49 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4,
50 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
51 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0
54 static bool IsSpace(int c
) {
55 return c
< 128 && (character_classification
[c
] & 1);
58 static bool IsOperator(int c
) {
59 return c
< 128 && (character_classification
[c
] & 2);
62 static bool IsIdentifier(int c
) {
63 return c
< 128 && (character_classification
[c
] & 4);
66 static bool IsDigit(int c
) {
67 return c
< 128 && (character_classification
[c
] & 8);
70 static bool IsHexDigit(int c
) {
71 return c
< 128 && (character_classification
[c
] & 16);
74 static bool IsBinDigit(int c
) {
75 return c
< 128 && (character_classification
[c
] & 32);
78 static int LowerCase(int c
)
80 if (c
>= 'A' && c
<= 'Z')
85 static void ColouriseBasicDoc(unsigned int startPos
, int length
, int initStyle
,
86 WordList
*keywordlists
[], Accessor
&styler
, char comment_char
) {
87 bool wasfirst
= true, isfirst
= true; // true if first token in a line
88 styler
.StartAt(startPos
);
90 StyleContext
sc(startPos
, length
, initStyle
, styler
);
92 // Can't use sc.More() here else we miss the last character
93 for (; ; sc
.Forward()) {
94 if (sc
.state
== SCE_B_IDENTIFIER
) {
95 if (!IsIdentifier(sc
.ch
)) {
97 if (wasfirst
&& sc
.Match(':')) {
98 sc
.ChangeState(SCE_B_LABEL
);
99 sc
.ForwardSetState(SCE_B_DEFAULT
);
108 sc
.GetCurrentLowered(s
, sizeof(s
));
109 for (int i
= 0; i
< 4; i
++) {
110 if (keywordlists
[i
]->InList(s
)) {
111 sc
.ChangeState(kstates
[i
]);
114 // Types, must set them as operator else they will be
115 // matched as number/constant
116 if (sc
.Match('.') || sc
.Match('$') || sc
.Match('%') ||
118 sc
.SetState(SCE_B_OPERATOR
);
120 sc
.SetState(SCE_B_DEFAULT
);
124 } else if (sc
.state
== SCE_B_OPERATOR
) {
125 if (!IsOperator(sc
.ch
) || sc
.Match('#'))
126 sc
.SetState(SCE_B_DEFAULT
);
127 } else if (sc
.state
== SCE_B_LABEL
) {
128 if (!IsIdentifier(sc
.ch
))
129 sc
.SetState(SCE_B_DEFAULT
);
130 } else if (sc
.state
== SCE_B_CONSTANT
) {
131 if (!IsIdentifier(sc
.ch
))
132 sc
.SetState(SCE_B_DEFAULT
);
133 } else if (sc
.state
== SCE_B_NUMBER
) {
135 sc
.SetState(SCE_B_DEFAULT
);
136 } else if (sc
.state
== SCE_B_HEXNUMBER
) {
137 if (!IsHexDigit(sc
.ch
))
138 sc
.SetState(SCE_B_DEFAULT
);
139 } else if (sc
.state
== SCE_B_BINNUMBER
) {
140 if (!IsBinDigit(sc
.ch
))
141 sc
.SetState(SCE_B_DEFAULT
);
142 } else if (sc
.state
== SCE_B_STRING
) {
144 sc
.ForwardSetState(SCE_B_DEFAULT
);
147 sc
.ChangeState(SCE_B_ERROR
);
148 sc
.SetState(SCE_B_DEFAULT
);
150 } else if (sc
.state
== SCE_B_COMMENT
|| sc
.state
== SCE_B_PREPROCESSOR
) {
152 sc
.SetState(SCE_B_DEFAULT
);
159 if (sc
.state
== SCE_B_DEFAULT
|| sc
.state
== SCE_B_ERROR
) {
160 if (isfirst
&& sc
.Match('.')) {
161 sc
.SetState(SCE_B_LABEL
);
162 } else if (isfirst
&& sc
.Match('#')) {
164 sc
.SetState(SCE_B_IDENTIFIER
);
165 } else if (sc
.Match(comment_char
)) {
166 // Hack to make deprecated QBASIC '$Include show
167 // up in freebasic with SCE_B_PREPROCESSOR.
168 if (comment_char
== '\'' && sc
.Match(comment_char
, '$'))
169 sc
.SetState(SCE_B_PREPROCESSOR
);
171 sc
.SetState(SCE_B_COMMENT
);
172 } else if (sc
.Match('"')) {
173 sc
.SetState(SCE_B_STRING
);
174 } else if (IsDigit(sc
.ch
)) {
175 sc
.SetState(SCE_B_NUMBER
);
176 } else if (sc
.Match('$')) {
177 sc
.SetState(SCE_B_HEXNUMBER
);
178 } else if (sc
.Match('%')) {
179 sc
.SetState(SCE_B_BINNUMBER
);
180 } else if (sc
.Match('#')) {
181 sc
.SetState(SCE_B_CONSTANT
);
182 } else if (IsOperator(sc
.ch
)) {
183 sc
.SetState(SCE_B_OPERATOR
);
184 } else if (IsIdentifier(sc
.ch
)) {
186 sc
.SetState(SCE_B_IDENTIFIER
);
187 } else if (!IsSpace(sc
.ch
)) {
188 sc
.SetState(SCE_B_ERROR
);
201 static int CheckBlitzFoldPoint(char const *token
, int &level
) {
202 if (!strcmp(token
, "function") ||
203 !strcmp(token
, "type")) {
204 level
|= SC_FOLDLEVELHEADERFLAG
;
207 if (!strcmp(token
, "end function") ||
208 !strcmp(token
, "end type")) {
214 static int CheckPureFoldPoint(char const *token
, int &level
) {
215 if (!strcmp(token
, "procedure") ||
216 !strcmp(token
, "enumeration") ||
217 !strcmp(token
, "interface") ||
218 !strcmp(token
, "structure")) {
219 level
|= SC_FOLDLEVELHEADERFLAG
;
222 if (!strcmp(token
, "endprocedure") ||
223 !strcmp(token
, "endenumeration") ||
224 !strcmp(token
, "endinterface") ||
225 !strcmp(token
, "endstructure")) {
231 static int CheckFreeFoldPoint(char const *token
, int &level
) {
232 if (!strcmp(token
, "function") ||
233 !strcmp(token
, "sub") ||
234 !strcmp(token
, "type")) {
235 level
|= SC_FOLDLEVELHEADERFLAG
;
238 if (!strcmp(token
, "end function") ||
239 !strcmp(token
, "end sub") ||
240 !strcmp(token
, "end type")) {
246 static void FoldBasicDoc(unsigned int startPos
, int length
,
247 Accessor
&styler
, int (*CheckFoldPoint
)(char const *, int &)) {
248 int line
= styler
.GetLine(startPos
);
249 int level
= styler
.LevelAt(line
);
250 int go
= 0, done
= 0;
251 int endPos
= startPos
+ length
;
255 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
256 // Scan for tokens at the start of the line (they may include
257 // whitespace, for tokens like "End Function"
258 for (i
= startPos
; i
< endPos
; i
++) {
259 int c
= styler
.SafeGetCharAt(i
);
261 if (wordlen
) { // are we scanning a token already?
262 word
[wordlen
] = static_cast<char>(LowerCase(c
));
263 if (!IsIdentifier(c
)) { // done with token
264 word
[wordlen
] = '\0';
265 go
= CheckFoldPoint(word
, level
);
267 // Treat any whitespace as single blank, for
268 // things like "End Function".
269 if (IsSpace(c
) && IsIdentifier(word
[wordlen
- 1])) {
274 else // done with this line
277 } else if (wordlen
< 255) {
280 } else { // start scanning at first non-whitespace character
282 if (IsIdentifier(c
)) {
283 word
[0] = static_cast<char>(LowerCase(c
));
285 } else // done with this line
290 if (c
== '\n') { // line end
291 if (!done
&& wordlen
== 0 && foldCompact
) // line was only space
292 level
|= SC_FOLDLEVELWHITEFLAG
;
293 if (level
!= styler
.LevelAt(line
))
294 styler
.SetLevel(line
, level
);
299 level
&= ~SC_FOLDLEVELHEADERFLAG
;
300 level
&= ~SC_FOLDLEVELWHITEFLAG
;
307 static void ColouriseBlitzBasicDoc(unsigned int startPos
, int length
, int initStyle
,
308 WordList
*keywordlists
[], Accessor
&styler
) {
309 ColouriseBasicDoc(startPos
, length
, initStyle
, keywordlists
, styler
, ';');
312 static void ColourisePureBasicDoc(unsigned int startPos
, int length
, int initStyle
,
313 WordList
*keywordlists
[], Accessor
&styler
) {
314 ColouriseBasicDoc(startPos
, length
, initStyle
, keywordlists
, styler
, ';');
317 static void ColouriseFreeBasicDoc(unsigned int startPos
, int length
, int initStyle
,
318 WordList
*keywordlists
[], Accessor
&styler
) {
319 ColouriseBasicDoc(startPos
, length
, initStyle
, keywordlists
, styler
, '\'');
322 static void FoldBlitzBasicDoc(unsigned int startPos
, int length
, int,
323 WordList
*[], Accessor
&styler
) {
324 FoldBasicDoc(startPos
, length
, styler
, CheckBlitzFoldPoint
);
327 static void FoldPureBasicDoc(unsigned int startPos
, int length
, int,
328 WordList
*[], Accessor
&styler
) {
329 FoldBasicDoc(startPos
, length
, styler
, CheckPureFoldPoint
);
332 static void FoldFreeBasicDoc(unsigned int startPos
, int length
, int,
333 WordList
*[], Accessor
&styler
) {
334 FoldBasicDoc(startPos
, length
, styler
, CheckFreeFoldPoint
);
337 static const char * const blitzbasicWordListDesc
[] = {
338 "BlitzBasic Keywords",
345 static const char * const purebasicWordListDesc
[] = {
346 "PureBasic Keywords",
347 "PureBasic PreProcessor Keywords",
353 static const char * const freebasicWordListDesc
[] = {
354 "FreeBasic Keywords",
355 "FreeBasic PreProcessor Keywords",
361 LexerModule
lmBlitzBasic(SCLEX_BLITZBASIC
, ColouriseBlitzBasicDoc
, "blitzbasic",
362 FoldBlitzBasicDoc
, blitzbasicWordListDesc
);
364 LexerModule
lmPureBasic(SCLEX_PUREBASIC
, ColourisePureBasicDoc
, "purebasic",
365 FoldPureBasicDoc
, purebasicWordListDesc
);
367 LexerModule
lmFreeBasic(SCLEX_FREEBASIC
, ColouriseFreeBasicDoc
, "freebasic",
368 FoldFreeBasicDoc
, freebasicWordListDesc
);