]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexVHDL.cxx
Don't document wxSortedArrayString as deriving from wxArrayString.
[wxWidgets.git] / src / stc / scintilla / lexers / LexVHDL.cxx
1 // Scintilla source code edit control
2 /** @file LexVHDL.cxx
3 ** Lexer for VHDL
4 ** Written by Phil Reid,
5 ** Based on:
6 ** - The Verilog Lexer by Avi Yegudin
7 ** - The Fortran Lexer by Chuan-jian Shen
8 ** - The C++ lexer by Neil Hodgson
9 **/
10 // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
11 // The License.txt file describes the conditions under which this software may be distributed.
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <stdio.h>
17 #include <stdarg.h>
18 #include <assert.h>
19
20 #include "ILexer.h"
21 #include "Scintilla.h"
22 #include "SciLexer.h"
23
24 #include "WordList.h"
25 #include "LexAccessor.h"
26 #include "Accessor.h"
27 #include "StyleContext.h"
28 #include "CharacterSet.h"
29 #include "LexerModule.h"
30
31 #ifdef SCI_NAMESPACE
32 using namespace Scintilla;
33 #endif
34
35 static void ColouriseVHDLDoc(
36 unsigned int startPos,
37 int length,
38 int initStyle,
39 WordList *keywordlists[],
40 Accessor &styler);
41
42
43 /***************************************/
44 static inline bool IsAWordChar(const int ch) {
45 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' );
46 }
47
48 /***************************************/
49 static inline bool IsAWordStart(const int ch) {
50 return (ch < 0x80) && (isalnum(ch) || ch == '_');
51 }
52
53 /***************************************/
54 inline bool IsABlank(unsigned int ch) {
55 return (ch == ' ') || (ch == 0x09) || (ch == 0x0b) ;
56 }
57
58 /***************************************/
59 static void ColouriseVHDLDoc(
60 unsigned int startPos,
61 int length,
62 int initStyle,
63 WordList *keywordlists[],
64 Accessor &styler)
65 {
66 WordList &Keywords = *keywordlists[0];
67 WordList &Operators = *keywordlists[1];
68 WordList &Attributes = *keywordlists[2];
69 WordList &Functions = *keywordlists[3];
70 WordList &Packages = *keywordlists[4];
71 WordList &Types = *keywordlists[5];
72 WordList &User = *keywordlists[6];
73
74 StyleContext sc(startPos, length, initStyle, styler);
75
76 for (; sc.More(); sc.Forward())
77 {
78
79 // Determine if the current state should terminate.
80 if (sc.state == SCE_VHDL_OPERATOR) {
81 sc.SetState(SCE_VHDL_DEFAULT);
82 } else if (sc.state == SCE_VHDL_NUMBER) {
83 if (!IsAWordChar(sc.ch) && (sc.ch != '#')) {
84 sc.SetState(SCE_VHDL_DEFAULT);
85 }
86 } else if (sc.state == SCE_VHDL_IDENTIFIER) {
87 if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
88 char s[100];
89 sc.GetCurrentLowered(s, sizeof(s));
90 if (Keywords.InList(s)) {
91 sc.ChangeState(SCE_VHDL_KEYWORD);
92 } else if (Operators.InList(s)) {
93 sc.ChangeState(SCE_VHDL_STDOPERATOR);
94 } else if (Attributes.InList(s)) {
95 sc.ChangeState(SCE_VHDL_ATTRIBUTE);
96 } else if (Functions.InList(s)) {
97 sc.ChangeState(SCE_VHDL_STDFUNCTION);
98 } else if (Packages.InList(s)) {
99 sc.ChangeState(SCE_VHDL_STDPACKAGE);
100 } else if (Types.InList(s)) {
101 sc.ChangeState(SCE_VHDL_STDTYPE);
102 } else if (User.InList(s)) {
103 sc.ChangeState(SCE_VHDL_USERWORD);
104 }
105 sc.SetState(SCE_VHDL_DEFAULT);
106 }
107 } else if (sc.state == SCE_VHDL_COMMENT || sc.state == SCE_VHDL_COMMENTLINEBANG) {
108 if (sc.atLineEnd) {
109 sc.SetState(SCE_VHDL_DEFAULT);
110 }
111 } else if (sc.state == SCE_VHDL_STRING) {
112 if (sc.ch == '\\') {
113 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
114 sc.Forward();
115 }
116 } else if (sc.ch == '\"') {
117 sc.ForwardSetState(SCE_VHDL_DEFAULT);
118 } else if (sc.atLineEnd) {
119 sc.ChangeState(SCE_VHDL_STRINGEOL);
120 sc.ForwardSetState(SCE_VHDL_DEFAULT);
121 }
122 }
123
124 // Determine if a new state should be entered.
125 if (sc.state == SCE_VHDL_DEFAULT) {
126 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
127 sc.SetState(SCE_VHDL_NUMBER);
128 } else if (IsAWordStart(sc.ch)) {
129 sc.SetState(SCE_VHDL_IDENTIFIER);
130 } else if (sc.Match('-', '-')) {
131 if (sc.Match("--!")) // Nice to have a different comment style
132 sc.SetState(SCE_VHDL_COMMENTLINEBANG);
133 else
134 sc.SetState(SCE_VHDL_COMMENT);
135 } else if (sc.ch == '\"') {
136 sc.SetState(SCE_VHDL_STRING);
137 } else if (isoperator(static_cast<char>(sc.ch))) {
138 sc.SetState(SCE_VHDL_OPERATOR);
139 }
140 }
141 }
142 sc.Complete();
143 }
144 //=============================================================================
145 static bool IsCommentLine(int line, Accessor &styler) {
146 int pos = styler.LineStart(line);
147 int eol_pos = styler.LineStart(line + 1) - 1;
148 for (int i = pos; i < eol_pos; i++) {
149 char ch = styler[i];
150 char chNext = styler[i+1];
151 if ((ch == '-') && (chNext == '-'))
152 return true;
153 else if (ch != ' ' && ch != '\t')
154 return false;
155 }
156 return false;
157 }
158
159 //=============================================================================
160 // Folding the code
161 static void FoldNoBoxVHDLDoc(
162 unsigned int startPos,
163 int length,
164 int,
165 Accessor &styler)
166 {
167 // Decided it would be smarter to have the lexer have all keywords included. Therefore I
168 // don't check if the style for the keywords that I use to adjust the levels.
169 char words[] =
170 "architecture begin case component else elsif end entity generate loop package process record then "
171 "procedure function when";
172 WordList keywords;
173 keywords.Set(words);
174
175 bool foldComment = styler.GetPropertyInt("fold.comment", 1) != 0;
176 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
177 bool foldAtElse = styler.GetPropertyInt("fold.at.else", 1) != 0;
178 bool foldAtBegin = styler.GetPropertyInt("fold.at.Begin", 1) != 0;
179 bool foldAtParenthese = styler.GetPropertyInt("fold.at.Parenthese", 1) != 0;
180 //bool foldAtWhen = styler.GetPropertyInt("fold.at.When", 1) != 0; //< fold at when in case statements
181
182 int visibleChars = 0;
183 unsigned int endPos = startPos + length;
184
185 int lineCurrent = styler.GetLine(startPos);
186 int levelCurrent = SC_FOLDLEVELBASE;
187 if(lineCurrent > 0)
188 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
189 //int levelMinCurrent = levelCurrent;
190 int levelMinCurrentElse = levelCurrent; //< Used for folding at 'else'
191 int levelMinCurrentBegin = levelCurrent; //< Used for folding at 'begin'
192 int levelNext = levelCurrent;
193
194 /***************************************/
195 int lastStart = 0;
196 char prevWord[32] = "";
197
198 /***************************************/
199 // Find prev word
200 // The logic for going up or down a level depends on a the previous keyword
201 // This code could be cleaned up.
202 int end = 0;
203 unsigned int j;
204 for(j = startPos; j>0; j--)
205 {
206 char ch = styler.SafeGetCharAt(j);
207 char chPrev = styler.SafeGetCharAt(j-1);
208 int style = styler.StyleAt(j);
209 int stylePrev = styler.StyleAt(j-1);
210 if ((stylePrev != SCE_VHDL_COMMENT) && (stylePrev != SCE_VHDL_STRING))
211 {
212 if(IsAWordChar(chPrev) && !IsAWordChar(ch))
213 {
214 end = j-1;
215 }
216 }
217 if ((style != SCE_VHDL_COMMENT) && (style != SCE_VHDL_STRING))
218 {
219 if(!IsAWordChar(chPrev) && IsAWordStart(ch) && (end != 0))
220 {
221 char s[32];
222 unsigned int k;
223 for(k=0; (k<31 ) && (k<end-j+1 ); k++) {
224 s[k] = static_cast<char>(tolower(styler[j+k]));
225 }
226 s[k] = '\0';
227
228 if(keywords.InList(s)) {
229 strcpy(prevWord, s);
230 break;
231 }
232 }
233 }
234 }
235 for(j=j+static_cast<unsigned int>(strlen(prevWord)); j<endPos; j++)
236 {
237 char ch = styler.SafeGetCharAt(j);
238 int style = styler.StyleAt(j);
239 if ((style != SCE_VHDL_COMMENT) && (style != SCE_VHDL_STRING))
240 {
241 if((ch == ';') && (strcmp(prevWord, "end") == 0))
242 {
243 strcpy(prevWord, ";");
244 }
245 }
246 }
247
248 char chNext = styler[startPos];
249 char chPrev = '\0';
250 char chNextNonBlank;
251 int styleNext = styler.StyleAt(startPos);
252 //Platform::DebugPrintf("Line[%04d] Prev[%20s] ************************* Level[%x]\n", lineCurrent+1, prevWord, levelCurrent);
253
254 /***************************************/
255 for (unsigned int i = startPos; i < endPos; i++)
256 {
257 char ch = chNext;
258 chNext = styler.SafeGetCharAt(i + 1);
259 chPrev = styler.SafeGetCharAt(i - 1);
260 chNextNonBlank = chNext;
261 unsigned int j = i+1;
262 while(IsABlank(chNextNonBlank) && j<endPos)
263 {
264 j ++ ;
265 chNextNonBlank = styler.SafeGetCharAt(j);
266 }
267 int style = styleNext;
268 styleNext = styler.StyleAt(i + 1);
269 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
270
271 if (foldComment && atEOL && IsCommentLine(lineCurrent, styler))
272 {
273 if(!IsCommentLine(lineCurrent-1, styler) && IsCommentLine(lineCurrent+1, styler))
274 {
275 levelNext++;
276 }
277 else if(IsCommentLine(lineCurrent-1, styler) && !IsCommentLine(lineCurrent+1, styler))
278 {
279 levelNext--;
280 }
281 }
282
283 if ((style == SCE_VHDL_OPERATOR) && foldAtParenthese)
284 {
285 if(ch == '(') {
286 levelNext++;
287 } else if (ch == ')') {
288 levelNext--;
289 }
290 }
291
292 if ((style != SCE_VHDL_COMMENT) && (style != SCE_VHDL_STRING))
293 {
294 if((ch == ';') && (strcmp(prevWord, "end") == 0))
295 {
296 strcpy(prevWord, ";");
297 }
298
299 if(!IsAWordChar(chPrev) && IsAWordStart(ch))
300 {
301 lastStart = i;
302 }
303
304 if(iswordchar(ch) && !iswordchar(chNext)) {
305 char s[32];
306 unsigned int k;
307 for(k=0; (k<31 ) && (k<i-lastStart+1 ); k++) {
308 s[k] = static_cast<char>(tolower(styler[lastStart+k]));
309 }
310 s[k] = '\0';
311
312 if(keywords.InList(s))
313 {
314 if (
315 strcmp(s, "architecture") == 0 ||
316 strcmp(s, "case") == 0 ||
317 strcmp(s, "component") == 0 ||
318 strcmp(s, "entity") == 0 ||
319 strcmp(s, "generate") == 0 ||
320 strcmp(s, "loop") == 0 ||
321 strcmp(s, "package") ==0 ||
322 strcmp(s, "process") == 0 ||
323 strcmp(s, "record") == 0 ||
324 strcmp(s, "then") == 0)
325 {
326 if (strcmp(prevWord, "end") != 0)
327 {
328 if (levelMinCurrentElse > levelNext) {
329 levelMinCurrentElse = levelNext;
330 }
331 levelNext++;
332 }
333 } else if (
334 strcmp(s, "procedure") == 0 ||
335 strcmp(s, "function") == 0)
336 {
337 if (strcmp(prevWord, "end") != 0) // check for "end procedure" etc.
338 { // This code checks to see if the procedure / function is a definition within a "package"
339 // rather than the actual code in the body.
340 int BracketLevel = 0;
341 for(int j=i+1; j<styler.Length(); j++)
342 {
343 int LocalStyle = styler.StyleAt(j);
344 char LocalCh = styler.SafeGetCharAt(j);
345 if(LocalCh == '(') BracketLevel++;
346 if(LocalCh == ')') BracketLevel--;
347 if(
348 (BracketLevel == 0) &&
349 (LocalStyle != SCE_VHDL_COMMENT) &&
350 (LocalStyle != SCE_VHDL_STRING) &&
351 !iswordchar(styler.SafeGetCharAt(j-1)) &&
352 styler.Match(j, "is") &&
353 !iswordchar(styler.SafeGetCharAt(j+2)))
354 {
355 if (levelMinCurrentElse > levelNext) {
356 levelMinCurrentElse = levelNext;
357 }
358 levelNext++;
359 break;
360 }
361 if((BracketLevel == 0) && (LocalCh == ';'))
362 {
363 break;
364 }
365 }
366 }
367
368 } else if (strcmp(s, "end") == 0) {
369 levelNext--;
370 } else if(strcmp(s, "elsif") == 0) { // elsif is followed by then so folding occurs correctly
371 levelNext--;
372 } else if (strcmp(s, "else") == 0) {
373 if(strcmp(prevWord, "when") != 0) // ignore a <= x when y else z;
374 {
375 levelMinCurrentElse = levelNext - 1; // VHDL else is all on its own so just dec. the min level
376 }
377 } else if(
378 ((strcmp(s, "begin") == 0) && (strcmp(prevWord, "architecture") == 0)) ||
379 ((strcmp(s, "begin") == 0) && (strcmp(prevWord, "function") == 0)) ||
380 ((strcmp(s, "begin") == 0) && (strcmp(prevWord, "procedure") == 0)))
381 {
382 levelMinCurrentBegin = levelNext - 1;
383 }
384 //Platform::DebugPrintf("Line[%04d] Prev[%20s] Cur[%20s] Level[%x]\n", lineCurrent+1, prevWord, s, levelCurrent);
385 strcpy(prevWord, s);
386 }
387 }
388 }
389 if (atEOL) {
390 int levelUse = levelCurrent;
391
392 if (foldAtElse && (levelMinCurrentElse < levelUse)) {
393 levelUse = levelMinCurrentElse;
394 }
395 if (foldAtBegin && (levelMinCurrentBegin < levelUse)) {
396 levelUse = levelMinCurrentBegin;
397 }
398 int lev = levelUse | levelNext << 16;
399 if (visibleChars == 0 && foldCompact)
400 lev |= SC_FOLDLEVELWHITEFLAG;
401
402 if (levelUse < levelNext)
403 lev |= SC_FOLDLEVELHEADERFLAG;
404 if (lev != styler.LevelAt(lineCurrent)) {
405 styler.SetLevel(lineCurrent, lev);
406 }
407 //Platform::DebugPrintf("Line[%04d] ---------------------------------------------------- Level[%x]\n", lineCurrent+1, levelCurrent);
408 lineCurrent++;
409 levelCurrent = levelNext;
410 //levelMinCurrent = levelCurrent;
411 levelMinCurrentElse = levelCurrent;
412 levelMinCurrentBegin = levelCurrent;
413 visibleChars = 0;
414 }
415 /***************************************/
416 if (!isspacechar(ch)) visibleChars++;
417 }
418
419 /***************************************/
420 // Platform::DebugPrintf("Line[%04d] ---------------------------------------------------- Level[%x]\n", lineCurrent+1, levelCurrent);
421 }
422
423 //=============================================================================
424 static void FoldVHDLDoc(unsigned int startPos, int length, int initStyle, WordList *[],
425 Accessor &styler) {
426 FoldNoBoxVHDLDoc(startPos, length, initStyle, styler);
427 }
428
429 //=============================================================================
430 static const char * const VHDLWordLists[] = {
431 "Keywords",
432 "Operators",
433 "Attributes",
434 "Standard Functions",
435 "Standard Packages",
436 "Standard Types",
437 "User Words",
438 0,
439 };
440
441
442 LexerModule lmVHDL(SCLEX_VHDL, ColouriseVHDLDoc, "vhdl", FoldVHDLDoc, VHDLWordLists);
443
444
445 // Keyword:
446 // access after alias all architecture array assert attribute begin block body buffer bus case component
447 // configuration constant disconnect downto else elsif end entity exit file for function generate generic
448 // group guarded if impure in inertial inout is label library linkage literal loop map new next null of
449 // on open others out package port postponed procedure process pure range record register reject report
450 // return select severity shared signal subtype then to transport type unaffected units until use variable
451 // wait when while with
452 //
453 // Operators:
454 // abs and mod nand nor not or rem rol ror sla sll sra srl xnor xor
455 //
456 // Attributes:
457 // left right low high ascending image value pos val succ pred leftof rightof base range reverse_range
458 // length delayed stable quiet transaction event active last_event last_active last_value driving
459 // driving_value simple_name path_name instance_name
460 //
461 // Std Functions:
462 // now readline read writeline write endfile resolved to_bit to_bitvector to_stdulogic to_stdlogicvector
463 // to_stdulogicvector to_x01 to_x01z to_UX01 rising_edge falling_edge is_x shift_left shift_right rotate_left
464 // rotate_right resize to_integer to_unsigned to_signed std_match to_01
465 //
466 // Std Packages:
467 // std ieee work standard textio std_logic_1164 std_logic_arith std_logic_misc std_logic_signed
468 // std_logic_textio std_logic_unsigned numeric_bit numeric_std math_complex math_real vital_primitives
469 // vital_timing
470 //
471 // Std Types:
472 // boolean bit character severity_level integer real time delay_length natural positive string bit_vector
473 // file_open_kind file_open_status line text side width std_ulogic std_ulogic_vector std_logic
474 // std_logic_vector X01 X01Z UX01 UX01Z unsigned signed
475 //
476