1
// Scintilla source code edit control
2
/** @file LexVerilog.cxx
4
** Written by Avi Yegudin, based on C++ lexer by Neil Hodgson
6
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
7
// The License.txt file describes the conditions under which this software may be distributed.
17
#include "Scintilla.h"
21
#include "LexAccessor.h"
23
#include "StyleContext.h"
24
#include "CharacterSet.h"
25
#include "LexerModule.h"
28
using namespace Scintilla;
31
static inline bool IsAWordChar(const int ch) {
32
return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '\'');
35
static inline bool IsAWordStart(const int ch) {
36
return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '$');
39
static void ColouriseVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
42
WordList &keywords = *keywordlists[0];
43
WordList &keywords2 = *keywordlists[1];
44
WordList &keywords3 = *keywordlists[2];
45
WordList &keywords4 = *keywordlists[3];
47
// Do not leak onto next line
48
if (initStyle == SCE_V_STRINGEOL)
49
initStyle = SCE_V_DEFAULT;
51
StyleContext sc(startPos, length, initStyle, styler);
53
for (; sc.More(); sc.Forward()) {
55
if (sc.atLineStart && (sc.state == SCE_V_STRING)) {
56
// Prevent SCE_V_STRINGEOL from leaking back to previous line
57
sc.SetState(SCE_V_STRING);
60
// Handle line continuation generically.
62
if (sc.chNext == '\n' || sc.chNext == '\r') {
64
if (sc.ch == '\r' && sc.chNext == '\n') {
71
// Determine if the current state should terminate.
72
if (sc.state == SCE_V_OPERATOR) {
73
sc.SetState(SCE_V_DEFAULT);
74
} else if (sc.state == SCE_V_NUMBER) {
75
if (!IsAWordChar(sc.ch)) {
76
sc.SetState(SCE_V_DEFAULT);
78
} else if (sc.state == SCE_V_IDENTIFIER) {
79
if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
81
sc.GetCurrent(s, sizeof(s));
82
if (keywords.InList(s)) {
83
sc.ChangeState(SCE_V_WORD);
84
} else if (keywords2.InList(s)) {
85
sc.ChangeState(SCE_V_WORD2);
86
} else if (keywords3.InList(s)) {
87
sc.ChangeState(SCE_V_WORD3);
88
} else if (keywords4.InList(s)) {
89
sc.ChangeState(SCE_V_USER);
91
sc.SetState(SCE_V_DEFAULT);
93
} else if (sc.state == SCE_V_PREPROCESSOR) {
94
if (!IsAWordChar(sc.ch)) {
95
sc.SetState(SCE_V_DEFAULT);
97
} else if (sc.state == SCE_V_COMMENT) {
98
if (sc.Match('*', '/')) {
100
sc.ForwardSetState(SCE_V_DEFAULT);
102
} else if (sc.state == SCE_V_COMMENTLINE || sc.state == SCE_V_COMMENTLINEBANG) {
103
if (sc.atLineStart) {
104
sc.SetState(SCE_V_DEFAULT);
106
} else if (sc.state == SCE_V_STRING) {
108
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
111
} else if (sc.ch == '\"') {
112
sc.ForwardSetState(SCE_V_DEFAULT);
113
} else if (sc.atLineEnd) {
114
sc.ChangeState(SCE_V_STRINGEOL);
115
sc.ForwardSetState(SCE_V_DEFAULT);
119
// Determine if a new state should be entered.
120
if (sc.state == SCE_V_DEFAULT) {
121
if (IsADigit(sc.ch) || (sc.ch == '\'') || (sc.ch == '.' && IsADigit(sc.chNext))) {
122
sc.SetState(SCE_V_NUMBER);
123
} else if (IsAWordStart(sc.ch)) {
124
sc.SetState(SCE_V_IDENTIFIER);
125
} else if (sc.Match('/', '*')) {
126
sc.SetState(SCE_V_COMMENT);
127
sc.Forward(); // Eat the * so it isn't used for the end of the comment
128
} else if (sc.Match('/', '/')) {
129
if (sc.Match("//!")) // Nice to have a different comment style
130
sc.SetState(SCE_V_COMMENTLINEBANG);
132
sc.SetState(SCE_V_COMMENTLINE);
133
} else if (sc.ch == '\"') {
134
sc.SetState(SCE_V_STRING);
135
} else if (sc.ch == '`') {
136
sc.SetState(SCE_V_PREPROCESSOR);
137
// Skip whitespace between ` and preprocessor word
140
} while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
142
sc.SetState(SCE_V_DEFAULT);
144
} else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@' || sc.ch == '#') {
145
sc.SetState(SCE_V_OPERATOR);
152
static bool IsStreamCommentStyle(int style) {
153
return style == SCE_V_COMMENT;
156
static bool IsCommentLine(int line, Accessor &styler) {
157
int pos = styler.LineStart(line);
158
int eolPos = styler.LineStart(line + 1) - 1;
159
for (int i = pos; i < eolPos; i++) {
161
char chNext = styler.SafeGetCharAt(i + 1);
162
int style = styler.StyleAt(i);
163
if (ch == '/' && chNext == '/' &&
164
(style == SCE_V_COMMENTLINE || style == SCE_V_COMMENTLINEBANG)) {
166
} else if (!IsASpaceOrTab(ch)) {
172
// Store both the current line's fold level and the next lines in the
173
// level store to make it easy to pick up with each increment
174
// and to make it possible to fiddle the current level for "} else {".
175
static void FoldNoBoxVerilogDoc(unsigned int startPos, int length, int initStyle,
177
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
178
bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
179
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
180
bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
181
// Verilog specific folding options:
183
// Generally used methodology in verilog code is
184
// one module per file, so folding at module definition is useless.
185
// fold_at_brace/parenthese -
186
// Folding of long port lists can be convenient.
187
bool foldAtModule = styler.GetPropertyInt("fold.verilog.flags", 0) != 0;
188
bool foldAtBrace = 1;
189
bool foldAtParenthese = 1;
191
unsigned int endPos = startPos + length;
192
int visibleChars = 0;
193
int lineCurrent = styler.GetLine(startPos);
194
int levelCurrent = SC_FOLDLEVELBASE;
196
levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
197
int levelMinCurrent = levelCurrent;
198
int levelNext = levelCurrent;
199
char chNext = styler[startPos];
200
int styleNext = styler.StyleAt(startPos);
201
int style = initStyle;
202
for (unsigned int i = startPos; i < endPos; i++) {
204
chNext = styler.SafeGetCharAt(i + 1);
205
int stylePrev = style;
207
styleNext = styler.StyleAt(i + 1);
208
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
209
if (foldComment && IsStreamCommentStyle(style)) {
210
if (!IsStreamCommentStyle(stylePrev)) {
212
} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
213
// Comments don't end at end of line and the next character may be unstyled.
217
if (foldComment && atEOL && IsCommentLine(lineCurrent, styler))
219
if (!IsCommentLine(lineCurrent - 1, styler)
220
&& IsCommentLine(lineCurrent + 1, styler))
222
else if (IsCommentLine(lineCurrent - 1, styler)
223
&& !IsCommentLine(lineCurrent+1, styler))
226
if (foldComment && (style == SCE_V_COMMENTLINE)) {
227
if ((ch == '/') && (chNext == '/')) {
228
char chNext2 = styler.SafeGetCharAt(i + 2);
229
if (chNext2 == '{') {
231
} else if (chNext2 == '}') {
236
if (foldPreprocessor && (style == SCE_V_PREPROCESSOR)) {
238
unsigned int j = i + 1;
239
while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
242
if (styler.Match(j, "if")) {
244
} else if (styler.Match(j, "end")) {
249
if (style == SCE_V_OPERATOR) {
250
if (foldAtParenthese) {
253
} else if (ch == ')') {
258
if (style == SCE_V_OPERATOR) {
262
} else if (ch == '}') {
267
if (style == SCE_V_WORD && stylePrev != SCE_V_WORD) {
269
if (styler.Match(j, "case") ||
270
styler.Match(j, "casex") ||
271
styler.Match(j, "casez") ||
272
styler.Match(j, "function") ||
273
styler.Match(j, "fork") ||
274
styler.Match(j, "table") ||
275
styler.Match(j, "task") ||
276
styler.Match(j, "generate") ||
277
styler.Match(j, "specify") ||
278
styler.Match(j, "primitive") ||
279
(styler.Match(j, "module") && foldAtModule) ||
280
styler.Match(j, "begin")) {
282
} else if (styler.Match(j, "endcase") ||
283
styler.Match(j, "endfunction") ||
284
styler.Match(j, "join") ||
285
styler.Match(j, "endtask") ||
286
styler.Match(j, "endgenerate") ||
287
styler.Match(j, "endtable") ||
288
styler.Match(j, "endspecify") ||
289
styler.Match(j, "endprimitive") ||
290
(styler.Match(j, "endmodule") && foldAtModule) ||
291
(styler.Match(j, "end") && !IsAWordChar(styler.SafeGetCharAt(j+3)))) {
296
int levelUse = levelCurrent;
298
levelUse = levelMinCurrent;
300
int lev = levelUse | levelNext << 16;
301
if (visibleChars == 0 && foldCompact)
302
lev |= SC_FOLDLEVELWHITEFLAG;
303
if (levelUse < levelNext)
304
lev |= SC_FOLDLEVELHEADERFLAG;
305
if (lev != styler.LevelAt(lineCurrent)) {
306
styler.SetLevel(lineCurrent, lev);
309
levelCurrent = levelNext;
310
levelMinCurrent = levelCurrent;
313
if (!isspacechar(ch))
318
static void FoldVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *[],
320
FoldNoBoxVerilogDoc(startPos, length, initStyle, styler);
323
static const char * const verilogWordLists[] = {
324
"Primary keywords and identifiers",
325
"Secondary keywords and identifiers",
327
"User defined tasks and identifiers",
333
LexerModule lmVerilog(SCLEX_VERILOG, ColouriseVerilogDoc, "verilog", FoldVerilogDoc, verilogWordLists);