1 // Scintilla source code edit control
2 /** @file LexSpecman.cxx
3 ** Lexer for Specman E language.
4 ** Written by Avi Yegudin, based on C++ lexer by Neil Hodgson
5 **/
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.
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
15
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
19
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
26
27 using namespace Scintilla;
28
IsAWordChar(const int ch)29 static inline bool IsAWordChar(const int ch) {
30 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '\'');
31 }
32
IsANumberChar(const int ch)33 static inline bool IsANumberChar(const int ch) {
34 return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '\'');
35 }
36
IsAWordStart(const int ch)37 static inline bool IsAWordStart(const int ch) {
38 return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '`');
39 }
40
ColouriseSpecmanDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler,bool caseSensitive)41 static void ColouriseSpecmanDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
42 Accessor &styler, bool caseSensitive) {
43
44 WordList &keywords = *keywordlists[0];
45 WordList &keywords2 = *keywordlists[1];
46 WordList &keywords3 = *keywordlists[2];
47 WordList &keywords4 = *keywordlists[3];
48
49 // Do not leak onto next line
50 if (initStyle == SCE_SN_STRINGEOL)
51 initStyle = SCE_SN_CODE;
52
53 int visibleChars = 0;
54
55 StyleContext sc(startPos, length, initStyle, styler);
56
57 for (; sc.More(); sc.Forward()) {
58
59 if (sc.atLineStart && (sc.state == SCE_SN_STRING)) {
60 // Prevent SCE_SN_STRINGEOL from leaking back to previous line
61 sc.SetState(SCE_SN_STRING);
62 }
63
64 // Handle line continuation generically.
65 if (sc.ch == '\\') {
66 if (sc.chNext == '\n' || sc.chNext == '\r') {
67 sc.Forward();
68 if (sc.ch == '\r' && sc.chNext == '\n') {
69 sc.Forward();
70 }
71 continue;
72 }
73 }
74
75 // Determine if the current state should terminate.
76 if (sc.state == SCE_SN_OPERATOR) {
77 sc.SetState(SCE_SN_CODE);
78 } else if (sc.state == SCE_SN_NUMBER) {
79 if (!IsANumberChar(sc.ch)) {
80 sc.SetState(SCE_SN_CODE);
81 }
82 } else if (sc.state == SCE_SN_IDENTIFIER) {
83 if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
84 char s[100];
85 if (caseSensitive) {
86 sc.GetCurrent(s, sizeof(s));
87 } else {
88 sc.GetCurrentLowered(s, sizeof(s));
89 }
90 if (keywords.InList(s)) {
91 sc.ChangeState(SCE_SN_WORD);
92 } else if (keywords2.InList(s)) {
93 sc.ChangeState(SCE_SN_WORD2);
94 } else if (keywords3.InList(s)) {
95 sc.ChangeState(SCE_SN_WORD3);
96 } else if (keywords4.InList(s)) {
97 sc.ChangeState(SCE_SN_USER);
98 }
99 sc.SetState(SCE_SN_CODE);
100 }
101 } else if (sc.state == SCE_SN_PREPROCESSOR) {
102 if (IsASpace(sc.ch)) {
103 sc.SetState(SCE_SN_CODE);
104 }
105 } else if (sc.state == SCE_SN_DEFAULT) {
106 if (sc.Match('<', '\'')) {
107 sc.Forward();
108 sc.ForwardSetState(SCE_SN_CODE);
109 }
110 } else if (sc.state == SCE_SN_COMMENTLINE || sc.state == SCE_SN_COMMENTLINEBANG) {
111 if (sc.atLineEnd) {
112 sc.SetState(SCE_SN_CODE);
113 visibleChars = 0;
114 }
115 } else if (sc.state == SCE_SN_STRING) {
116 if (sc.ch == '\\') {
117 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
118 sc.Forward();
119 }
120 } else if (sc.ch == '\"') {
121 sc.ForwardSetState(SCE_SN_CODE);
122 } else if (sc.atLineEnd) {
123 sc.ChangeState(SCE_SN_STRINGEOL);
124 sc.ForwardSetState(SCE_SN_CODE);
125 visibleChars = 0;
126 }
127 } else if (sc.state == SCE_SN_SIGNAL) {
128 if (sc.atLineEnd) {
129 sc.ChangeState(SCE_SN_STRINGEOL);
130 sc.ForwardSetState(SCE_SN_CODE);
131 visibleChars = 0;
132 } else if (sc.ch == '\\') {
133 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
134 sc.Forward();
135 }
136 } else if (sc.ch == '\'') {
137 sc.ForwardSetState(SCE_SN_CODE);
138 }
139 } else if (sc.state == SCE_SN_REGEXTAG) {
140 if (!IsADigit(sc.ch)) {
141 sc.SetState(SCE_SN_CODE);
142 }
143 }
144
145 // Determine if a new state should be entered.
146 if (sc.state == SCE_SN_CODE) {
147 if (sc.ch == '$' && IsADigit(sc.chNext)) {
148 sc.SetState(SCE_SN_REGEXTAG);
149 sc.Forward();
150 } else if (IsADigit(sc.ch)) {
151 sc.SetState(SCE_SN_NUMBER);
152 } else if (IsAWordStart(sc.ch)) {
153 sc.SetState(SCE_SN_IDENTIFIER);
154 } else if (sc.Match('\'', '>')) {
155 sc.SetState(SCE_SN_DEFAULT);
156 sc.Forward(); // Eat the * so it isn't used for the end of the comment
157 } else if (sc.Match('/', '/')) {
158 if (sc.Match("//!")) // Nice to have a different comment style
159 sc.SetState(SCE_SN_COMMENTLINEBANG);
160 else
161 sc.SetState(SCE_SN_COMMENTLINE);
162 } else if (sc.Match('-', '-')) {
163 if (sc.Match("--!")) // Nice to have a different comment style
164 sc.SetState(SCE_SN_COMMENTLINEBANG);
165 else
166 sc.SetState(SCE_SN_COMMENTLINE);
167 } else if (sc.ch == '\"') {
168 sc.SetState(SCE_SN_STRING);
169 } else if (sc.ch == '\'') {
170 sc.SetState(SCE_SN_SIGNAL);
171 } else if (sc.ch == '#' && visibleChars == 0) {
172 // Preprocessor commands are alone on their line
173 sc.SetState(SCE_SN_PREPROCESSOR);
174 // Skip whitespace between # and preprocessor word
175 do {
176 sc.Forward();
177 } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
178 if (sc.atLineEnd) {
179 sc.SetState(SCE_SN_CODE);
180 }
181 } else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@') {
182 sc.SetState(SCE_SN_OPERATOR);
183 }
184 }
185
186 if (sc.atLineEnd) {
187 // Reset states to begining of colourise so no surprises
188 // if different sets of lines lexed.
189 visibleChars = 0;
190 }
191 if (!IsASpace(sc.ch)) {
192 visibleChars++;
193 }
194 }
195 sc.Complete();
196 }
197
198 // Store both the current line's fold level and the next lines in the
199 // level store to make it easy to pick up with each increment
200 // and to make it possible to fiddle the current level for "} else {".
FoldNoBoxSpecmanDoc(Sci_PositionU startPos,Sci_Position length,int,Accessor & styler)201 static void FoldNoBoxSpecmanDoc(Sci_PositionU startPos, Sci_Position length, int,
202 Accessor &styler) {
203 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
204 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
205 bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
206 Sci_PositionU endPos = startPos + length;
207 int visibleChars = 0;
208 Sci_Position lineCurrent = styler.GetLine(startPos);
209 int levelCurrent = SC_FOLDLEVELBASE;
210 if (lineCurrent > 0)
211 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
212 int levelMinCurrent = levelCurrent;
213 int levelNext = levelCurrent;
214 char chNext = styler[startPos];
215 int styleNext = styler.StyleAt(startPos);
216 int style;
217 for (Sci_PositionU i = startPos; i < endPos; i++) {
218 char ch = chNext;
219 chNext = styler.SafeGetCharAt(i + 1);
220 //int stylePrev = style;
221 style = styleNext;
222 styleNext = styler.StyleAt(i + 1);
223 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
224 if (foldComment && (style == SCE_SN_COMMENTLINE)) {
225 if (((ch == '/') && (chNext == '/')) ||
226 ((ch == '-') && (chNext == '-'))) {
227 char chNext2 = styler.SafeGetCharAt(i + 2);
228 if (chNext2 == '{') {
229 levelNext++;
230 } else if (chNext2 == '}') {
231 levelNext--;
232 }
233 }
234 }
235 if (style == SCE_SN_OPERATOR) {
236 if (ch == '{') {
237 // Measure the minimum before a '{' to allow
238 // folding on "} else {"
239 if (levelMinCurrent > levelNext) {
240 levelMinCurrent = levelNext;
241 }
242 levelNext++;
243 } else if (ch == '}') {
244 levelNext--;
245 }
246 }
247 if (atEOL) {
248 int levelUse = levelCurrent;
249 if (foldAtElse) {
250 levelUse = levelMinCurrent;
251 }
252 int lev = levelUse | levelNext << 16;
253 if (visibleChars == 0 && foldCompact)
254 lev |= SC_FOLDLEVELWHITEFLAG;
255 if (levelUse < levelNext)
256 lev |= SC_FOLDLEVELHEADERFLAG;
257 if (lev != styler.LevelAt(lineCurrent)) {
258 styler.SetLevel(lineCurrent, lev);
259 }
260 lineCurrent++;
261 levelCurrent = levelNext;
262 levelMinCurrent = levelCurrent;
263 visibleChars = 0;
264 }
265 if (!isspacechar(ch))
266 visibleChars++;
267 }
268 }
269
FoldSpecmanDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * [],Accessor & styler)270 static void FoldSpecmanDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[],
271 Accessor &styler) {
272 FoldNoBoxSpecmanDoc(startPos, length, initStyle, styler);
273 }
274
275 static const char * const specmanWordLists[] = {
276 "Primary keywords and identifiers",
277 "Secondary keywords and identifiers",
278 "Sequence keywords and identifiers",
279 "User defined keywords and identifiers",
280 "Unused",
281 0,
282 };
283
ColouriseSpecmanDocSensitive(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler)284 static void ColouriseSpecmanDocSensitive(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
285 Accessor &styler) {
286 ColouriseSpecmanDoc(startPos, length, initStyle, keywordlists, styler, true);
287 }
288
289
290 LexerModule lmSpecman(SCLEX_SPECMAN, ColouriseSpecmanDocSensitive, "specman", FoldSpecmanDoc, specmanWordLists);
291