]>
Commit | Line | Data |
---|---|---|
a33203cb RD |
1 | // Scintilla source code edit control |
2 | /** @file LexVHDL.cxx | |
3 | ** Lexer for VHDL | |
1dcf666d | 4 | ** Written by Phil Reid, |
a33203cb | 5 | ** Based on: |
1dcf666d | 6 | ** - The Verilog Lexer by Avi Yegudin |
a33203cb RD |
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> | |
1dcf666d | 18 | #include <assert.h> |
a33203cb | 19 | |
1dcf666d RD |
20 | #include "ILexer.h" |
21 | #include "Scintilla.h" | |
22 | #include "SciLexer.h" | |
a33203cb | 23 | |
1dcf666d RD |
24 | #include "WordList.h" |
25 | #include "LexAccessor.h" | |
a33203cb RD |
26 | #include "Accessor.h" |
27 | #include "StyleContext.h" | |
1dcf666d RD |
28 | #include "CharacterSet.h" |
29 | #include "LexerModule.h" | |
a33203cb | 30 | |
7e0c58e9 RD |
31 | #ifdef SCI_NAMESPACE |
32 | using namespace Scintilla; | |
33 | #endif | |
34 | ||
a33203cb RD |
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 | } | |
1dcf666d | 107 | } else if (sc.state == SCE_VHDL_COMMENT || sc.state == SCE_VHDL_COMMENTLINEBANG) { |
a33203cb RD |
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) { | |
1dcf666d | 119 | sc.ChangeState(SCE_VHDL_STRINGEOL); |
a33203cb RD |
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); | |
a33203cb RD |
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, | |
1dcf666d | 164 | int, |
a33203cb RD |
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 | } | |
1dcf666d | 235 | for(j=j+static_cast<unsigned int>(strlen(prevWord)); j<endPos; j++) |
a33203cb RD |
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); | |
a33203cb RD |
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 | } | |
1dcf666d | 267 | int style = styleNext; |
a33203cb RD |
268 | styleNext = styler.StyleAt(i + 1); |
269 | bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); | |
270 | ||
1dcf666d | 271 | if (foldComment && atEOL && IsCommentLine(lineCurrent, styler)) |
a33203cb RD |
272 | { |
273 | if(!IsCommentLine(lineCurrent-1, styler) && IsCommentLine(lineCurrent+1, styler)) | |
274 | { | |
275 | levelNext++; | |
1dcf666d | 276 | } |
a33203cb RD |
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 | { | |
1dcf666d | 382 | levelMinCurrentBegin = levelNext - 1; |
a33203cb RD |
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: | |
1dcf666d RD |
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 | |
a33203cb RD |
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: | |
1dcf666d RD |
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 | |
a33203cb RD |
459 | // driving_value simple_name path_name instance_name |
460 | // | |
461 | // Std Functions: | |
1dcf666d RD |
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 | |
a33203cb RD |
464 | // rotate_right resize to_integer to_unsigned to_signed std_match to_01 |
465 | // | |
466 | // Std Packages: | |
1dcf666d RD |
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 | |
a33203cb RD |
469 | // vital_timing |
470 | // | |
471 | // Std Types: | |
1dcf666d RD |
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 | |
a33203cb RD |
474 | // std_logic_vector X01 X01Z UX01 UX01Z unsigned signed |
475 | // | |
476 |