OSDN Git Service

Commit DialogBox compile Okay
[tortoisegit/TortoiseGitJp.git] / ext / scintilla / src / LexBasic.cxx
1 // Scintilla source code edit control\r
2 /** @file LexBasic.cxx\r
3  ** Lexer for BlitzBasic and PureBasic.\r
4  **/\r
5 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>\r
6 // The License.txt file describes the conditions under which this software may be distributed.\r
7 \r
8 // This tries to be a unified Lexer/Folder for all the BlitzBasic/BlitzMax/PurBasic basics\r
9 // and derivatives. Once they diverge enough, might want to split it into multiple\r
10 // lexers for more code clearity.\r
11 //\r
12 // Mail me (elias <at> users <dot> sf <dot> net) for any bugs.\r
13 \r
14 // Folding only works for simple things like functions or types.\r
15 \r
16 // You may want to have a look at my ctags lexer as well, if you additionally to coloring\r
17 // and folding need to extract things like label tags in your editor.\r
18 \r
19 #include <stdlib.h>\r
20 #include <string.h>\r
21 #include <stdio.h>\r
22 #include <ctype.h>\r
23 #include <stdarg.h>\r
24 \r
25 #include "Platform.h"\r
26 \r
27 #include "PropSet.h"\r
28 #include "Accessor.h"\r
29 #include "StyleContext.h"\r
30 #include "KeyWords.h"\r
31 #include "Scintilla.h"\r
32 #include "SciLexer.h"\r
33 \r
34 #ifdef SCI_NAMESPACE\r
35 using namespace Scintilla;\r
36 #endif\r
37 \r
38 /* Bits:\r
39  * 1  - whitespace\r
40  * 2  - operator\r
41  * 4  - identifier\r
42  * 8  - decimal digit\r
43  * 16 - hex digit\r
44  * 32 - bin digit\r
45  */\r
46 static int character_classification[128] =\r
47 {\r
48     0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0,  0,  1,  0,  0,\r
49     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,\r
50     1,  2,  0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  10, 2,\r
51     60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2,  2,  2,  2,  2,  2,\r
52     2,  20, 20, 20, 20, 20, 20, 4,  4,  4,  4,  4,  4,  4,  4,  4,\r
53     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  2,  4,\r
54     2,  20, 20, 20, 20, 20, 20, 4,  4,  4,  4,  4,  4,  4,  4,  4,\r
55     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  2,  0\r
56 };\r
57 \r
58 static bool IsSpace(int c) {\r
59         return c < 128 && (character_classification[c] & 1);\r
60 }\r
61 \r
62 static bool IsOperator(int c) {\r
63         return c < 128 && (character_classification[c] & 2);\r
64 }\r
65 \r
66 static bool IsIdentifier(int c) {\r
67         return c < 128 && (character_classification[c] & 4);\r
68 }\r
69 \r
70 static bool IsDigit(int c) {\r
71         return c < 128 && (character_classification[c] & 8);\r
72 }\r
73 \r
74 static bool IsHexDigit(int c) {\r
75         return c < 128 && (character_classification[c] & 16);\r
76 }\r
77 \r
78 static bool IsBinDigit(int c) {\r
79         return c < 128 && (character_classification[c] & 32);\r
80 }\r
81 \r
82 static int LowerCase(int c)\r
83 {\r
84         if (c >= 'A' && c <= 'Z')\r
85                 return 'a' + c - 'A';\r
86         return c;\r
87 }\r
88 \r
89 static void ColouriseBasicDoc(unsigned int startPos, int length, int initStyle,\r
90                            WordList *keywordlists[], Accessor &styler, char comment_char) {\r
91         bool wasfirst = true, isfirst = true; // true if first token in a line\r
92         styler.StartAt(startPos);\r
93 \r
94         StyleContext sc(startPos, length, initStyle, styler);\r
95 \r
96         // Can't use sc.More() here else we miss the last character\r
97         for (; ; sc.Forward()) {\r
98                 if (sc.state == SCE_B_IDENTIFIER) {\r
99                         if (!IsIdentifier(sc.ch)) {\r
100                                 // Labels\r
101                                 if (wasfirst && sc.Match(':')) {\r
102                                         sc.ChangeState(SCE_B_LABEL);\r
103                                         sc.ForwardSetState(SCE_B_DEFAULT);\r
104                                 } else {\r
105                                         char s[100];\r
106                                         int kstates[4] = {\r
107                                                 SCE_B_KEYWORD,\r
108                                                 SCE_B_KEYWORD2,\r
109                                                 SCE_B_KEYWORD3,\r
110                                                 SCE_B_KEYWORD4,\r
111                                         };\r
112                                         sc.GetCurrentLowered(s, sizeof(s));\r
113                                         for (int i = 0; i < 4; i++) {\r
114                                                 if (keywordlists[i]->InList(s)) {\r
115                                                         sc.ChangeState(kstates[i]);\r
116                                                 }\r
117                                         }\r
118                                         // Types, must set them as operator else they will be\r
119                                         // matched as number/constant\r
120                                         if (sc.Match('.') || sc.Match('$') || sc.Match('%') ||\r
121                                                 sc.Match('#')) {\r
122                                                 sc.SetState(SCE_B_OPERATOR);\r
123                                         } else {\r
124                                                 sc.SetState(SCE_B_DEFAULT);\r
125                                         }\r
126                                 }\r
127                         }\r
128                 } else if (sc.state == SCE_B_OPERATOR) {\r
129                         if (!IsOperator(sc.ch) || sc.Match('#'))\r
130                                 sc.SetState(SCE_B_DEFAULT);\r
131                 } else if (sc.state == SCE_B_LABEL) {\r
132                         if (!IsIdentifier(sc.ch))\r
133                                 sc.SetState(SCE_B_DEFAULT);\r
134                 } else if (sc.state == SCE_B_CONSTANT) {\r
135                         if (!IsIdentifier(sc.ch))\r
136                                 sc.SetState(SCE_B_DEFAULT);\r
137                 } else if (sc.state == SCE_B_NUMBER) {\r
138                         if (!IsDigit(sc.ch))\r
139                                 sc.SetState(SCE_B_DEFAULT);\r
140                 } else if (sc.state == SCE_B_HEXNUMBER) {\r
141                         if (!IsHexDigit(sc.ch))\r
142                                 sc.SetState(SCE_B_DEFAULT);\r
143                 } else if (sc.state == SCE_B_BINNUMBER) {\r
144                         if (!IsBinDigit(sc.ch))\r
145                                 sc.SetState(SCE_B_DEFAULT);\r
146                 } else if (sc.state == SCE_B_STRING) {\r
147                         if (sc.ch == '"') {\r
148                                 sc.ForwardSetState(SCE_B_DEFAULT);\r
149                         }\r
150                         if (sc.atLineEnd) {\r
151                                 sc.ChangeState(SCE_B_ERROR);\r
152                                 sc.SetState(SCE_B_DEFAULT);\r
153                         }\r
154                 } else if (sc.state == SCE_B_COMMENT || sc.state == SCE_B_PREPROCESSOR) {\r
155                         if (sc.atLineEnd) {\r
156                                 sc.SetState(SCE_B_DEFAULT);\r
157                         }\r
158                 }\r
159 \r
160                 if (sc.atLineStart)\r
161                         isfirst = true;\r
162 \r
163                 if (sc.state == SCE_B_DEFAULT || sc.state == SCE_B_ERROR) {\r
164                         if (isfirst && sc.Match('.')) {\r
165                                 sc.SetState(SCE_B_LABEL);\r
166                         } else if (isfirst && sc.Match('#')) {\r
167                                 wasfirst = isfirst;\r
168                                 sc.SetState(SCE_B_IDENTIFIER);\r
169                         } else if (sc.Match(comment_char)) {\r
170                                 // Hack to make deprecated QBASIC '$Include show\r
171                                 // up in freebasic with SCE_B_PREPROCESSOR.\r
172                                 if (comment_char == '\'' && sc.Match(comment_char, '$'))\r
173                                         sc.SetState(SCE_B_PREPROCESSOR);\r
174                                 else\r
175                                         sc.SetState(SCE_B_COMMENT);\r
176                         } else if (sc.Match('"')) {\r
177                                 sc.SetState(SCE_B_STRING);\r
178                         } else if (IsDigit(sc.ch)) {\r
179                                 sc.SetState(SCE_B_NUMBER);\r
180                         } else if (sc.Match('$')) {\r
181                                 sc.SetState(SCE_B_HEXNUMBER);\r
182                         } else if (sc.Match('%')) {\r
183                                 sc.SetState(SCE_B_BINNUMBER);\r
184                         } else if (sc.Match('#')) {\r
185                                 sc.SetState(SCE_B_CONSTANT);\r
186                         } else if (IsOperator(sc.ch)) {\r
187                                 sc.SetState(SCE_B_OPERATOR);\r
188                         } else if (IsIdentifier(sc.ch)) {\r
189                                 wasfirst = isfirst;\r
190                                 sc.SetState(SCE_B_IDENTIFIER);\r
191                         } else if (!IsSpace(sc.ch)) {\r
192                                 sc.SetState(SCE_B_ERROR);\r
193                         }\r
194                 }\r
195 \r
196                 if (!IsSpace(sc.ch))\r
197                         isfirst = false;\r
198 \r
199                 if (!sc.More())\r
200                         break;\r
201         }\r
202         sc.Complete();\r
203 }\r
204 \r
205 static int CheckBlitzFoldPoint(char const *token, int &level) {\r
206         if (!strcmp(token, "function") ||\r
207                 !strcmp(token, "type")) {\r
208                 level |= SC_FOLDLEVELHEADERFLAG;\r
209                 return 1;\r
210         }\r
211         if (!strcmp(token, "end function") ||\r
212                 !strcmp(token, "end type")) {\r
213                 return -1;\r
214         }\r
215         return 0;\r
216 }\r
217 \r
218 static int CheckPureFoldPoint(char const *token, int &level) {\r
219         if (!strcmp(token, "procedure") ||\r
220                 !strcmp(token, "enumeration") ||\r
221                 !strcmp(token, "interface") ||\r
222                 !strcmp(token, "structure")) {\r
223                 level |= SC_FOLDLEVELHEADERFLAG;\r
224                 return 1;\r
225         }\r
226         if (!strcmp(token, "endprocedure") ||\r
227                 !strcmp(token, "endenumeration") ||\r
228                 !strcmp(token, "endinterface") ||\r
229                 !strcmp(token, "endstructure")) {\r
230                 return -1;\r
231         }\r
232         return 0;\r
233 }\r
234 \r
235 static int CheckFreeFoldPoint(char const *token, int &level) {\r
236         if (!strcmp(token, "function") ||\r
237                 !strcmp(token, "sub") ||\r
238                 !strcmp(token, "type")) {\r
239                 level |= SC_FOLDLEVELHEADERFLAG;\r
240                 return 1;\r
241         }\r
242         if (!strcmp(token, "end function") ||\r
243                 !strcmp(token, "end sub") ||\r
244                 !strcmp(token, "end type")) {\r
245                 return -1;\r
246         }\r
247         return 0;\r
248 }\r
249 \r
250 static void FoldBasicDoc(unsigned int startPos, int length,\r
251         Accessor &styler, int (*CheckFoldPoint)(char const *, int &)) {\r
252         int line = styler.GetLine(startPos);\r
253         int level = styler.LevelAt(line);\r
254         int go = 0, done = 0;\r
255         int endPos = startPos + length;\r
256         char word[256];\r
257         int wordlen = 0;\r
258         int i;\r
259         bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;\r
260         // Scan for tokens at the start of the line (they may include\r
261         // whitespace, for tokens like "End Function"\r
262         for (i = startPos; i < endPos; i++) {\r
263                 int c = styler.SafeGetCharAt(i);\r
264                 if (!done && !go) {\r
265                         if (wordlen) { // are we scanning a token already?\r
266                                 word[wordlen] = static_cast<char>(LowerCase(c));\r
267                                 if (!IsIdentifier(c)) { // done with token\r
268                                         word[wordlen] = '\0';\r
269                                         go = CheckFoldPoint(word, level);\r
270                                         if (!go) {\r
271                                                 // Treat any whitespace as single blank, for\r
272                                                 // things like "End   Function".\r
273                                                 if (IsSpace(c) && IsIdentifier(word[wordlen - 1])) {\r
274                                                         word[wordlen] = ' ';\r
275                                                         if (wordlen < 255)\r
276                                                                 wordlen++;\r
277                                                 }\r
278                                                 else // done with this line\r
279                                                         done = 1;\r
280                                         }\r
281                                 } else if (wordlen < 255) {\r
282                                         wordlen++;\r
283                                 }\r
284                         } else { // start scanning at first non-whitespace character\r
285                                 if (!IsSpace(c)) {\r
286                                         if (IsIdentifier(c)) {\r
287                                                 word[0] = static_cast<char>(LowerCase(c));\r
288                                                 wordlen = 1;\r
289                                         } else // done with this line\r
290                                                 done = 1;\r
291                                 }\r
292                         }\r
293                 }\r
294                 if (c == '\n') { // line end\r
295                         if (!done && wordlen == 0 && foldCompact) // line was only space\r
296                                 level |= SC_FOLDLEVELWHITEFLAG;\r
297                         if (level != styler.LevelAt(line))\r
298                                 styler.SetLevel(line, level);\r
299                         level += go;\r
300                         line++;\r
301                         // reset state\r
302                         wordlen = 0;\r
303                         level &= ~SC_FOLDLEVELHEADERFLAG;\r
304                         level &= ~SC_FOLDLEVELWHITEFLAG;\r
305                         go = 0;\r
306                         done = 0;\r
307                 }\r
308         }\r
309 }\r
310 \r
311 static void ColouriseBlitzBasicDoc(unsigned int startPos, int length, int initStyle,\r
312                            WordList *keywordlists[], Accessor &styler) {\r
313         ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, ';');\r
314 }\r
315 \r
316 static void ColourisePureBasicDoc(unsigned int startPos, int length, int initStyle,\r
317                            WordList *keywordlists[], Accessor &styler) {\r
318         ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, ';');\r
319 }\r
320 \r
321 static void ColouriseFreeBasicDoc(unsigned int startPos, int length, int initStyle,\r
322                            WordList *keywordlists[], Accessor &styler) {\r
323         ColouriseBasicDoc(startPos, length, initStyle, keywordlists, styler, '\'');\r
324 }\r
325 \r
326 static void FoldBlitzBasicDoc(unsigned int startPos, int length, int,\r
327         WordList *[], Accessor &styler) {\r
328         FoldBasicDoc(startPos, length, styler, CheckBlitzFoldPoint);\r
329 }\r
330 \r
331 static void FoldPureBasicDoc(unsigned int startPos, int length, int,\r
332         WordList *[], Accessor &styler) {\r
333         FoldBasicDoc(startPos, length, styler, CheckPureFoldPoint);\r
334 }\r
335 \r
336 static void FoldFreeBasicDoc(unsigned int startPos, int length, int,\r
337         WordList *[], Accessor &styler) {\r
338         FoldBasicDoc(startPos, length, styler, CheckFreeFoldPoint);\r
339 }\r
340 \r
341 static const char * const blitzbasicWordListDesc[] = {\r
342         "BlitzBasic Keywords",\r
343         "user1",\r
344         "user2",\r
345         "user3",\r
346         0\r
347 };\r
348 \r
349 static const char * const purebasicWordListDesc[] = {\r
350         "PureBasic Keywords",\r
351         "PureBasic PreProcessor Keywords",\r
352         "user defined 1",\r
353         "user defined 2",\r
354         0\r
355 };\r
356 \r
357 static const char * const freebasicWordListDesc[] = {\r
358         "FreeBasic Keywords",\r
359         "FreeBasic PreProcessor Keywords",\r
360         "user defined 1",\r
361         "user defined 2",\r
362         0\r
363 };\r
364 \r
365 LexerModule lmBlitzBasic(SCLEX_BLITZBASIC, ColouriseBlitzBasicDoc, "blitzbasic",\r
366         FoldBlitzBasicDoc, blitzbasicWordListDesc);\r
367 \r
368 LexerModule lmPureBasic(SCLEX_PUREBASIC, ColourisePureBasicDoc, "purebasic",\r
369         FoldPureBasicDoc, purebasicWordListDesc);\r
370 \r
371 LexerModule lmFreeBasic(SCLEX_FREEBASIC, ColouriseFreeBasicDoc, "freebasic",\r
372         FoldFreeBasicDoc, freebasicWordListDesc);\r
373 \r