1 // Scintilla source code edit control
\r
2 /** @file LexVHDL.cxx
\r
4 ** Written by Phil Reid,
\r
6 ** - The Verilog Lexer by Avi Yegudin
\r
7 ** - The Fortran Lexer by Chuan-jian Shen
\r
8 ** - The C++ lexer by Neil Hodgson
\r
10 // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
\r
11 // The License.txt file describes the conditions under which this software may be distributed.
\r
19 #include "Platform.h"
\r
21 #include "PropSet.h"
\r
22 #include "Accessor.h"
\r
23 #include "StyleContext.h"
\r
24 #include "KeyWords.h"
\r
25 #include "Scintilla.h"
\r
26 #include "SciLexer.h"
\r
28 #ifdef SCI_NAMESPACE
\r
29 using namespace Scintilla;
\r
32 static void ColouriseVHDLDoc(
\r
33 unsigned int startPos,
\r
36 WordList *keywordlists[],
\r
40 /***************************************/
\r
41 static inline bool IsAWordChar(const int ch) {
\r
42 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' );
\r
45 /***************************************/
\r
46 static inline bool IsAWordStart(const int ch) {
\r
47 return (ch < 0x80) && (isalnum(ch) || ch == '_');
\r
50 /***************************************/
\r
51 inline bool IsABlank(unsigned int ch) {
\r
52 return (ch == ' ') || (ch == 0x09) || (ch == 0x0b) ;
\r
55 /***************************************/
\r
56 static void ColouriseVHDLDoc(
\r
57 unsigned int startPos,
\r
60 WordList *keywordlists[],
\r
63 WordList &Keywords = *keywordlists[0];
\r
64 WordList &Operators = *keywordlists[1];
\r
65 WordList &Attributes = *keywordlists[2];
\r
66 WordList &Functions = *keywordlists[3];
\r
67 WordList &Packages = *keywordlists[4];
\r
68 WordList &Types = *keywordlists[5];
\r
69 WordList &User = *keywordlists[6];
\r
71 StyleContext sc(startPos, length, initStyle, styler);
\r
73 for (; sc.More(); sc.Forward())
\r
76 // Determine if the current state should terminate.
\r
77 if (sc.state == SCE_VHDL_OPERATOR) {
\r
78 sc.SetState(SCE_VHDL_DEFAULT);
\r
79 } else if (sc.state == SCE_VHDL_NUMBER) {
\r
80 if (!IsAWordChar(sc.ch) && (sc.ch != '#')) {
\r
81 sc.SetState(SCE_VHDL_DEFAULT);
\r
83 } else if (sc.state == SCE_VHDL_IDENTIFIER) {
\r
84 if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
\r
86 sc.GetCurrentLowered(s, sizeof(s));
\r
87 if (Keywords.InList(s)) {
\r
88 sc.ChangeState(SCE_VHDL_KEYWORD);
\r
89 } else if (Operators.InList(s)) {
\r
90 sc.ChangeState(SCE_VHDL_STDOPERATOR);
\r
91 } else if (Attributes.InList(s)) {
\r
92 sc.ChangeState(SCE_VHDL_ATTRIBUTE);
\r
93 } else if (Functions.InList(s)) {
\r
94 sc.ChangeState(SCE_VHDL_STDFUNCTION);
\r
95 } else if (Packages.InList(s)) {
\r
96 sc.ChangeState(SCE_VHDL_STDPACKAGE);
\r
97 } else if (Types.InList(s)) {
\r
98 sc.ChangeState(SCE_VHDL_STDTYPE);
\r
99 } else if (User.InList(s)) {
\r
100 sc.ChangeState(SCE_VHDL_USERWORD);
\r
102 sc.SetState(SCE_VHDL_DEFAULT);
\r
104 } else if (sc.state == SCE_VHDL_COMMENT || sc.state == SCE_V_COMMENTLINEBANG) {
\r
105 if (sc.atLineEnd) {
\r
106 sc.SetState(SCE_VHDL_DEFAULT);
\r
108 } else if (sc.state == SCE_VHDL_STRING) {
\r
109 if (sc.ch == '\\') {
\r
110 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
\r
113 } else if (sc.ch == '\"') {
\r
114 sc.ForwardSetState(SCE_VHDL_DEFAULT);
\r
115 } else if (sc.atLineEnd) {
\r
116 sc.ChangeState(SCE_V_STRINGEOL);
\r
117 sc.ForwardSetState(SCE_VHDL_DEFAULT);
\r
121 // Determine if a new state should be entered.
\r
122 if (sc.state == SCE_VHDL_DEFAULT) {
\r
123 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
\r
124 sc.SetState(SCE_VHDL_NUMBER);
\r
125 } else if (IsAWordStart(sc.ch)) {
\r
126 sc.SetState(SCE_VHDL_IDENTIFIER);
\r
127 } else if (sc.Match('-', '-')) {
\r
128 sc.SetState(SCE_VHDL_COMMENT);
\r
130 } else if (sc.Match('-', '-')) {
\r
131 if (sc.Match("--!")) // Nice to have a different comment style
\r
132 sc.SetState(SCE_VHDL_COMMENTLINEBANG);
\r
134 sc.SetState(SCE_VHDL_COMMENT);
\r
135 } else if (sc.ch == '\"') {
\r
136 sc.SetState(SCE_VHDL_STRING);
\r
137 } else if (isoperator(static_cast<char>(sc.ch))) {
\r
138 sc.SetState(SCE_VHDL_OPERATOR);
\r
144 //=============================================================================
\r
145 static bool IsCommentLine(int line, Accessor &styler) {
\r
146 int pos = styler.LineStart(line);
\r
147 int eol_pos = styler.LineStart(line + 1) - 1;
\r
148 for (int i = pos; i < eol_pos; i++) {
\r
149 char ch = styler[i];
\r
150 char chNext = styler[i+1];
\r
151 if ((ch == '-') && (chNext == '-'))
\r
153 else if (ch != ' ' && ch != '\t')
\r
159 //=============================================================================
\r
160 // Folding the code
\r
161 static void FoldNoBoxVHDLDoc(
\r
162 unsigned int startPos,
\r
167 // Decided it would be smarter to have the lexer have all keywords included. Therefore I
\r
168 // don't check if the style for the keywords that I use to adjust the levels.
\r
170 "architecture begin case component else elsif end entity generate loop package process record then "
\r
171 "procedure function when";
\r
173 keywords.Set(words);
\r
175 bool foldComment = styler.GetPropertyInt("fold.comment", 1) != 0;
\r
176 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
\r
177 bool foldAtElse = styler.GetPropertyInt("fold.at.else", 1) != 0;
\r
178 bool foldAtBegin = styler.GetPropertyInt("fold.at.Begin", 1) != 0;
\r
179 bool foldAtParenthese = styler.GetPropertyInt("fold.at.Parenthese", 1) != 0;
\r
180 //bool foldAtWhen = styler.GetPropertyInt("fold.at.When", 1) != 0; //< fold at when in case statements
\r
182 int visibleChars = 0;
\r
183 unsigned int endPos = startPos + length;
\r
185 int lineCurrent = styler.GetLine(startPos);
\r
186 int levelCurrent = SC_FOLDLEVELBASE;
\r
187 if(lineCurrent > 0)
\r
188 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
\r
189 //int levelMinCurrent = levelCurrent;
\r
190 int levelMinCurrentElse = levelCurrent; //< Used for folding at 'else'
\r
191 int levelMinCurrentBegin = levelCurrent; //< Used for folding at 'begin'
\r
192 int levelNext = levelCurrent;
\r
194 /***************************************/
\r
196 char prevWord[32] = "";
\r
198 /***************************************/
\r
200 // The logic for going up or down a level depends on a the previous keyword
\r
201 // This code could be cleaned up.
\r
204 for(j = startPos; j>0; j--)
\r
206 char ch = styler.SafeGetCharAt(j);
\r
207 char chPrev = styler.SafeGetCharAt(j-1);
\r
208 int style = styler.StyleAt(j);
\r
209 int stylePrev = styler.StyleAt(j-1);
\r
210 if ((stylePrev != SCE_VHDL_COMMENT) && (stylePrev != SCE_VHDL_STRING))
\r
212 if(IsAWordChar(chPrev) && !IsAWordChar(ch))
\r
217 if ((style != SCE_VHDL_COMMENT) && (style != SCE_VHDL_STRING))
\r
219 if(!IsAWordChar(chPrev) && IsAWordStart(ch) && (end != 0))
\r
223 for(k=0; (k<31 ) && (k<end-j+1 ); k++) {
\r
224 s[k] = static_cast<char>(tolower(styler[j+k]));
\r
228 if(keywords.InList(s)) {
\r
229 strcpy(prevWord, s);
\r
235 for(j=j+strlen(prevWord); j<endPos; j++)
\r
237 char ch = styler.SafeGetCharAt(j);
\r
238 int style = styler.StyleAt(j);
\r
239 if ((style != SCE_VHDL_COMMENT) && (style != SCE_VHDL_STRING))
\r
241 if((ch == ';') && (strcmp(prevWord, "end") == 0))
\r
243 strcpy(prevWord, ";");
\r
248 char chNext = styler[startPos];
\r
249 char chPrev = '\0';
\r
250 char chNextNonBlank;
\r
251 int styleNext = styler.StyleAt(startPos);
\r
252 int style = initStyle;
\r
253 //Platform::DebugPrintf("Line[%04d] Prev[%20s] ************************* Level[%x]\n", lineCurrent+1, prevWord, levelCurrent);
\r
255 /***************************************/
\r
256 for (unsigned int i = startPos; i < endPos; i++)
\r
259 chNext = styler.SafeGetCharAt(i + 1);
\r
260 chPrev = styler.SafeGetCharAt(i - 1);
\r
261 chNextNonBlank = chNext;
\r
262 unsigned int j = i+1;
\r
263 while(IsABlank(chNextNonBlank) && j<endPos)
\r
266 chNextNonBlank = styler.SafeGetCharAt(j);
\r
269 styleNext = styler.StyleAt(i + 1);
\r
270 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
\r
272 if (foldComment && atEOL && IsCommentLine(lineCurrent, styler))
\r
274 if(!IsCommentLine(lineCurrent-1, styler) && IsCommentLine(lineCurrent+1, styler))
\r
278 else if(IsCommentLine(lineCurrent-1, styler) && !IsCommentLine(lineCurrent+1, styler))
\r
284 if ((style == SCE_VHDL_OPERATOR) && foldAtParenthese)
\r
288 } else if (ch == ')') {
\r
293 if ((style != SCE_VHDL_COMMENT) && (style != SCE_VHDL_STRING))
\r
295 if((ch == ';') && (strcmp(prevWord, "end") == 0))
\r
297 strcpy(prevWord, ";");
\r
300 if(!IsAWordChar(chPrev) && IsAWordStart(ch))
\r
305 if(iswordchar(ch) && !iswordchar(chNext)) {
\r
308 for(k=0; (k<31 ) && (k<i-lastStart+1 ); k++) {
\r
309 s[k] = static_cast<char>(tolower(styler[lastStart+k]));
\r
313 if(keywords.InList(s))
\r
316 strcmp(s, "architecture") == 0 ||
\r
317 strcmp(s, "case") == 0 ||
\r
318 strcmp(s, "component") == 0 ||
\r
319 strcmp(s, "entity") == 0 ||
\r
320 strcmp(s, "generate") == 0 ||
\r
321 strcmp(s, "loop") == 0 ||
\r
322 strcmp(s, "package") ==0 ||
\r
323 strcmp(s, "process") == 0 ||
\r
324 strcmp(s, "record") == 0 ||
\r
325 strcmp(s, "then") == 0)
\r
327 if (strcmp(prevWord, "end") != 0)
\r
329 if (levelMinCurrentElse > levelNext) {
\r
330 levelMinCurrentElse = levelNext;
\r
335 strcmp(s, "procedure") == 0 ||
\r
336 strcmp(s, "function") == 0)
\r
338 if (strcmp(prevWord, "end") != 0) // check for "end procedure" etc.
\r
339 { // This code checks to see if the procedure / function is a definition within a "package"
\r
340 // rather than the actual code in the body.
\r
341 int BracketLevel = 0;
\r
342 for(int j=i+1; j<styler.Length(); j++)
\r
344 int LocalStyle = styler.StyleAt(j);
\r
345 char LocalCh = styler.SafeGetCharAt(j);
\r
346 if(LocalCh == '(') BracketLevel++;
\r
347 if(LocalCh == ')') BracketLevel--;
\r
349 (BracketLevel == 0) &&
\r
350 (LocalStyle != SCE_VHDL_COMMENT) &&
\r
351 (LocalStyle != SCE_VHDL_STRING) &&
\r
352 !iswordchar(styler.SafeGetCharAt(j-1)) &&
\r
353 styler.Match(j, "is") &&
\r
354 !iswordchar(styler.SafeGetCharAt(j+2)))
\r
356 if (levelMinCurrentElse > levelNext) {
\r
357 levelMinCurrentElse = levelNext;
\r
362 if((BracketLevel == 0) && (LocalCh == ';'))
\r
369 } else if (strcmp(s, "end") == 0) {
\r
371 } else if(strcmp(s, "elsif") == 0) { // elsif is followed by then so folding occurs correctly
\r
373 } else if (strcmp(s, "else") == 0) {
\r
374 if(strcmp(prevWord, "when") != 0) // ignore a <= x when y else z;
\r
376 levelMinCurrentElse = levelNext - 1; // VHDL else is all on its own so just dec. the min level
\r
379 ((strcmp(s, "begin") == 0) && (strcmp(prevWord, "architecture") == 0)) ||
\r
380 ((strcmp(s, "begin") == 0) && (strcmp(prevWord, "function") == 0)) ||
\r
381 ((strcmp(s, "begin") == 0) && (strcmp(prevWord, "procedure") == 0)))
\r
383 levelMinCurrentBegin = levelNext - 1;
\r
385 //Platform::DebugPrintf("Line[%04d] Prev[%20s] Cur[%20s] Level[%x]\n", lineCurrent+1, prevWord, s, levelCurrent);
\r
386 strcpy(prevWord, s);
\r
391 int levelUse = levelCurrent;
\r
393 if (foldAtElse && (levelMinCurrentElse < levelUse)) {
\r
394 levelUse = levelMinCurrentElse;
\r
396 if (foldAtBegin && (levelMinCurrentBegin < levelUse)) {
\r
397 levelUse = levelMinCurrentBegin;
\r
399 int lev = levelUse | levelNext << 16;
\r
400 if (visibleChars == 0 && foldCompact)
\r
401 lev |= SC_FOLDLEVELWHITEFLAG;
\r
403 if (levelUse < levelNext)
\r
404 lev |= SC_FOLDLEVELHEADERFLAG;
\r
405 if (lev != styler.LevelAt(lineCurrent)) {
\r
406 styler.SetLevel(lineCurrent, lev);
\r
408 //Platform::DebugPrintf("Line[%04d] ---------------------------------------------------- Level[%x]\n", lineCurrent+1, levelCurrent);
\r
410 levelCurrent = levelNext;
\r
411 //levelMinCurrent = levelCurrent;
\r
412 levelMinCurrentElse = levelCurrent;
\r
413 levelMinCurrentBegin = levelCurrent;
\r
416 /***************************************/
\r
417 if (!isspacechar(ch)) visibleChars++;
\r
420 /***************************************/
\r
421 // Platform::DebugPrintf("Line[%04d] ---------------------------------------------------- Level[%x]\n", lineCurrent+1, levelCurrent);
\r
424 //=============================================================================
\r
425 static void FoldVHDLDoc(unsigned int startPos, int length, int initStyle, WordList *[],
\r
426 Accessor &styler) {
\r
427 FoldNoBoxVHDLDoc(startPos, length, initStyle, styler);
\r
430 //=============================================================================
\r
431 static const char * const VHDLWordLists[] = {
\r
435 "Standard Functions",
\r
436 "Standard Packages",
\r
443 LexerModule lmVHDL(SCLEX_VHDL, ColouriseVHDLDoc, "vhdl", FoldVHDLDoc, VHDLWordLists);
\r
447 // access after alias all architecture array assert attribute begin block body buffer bus case component
\r
448 // configuration constant disconnect downto else elsif end entity exit file for function generate generic
\r
449 // group guarded if impure in inertial inout is label library linkage literal loop map new next null of
\r
450 // on open others out package port postponed procedure process pure range record register reject report
\r
451 // return select severity shared signal subtype then to transport type unaffected units until use variable
\r
452 // wait when while with
\r
455 // abs and mod nand nor not or rem rol ror sla sll sra srl xnor xor
\r
458 // left right low high ascending image value pos val succ pred leftof rightof base range reverse_range
\r
459 // length delayed stable quiet transaction event active last_event last_active last_value driving
\r
460 // driving_value simple_name path_name instance_name
\r
463 // now readline read writeline write endfile resolved to_bit to_bitvector to_stdulogic to_stdlogicvector
\r
464 // to_stdulogicvector to_x01 to_x01z to_UX01 rising_edge falling_edge is_x shift_left shift_right rotate_left
\r
465 // rotate_right resize to_integer to_unsigned to_signed std_match to_01
\r
468 // std ieee work standard textio std_logic_1164 std_logic_arith std_logic_misc std_logic_signed
\r
469 // std_logic_textio std_logic_unsigned numeric_bit numeric_std math_complex math_real vital_primitives
\r
473 // boolean bit character severity_level integer real time delay_length natural positive string bit_vector
\r
474 // file_open_kind file_open_status line text side width std_ulogic std_ulogic_vector std_logic
\r
475 // std_logic_vector X01 X01Z UX01 UX01Z unsigned signed
\r