1 // Scintilla source code edit control
4 ** Written by Phil Reid,
6 ** - The Verilog Lexer by Avi Yegudin
7 ** - The Fortran Lexer by Chuan-jian Shen
8 ** - The C++ lexer by Neil Hodgson
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.
21 #include "Scintilla.h"
25 #include "LexAccessor.h"
27 #include "StyleContext.h"
28 #include "CharacterSet.h"
29 #include "LexerModule.h"
32 using namespace Scintilla
;
35 static void ColouriseVHDLDoc(
36 Sci_PositionU startPos
,
39 WordList
*keywordlists
[],
43 /***************************************/
44 static inline bool IsAWordChar(const int ch
) {
45 return (ch
< 0x80) && (isalnum(ch
) || ch
== '.' || ch
== '_' );
48 /***************************************/
49 static inline bool IsAWordStart(const int ch
) {
50 return (ch
< 0x80) && (isalnum(ch
) || ch
== '_');
53 /***************************************/
54 static inline bool IsABlank(unsigned int ch
) {
55 return (ch
== ' ') || (ch
== 0x09) || (ch
== 0x0b) ;
58 /***************************************/
59 static void ColouriseVHDLDoc(
60 Sci_PositionU startPos
,
63 WordList
*keywordlists
[],
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];
74 StyleContext
sc(startPos
, length
, initStyle
, styler
);
75 bool isExtendedId
= false; // true when parsing an extended identifier
77 for (; sc
.More(); sc
.Forward())
80 // Determine if the current state should terminate.
81 if (sc
.state
== SCE_VHDL_OPERATOR
) {
82 sc
.SetState(SCE_VHDL_DEFAULT
);
83 } else if (sc
.state
== SCE_VHDL_NUMBER
) {
84 if (!IsAWordChar(sc
.ch
) && (sc
.ch
!= '#')) {
85 sc
.SetState(SCE_VHDL_DEFAULT
);
87 } else if (sc
.state
== SCE_VHDL_IDENTIFIER
) {
88 if (!isExtendedId
&& (!IsAWordChar(sc
.ch
) || (sc
.ch
== '.'))) {
90 sc
.GetCurrentLowered(s
, sizeof(s
));
91 if (Keywords
.InList(s
)) {
92 sc
.ChangeState(SCE_VHDL_KEYWORD
);
93 } else if (Operators
.InList(s
)) {
94 sc
.ChangeState(SCE_VHDL_STDOPERATOR
);
95 } else if (Attributes
.InList(s
)) {
96 sc
.ChangeState(SCE_VHDL_ATTRIBUTE
);
97 } else if (Functions
.InList(s
)) {
98 sc
.ChangeState(SCE_VHDL_STDFUNCTION
);
99 } else if (Packages
.InList(s
)) {
100 sc
.ChangeState(SCE_VHDL_STDPACKAGE
);
101 } else if (Types
.InList(s
)) {
102 sc
.ChangeState(SCE_VHDL_STDTYPE
);
103 } else if (User
.InList(s
)) {
104 sc
.ChangeState(SCE_VHDL_USERWORD
);
106 sc
.SetState(SCE_VHDL_DEFAULT
);
107 } else if (isExtendedId
&& ((sc
.ch
== '\\') || sc
.atLineEnd
)) {
108 // extended identifiers are terminated by backslash, check for end of line in case we have invalid syntax
109 isExtendedId
= false;
110 sc
.ForwardSetState(SCE_VHDL_DEFAULT
);
112 } else if (sc
.state
== SCE_VHDL_COMMENT
|| sc
.state
== SCE_VHDL_COMMENTLINEBANG
) {
114 sc
.SetState(SCE_VHDL_DEFAULT
);
116 } else if (sc
.state
== SCE_VHDL_STRING
) {
118 if (sc
.chNext
== '\"' || sc
.chNext
== '\'' || sc
.chNext
== '\\') {
121 } else if (sc
.ch
== '\"') {
122 sc
.ForwardSetState(SCE_VHDL_DEFAULT
);
123 } else if (sc
.atLineEnd
) {
124 sc
.ChangeState(SCE_VHDL_STRINGEOL
);
125 sc
.ForwardSetState(SCE_VHDL_DEFAULT
);
127 } else if (sc
.state
== SCE_VHDL_BLOCK_COMMENT
){
128 if(sc
.ch
== '*' && sc
.chNext
== '/'){
130 sc
.ForwardSetState(SCE_VHDL_DEFAULT
);
134 // Determine if a new state should be entered.
135 if (sc
.state
== SCE_VHDL_DEFAULT
) {
136 if (IsADigit(sc
.ch
) || (sc
.ch
== '.' && IsADigit(sc
.chNext
))) {
137 sc
.SetState(SCE_VHDL_NUMBER
);
138 } else if (IsAWordStart(sc
.ch
)) {
139 sc
.SetState(SCE_VHDL_IDENTIFIER
);
140 } else if (sc
.Match('-', '-')) {
141 if (sc
.Match("--!")) // Nice to have a different comment style
142 sc
.SetState(SCE_VHDL_COMMENTLINEBANG
);
144 sc
.SetState(SCE_VHDL_COMMENT
);
145 } else if (sc
.Match('/', '*')){
146 sc
.SetState(SCE_VHDL_BLOCK_COMMENT
);
147 } else if (sc
.ch
== '\"') {
148 sc
.SetState(SCE_VHDL_STRING
);
149 } else if (sc
.ch
== '\\') {
151 sc
.SetState(SCE_VHDL_IDENTIFIER
);
152 } else if (isoperator(static_cast<char>(sc
.ch
))) {
153 sc
.SetState(SCE_VHDL_OPERATOR
);
159 //=============================================================================
160 static bool IsCommentLine(Sci_Position line
, Accessor
&styler
) {
161 Sci_Position pos
= styler
.LineStart(line
);
162 Sci_Position eol_pos
= styler
.LineStart(line
+ 1) - 1;
163 for (Sci_Position i
= pos
; i
< eol_pos
; i
++) {
165 char chNext
= styler
[i
+1];
166 if ((ch
== '-') && (chNext
== '-'))
168 else if (ch
!= ' ' && ch
!= '\t')
173 static bool IsCommentBlockStart(Sci_Position line
, Accessor
&styler
)
175 Sci_Position pos
= styler
.LineStart(line
);
176 Sci_Position eol_pos
= styler
.LineStart(line
+ 1) - 1;
177 for (Sci_Position i
= pos
; i
< eol_pos
; i
++) {
179 char chNext
= styler
[i
+1];
180 char style
= styler
.StyleAt(i
);
181 if ((style
== SCE_VHDL_BLOCK_COMMENT
) && (ch
== '/') && (chNext
== '*'))
187 static bool IsCommentBlockEnd(Sci_Position line
, Accessor
&styler
)
189 Sci_Position pos
= styler
.LineStart(line
);
190 Sci_Position eol_pos
= styler
.LineStart(line
+ 1) - 1;
192 for (Sci_Position i
= pos
; i
< eol_pos
; i
++) {
194 char chNext
= styler
[i
+1];
195 char style
= styler
.StyleAt(i
);
196 if ((style
== SCE_VHDL_BLOCK_COMMENT
) && (ch
== '*') && (chNext
== '/'))
202 static bool IsCommentStyle(char style
)
204 return style
== SCE_VHDL_BLOCK_COMMENT
|| style
== SCE_VHDL_COMMENT
|| style
== SCE_VHDL_COMMENTLINEBANG
;
207 //=============================================================================
209 static void FoldNoBoxVHDLDoc(
210 Sci_PositionU startPos
,
215 // Decided it would be smarter to have the lexer have all keywords included. Therefore I
216 // don't check if the style for the keywords that I use to adjust the levels.
218 "architecture begin block case component else elsif end entity generate loop package process record then "
219 "procedure protected function when units";
223 bool foldComment
= styler
.GetPropertyInt("fold.comment", 1) != 0;
224 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
225 bool foldAtElse
= styler
.GetPropertyInt("fold.at.else", 1) != 0;
226 bool foldAtBegin
= styler
.GetPropertyInt("fold.at.Begin", 1) != 0;
227 bool foldAtParenthese
= styler
.GetPropertyInt("fold.at.Parenthese", 1) != 0;
228 //bool foldAtWhen = styler.GetPropertyInt("fold.at.When", 1) != 0; //< fold at when in case statements
230 int visibleChars
= 0;
231 Sci_PositionU endPos
= startPos
+ length
;
233 Sci_Position lineCurrent
= styler
.GetLine(startPos
);
234 int levelCurrent
= SC_FOLDLEVELBASE
;
236 levelCurrent
= styler
.LevelAt(lineCurrent
-1) >> 16;
237 //int levelMinCurrent = levelCurrent;
238 int levelMinCurrentElse
= levelCurrent
; //< Used for folding at 'else'
239 int levelMinCurrentBegin
= levelCurrent
; //< Used for folding at 'begin'
240 int levelNext
= levelCurrent
;
242 /***************************************/
243 Sci_Position lastStart
= 0;
244 char prevWord
[32] = "";
246 /***************************************/
248 // The logic for going up or down a level depends on a the previous keyword
249 // This code could be cleaned up.
250 Sci_Position end
= 0;
252 for(j
= startPos
; j
>0; j
--)
254 char ch
= styler
.SafeGetCharAt(j
);
255 char chPrev
= styler
.SafeGetCharAt(j
-1);
256 int style
= styler
.StyleAt(j
);
257 int stylePrev
= styler
.StyleAt(j
-1);
258 if ((!IsCommentStyle(style
)) && (stylePrev
!= SCE_VHDL_STRING
))
260 if(IsAWordChar(chPrev
) && !IsAWordChar(ch
))
265 if ((!IsCommentStyle(style
)) && (style
!= SCE_VHDL_STRING
))
267 if(!IsAWordChar(chPrev
) && IsAWordStart(ch
) && (end
!= 0))
271 for(k
=0; (k
<31 ) && (k
<end
-j
+1 ); k
++) {
272 s
[k
] = static_cast<char>(tolower(styler
[j
+k
]));
276 if(keywords
.InList(s
)) {
283 for(j
=j
+static_cast<Sci_PositionU
>(strlen(prevWord
)); j
<endPos
; j
++)
285 char ch
= styler
.SafeGetCharAt(j
);
286 int style
= styler
.StyleAt(j
);
287 if ((!IsCommentStyle(style
)) && (style
!= SCE_VHDL_STRING
))
289 if((ch
== ';') && (strcmp(prevWord
, "end") == 0))
291 strcpy(prevWord
, ";");
296 char chNext
= styler
[startPos
];
299 int styleNext
= styler
.StyleAt(startPos
);
300 //Platform::DebugPrintf("Line[%04d] Prev[%20s] ************************* Level[%x]\n", lineCurrent+1, prevWord, levelCurrent);
302 /***************************************/
303 for (Sci_PositionU i
= startPos
; i
< endPos
; i
++)
306 chNext
= styler
.SafeGetCharAt(i
+ 1);
307 chPrev
= styler
.SafeGetCharAt(i
- 1);
308 chNextNonBlank
= chNext
;
309 Sci_PositionU j
= i
+1;
310 while(IsABlank(chNextNonBlank
) && j
<endPos
)
313 chNextNonBlank
= styler
.SafeGetCharAt(j
);
315 int style
= styleNext
;
316 styleNext
= styler
.StyleAt(i
+ 1);
317 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
319 if (foldComment
&& atEOL
)
321 if(IsCommentLine(lineCurrent
, styler
))
323 if(!IsCommentLine(lineCurrent
-1, styler
) && IsCommentLine(lineCurrent
+1, styler
))
327 else if(IsCommentLine(lineCurrent
-1, styler
) && !IsCommentLine(lineCurrent
+1, styler
))
334 if (IsCommentBlockStart(lineCurrent
, styler
) && !IsCommentBlockEnd(lineCurrent
, styler
))
338 else if (IsCommentBlockEnd(lineCurrent
, styler
) && !IsCommentBlockStart(lineCurrent
, styler
))
345 if ((style
== SCE_VHDL_OPERATOR
) && foldAtParenthese
)
349 } else if (ch
== ')') {
354 if ((!IsCommentStyle(style
)) && (style
!= SCE_VHDL_STRING
))
356 if((ch
== ';') && (strcmp(prevWord
, "end") == 0))
358 strcpy(prevWord
, ";");
361 if(!IsAWordChar(chPrev
) && IsAWordStart(ch
))
366 if(IsAWordChar(ch
) && !IsAWordChar(chNext
)) {
369 for(k
=0; (k
<31 ) && (k
<i
-lastStart
+1 ); k
++) {
370 s
[k
] = static_cast<char>(tolower(styler
[lastStart
+k
]));
374 if(keywords
.InList(s
))
377 strcmp(s
, "architecture") == 0 ||
378 strcmp(s
, "case") == 0 ||
379 strcmp(s
, "generate") == 0 ||
380 strcmp(s
, "block") == 0 ||
381 strcmp(s
, "loop") == 0 ||
382 strcmp(s
, "package") ==0 ||
383 strcmp(s
, "process") == 0 ||
384 strcmp(s
, "protected") == 0 ||
385 strcmp(s
, "record") == 0 ||
386 strcmp(s
, "then") == 0 ||
387 strcmp(s
, "units") == 0)
389 if (strcmp(prevWord
, "end") != 0)
391 if (levelMinCurrentElse
> levelNext
) {
392 levelMinCurrentElse
= levelNext
;
397 strcmp(s
, "component") == 0 ||
398 strcmp(s
, "entity") == 0 ||
399 strcmp(s
, "configuration") == 0 )
401 if (strcmp(prevWord
, "end") != 0 && lastStart
)
402 { // check for instantiated unit by backward searching for the colon.
403 Sci_PositionU pos
= lastStart
;
404 char chAtPos
, styleAtPos
;
405 do{// skip white spaces
407 styleAtPos
= styler
.StyleAt(pos
);
408 chAtPos
= styler
.SafeGetCharAt(pos
);
410 (chAtPos
== ' ' || chAtPos
== '\t' ||
411 chAtPos
== '\n' || chAtPos
== '\r' ||
412 IsCommentStyle(styleAtPos
)));
414 // check for a colon (':') before the instantiated units "entity", "component" or "configuration". Don't fold thereafter.
417 if (levelMinCurrentElse
> levelNext
) {
418 levelMinCurrentElse
= levelNext
;
424 strcmp(s
, "procedure") == 0 ||
425 strcmp(s
, "function") == 0)
427 if (strcmp(prevWord
, "end") != 0) // check for "end procedure" etc.
428 { // This code checks to see if the procedure / function is a definition within a "package"
429 // rather than the actual code in the body.
430 int BracketLevel
= 0;
431 for(Sci_Position pos
=i
+1; pos
<styler
.Length(); pos
++)
433 int styleAtPos
= styler
.StyleAt(pos
);
434 char chAtPos
= styler
.SafeGetCharAt(pos
);
435 if(chAtPos
== '(') BracketLevel
++;
436 if(chAtPos
== ')') BracketLevel
--;
438 (BracketLevel
== 0) &&
439 (!IsCommentStyle(styleAtPos
)) &&
440 (styleAtPos
!= SCE_VHDL_STRING
) &&
441 !iswordchar(styler
.SafeGetCharAt(pos
-1)) &&
442 (chAtPos
|' ')=='i' && (styler
.SafeGetCharAt(pos
+1)|' ')=='s' &&
443 !iswordchar(styler
.SafeGetCharAt(pos
+2)))
445 if (levelMinCurrentElse
> levelNext
) {
446 levelMinCurrentElse
= levelNext
;
451 if((BracketLevel
== 0) && (chAtPos
== ';'))
458 } else if (strcmp(s
, "end") == 0) {
460 } else if(strcmp(s
, "elsif") == 0) { // elsif is followed by then so folding occurs correctly
462 } else if (strcmp(s
, "else") == 0) {
463 if(strcmp(prevWord
, "when") != 0) // ignore a <= x when y else z;
465 levelMinCurrentElse
= levelNext
- 1; // VHDL else is all on its own so just dec. the min level
468 ((strcmp(s
, "begin") == 0) && (strcmp(prevWord
, "architecture") == 0)) ||
469 ((strcmp(s
, "begin") == 0) && (strcmp(prevWord
, "function") == 0)) ||
470 ((strcmp(s
, "begin") == 0) && (strcmp(prevWord
, "procedure") == 0)))
472 levelMinCurrentBegin
= levelNext
- 1;
474 //Platform::DebugPrintf("Line[%04d] Prev[%20s] Cur[%20s] Level[%x]\n", lineCurrent+1, prevWord, s, levelCurrent);
480 int levelUse
= levelCurrent
;
482 if (foldAtElse
&& (levelMinCurrentElse
< levelUse
)) {
483 levelUse
= levelMinCurrentElse
;
485 if (foldAtBegin
&& (levelMinCurrentBegin
< levelUse
)) {
486 levelUse
= levelMinCurrentBegin
;
488 int lev
= levelUse
| levelNext
<< 16;
489 if (visibleChars
== 0 && foldCompact
)
490 lev
|= SC_FOLDLEVELWHITEFLAG
;
492 if (levelUse
< levelNext
)
493 lev
|= SC_FOLDLEVELHEADERFLAG
;
494 if (lev
!= styler
.LevelAt(lineCurrent
)) {
495 styler
.SetLevel(lineCurrent
, lev
);
497 //Platform::DebugPrintf("Line[%04d] ---------------------------------------------------- Level[%x]\n", lineCurrent+1, levelCurrent);
499 levelCurrent
= levelNext
;
500 //levelMinCurrent = levelCurrent;
501 levelMinCurrentElse
= levelCurrent
;
502 levelMinCurrentBegin
= levelCurrent
;
505 /***************************************/
506 if (!isspacechar(ch
)) visibleChars
++;
509 /***************************************/
510 // Platform::DebugPrintf("Line[%04d] ---------------------------------------------------- Level[%x]\n", lineCurrent+1, levelCurrent);
513 //=============================================================================
514 static void FoldVHDLDoc(Sci_PositionU startPos
, Sci_Position length
, int initStyle
, WordList
*[],
516 FoldNoBoxVHDLDoc(startPos
, length
, initStyle
, styler
);
519 //=============================================================================
520 static const char * const VHDLWordLists
[] = {
524 "Standard Functions",
532 LexerModule
lmVHDL(SCLEX_VHDL
, ColouriseVHDLDoc
, "vhdl", FoldVHDLDoc
, VHDLWordLists
);
536 // access after alias all architecture array assert attribute begin block body buffer bus case component
537 // configuration constant disconnect downto else elsif end entity exit file for function generate generic
538 // group guarded if impure in inertial inout is label library linkage literal loop map new next null of
539 // on open others out package port postponed procedure process pure range record register reject report
540 // return select severity shared signal subtype then to transport type unaffected units until use variable
541 // wait when while with
544 // abs and mod nand nor not or rem rol ror sla sll sra srl xnor xor
547 // left right low high ascending image value pos val succ pred leftof rightof base range reverse_range
548 // length delayed stable quiet transaction event active last_event last_active last_value driving
549 // driving_value simple_name path_name instance_name
552 // now readline read writeline write endfile resolved to_bit to_bitvector to_stdulogic to_stdlogicvector
553 // to_stdulogicvector to_x01 to_x01z to_UX01 rising_edge falling_edge is_x shift_left shift_right rotate_left
554 // rotate_right resize to_integer to_unsigned to_signed std_match to_01
557 // std ieee work standard textio std_logic_1164 std_logic_arith std_logic_misc std_logic_signed
558 // std_logic_textio std_logic_unsigned numeric_bit numeric_std math_complex math_real vital_primitives
562 // boolean bit character severity_level integer real time delay_length natural positive string bit_vector
563 // file_open_kind file_open_status line text side width std_ulogic std_ulogic_vector std_logic
564 // std_logic_vector X01 X01Z UX01 UX01Z unsigned signed