1 // Scintilla source code edit control
2 /** @file LexDMIS.cxx
3 ** Lexer for DMIS.
4 **/
5 // Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
6 // Copyright 2013-2014 by Andreas Tscharner <andy@vis.ethz.ch>
7 // The License.txt file describes the conditions under which this software may be distributed.
8
9
10 #include <cstdlib>
11 #include <cassert>
12 #include <cstring>
13 #include <cctype>
14
15 #include "ILexer.h"
16 #include "Scintilla.h"
17 #include "SciLexer.h"
18
19 #include "WordList.h"
20 #include "LexAccessor.h"
21 #include "StyleContext.h"
22 #include "CharacterSet.h"
23 #include "LexerModule.h"
24 #include "DefaultLexer.h"
25
26 using namespace Scintilla;
27
28
29 static const char *const DMISWordListDesc[] = {
30 "DMIS Major Words",
31 "DMIS Minor Words",
32 "Unsupported DMIS Major Words",
33 "Unsupported DMIS Minor Words",
34 "Keywords for code folding start",
35 "Corresponding keywords for code folding end",
36 0
37 };
38
39
40 class LexerDMIS : public DefaultLexer
41 {
42 private:
43 char *m_wordListSets;
44 WordList m_majorWords;
45 WordList m_minorWords;
46 WordList m_unsupportedMajor;
47 WordList m_unsupportedMinor;
48 WordList m_codeFoldingStart;
49 WordList m_codeFoldingEnd;
50
51 char * SCI_METHOD UpperCase(char *item);
52 void SCI_METHOD InitWordListSets(void);
53
54 public:
55 LexerDMIS(void);
56 virtual ~LexerDMIS(void);
57
Version() const58 int SCI_METHOD Version() const override {
59 return lvOriginal;
60 }
61
Release()62 void SCI_METHOD Release() override {
63 delete this;
64 }
65
PropertyNames()66 const char * SCI_METHOD PropertyNames() override {
67 return NULL;
68 }
69
PropertyType(const char *)70 int SCI_METHOD PropertyType(const char *) override {
71 return -1;
72 }
73
DescribeProperty(const char *)74 const char * SCI_METHOD DescribeProperty(const char *) override {
75 return NULL;
76 }
77
PropertySet(const char *,const char *)78 Sci_Position SCI_METHOD PropertySet(const char *, const char *) override {
79 return -1;
80 }
81
82 Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
83
PrivateCall(int,void *)84 void * SCI_METHOD PrivateCall(int, void *) override {
85 return NULL;
86 }
87
LexerFactoryDMIS()88 static ILexer *LexerFactoryDMIS() {
89 return new LexerDMIS;
90 }
91
92 const char * SCI_METHOD DescribeWordListSets() override;
93 void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override;
94 void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override;
95 };
96
97
UpperCase(char * item)98 char * SCI_METHOD LexerDMIS::UpperCase(char *item)
99 {
100 char *itemStart;
101
102
103 itemStart = item;
104 while (item && *item) {
105 *item = toupper(*item);
106 item++;
107 };
108 return itemStart;
109 }
110
InitWordListSets(void)111 void SCI_METHOD LexerDMIS::InitWordListSets(void)
112 {
113 size_t totalLen = 0;
114
115
116 for (int i=0; DMISWordListDesc[i]; i++) {
117 totalLen += strlen(DMISWordListDesc[i]);
118 totalLen++;
119 };
120
121 totalLen++;
122 this->m_wordListSets = new char[totalLen];
123 memset(this->m_wordListSets, 0, totalLen);
124
125 for (int i=0; DMISWordListDesc[i]; i++) {
126 strcat(this->m_wordListSets, DMISWordListDesc[i]);
127 strcat(this->m_wordListSets, "\n");
128 };
129 }
130
131
LexerDMIS(void)132 LexerDMIS::LexerDMIS(void) {
133 this->InitWordListSets();
134
135 this->m_majorWords.Clear();
136 this->m_minorWords.Clear();
137 this->m_unsupportedMajor.Clear();
138 this->m_unsupportedMinor.Clear();
139 this->m_codeFoldingStart.Clear();
140 this->m_codeFoldingEnd.Clear();
141 }
142
~LexerDMIS(void)143 LexerDMIS::~LexerDMIS(void) {
144 delete[] this->m_wordListSets;
145 }
146
WordListSet(int n,const char * wl)147 Sci_Position SCI_METHOD LexerDMIS::WordListSet(int n, const char *wl)
148 {
149 switch (n) {
150 case 0:
151 this->m_majorWords.Clear();
152 this->m_majorWords.Set(wl);
153 break;
154 case 1:
155 this->m_minorWords.Clear();
156 this->m_minorWords.Set(wl);
157 break;
158 case 2:
159 this->m_unsupportedMajor.Clear();
160 this->m_unsupportedMajor.Set(wl);
161 break;
162 case 3:
163 this->m_unsupportedMinor.Clear();
164 this->m_unsupportedMinor.Set(wl);
165 break;
166 case 4:
167 this->m_codeFoldingStart.Clear();
168 this->m_codeFoldingStart.Set(wl);
169 break;
170 case 5:
171 this->m_codeFoldingEnd.Clear();
172 this->m_codeFoldingEnd.Set(wl);
173 break;
174 default:
175 return -1;
176 break;
177 }
178
179 return 0;
180 }
181
DescribeWordListSets()182 const char * SCI_METHOD LexerDMIS::DescribeWordListSets()
183 {
184 return this->m_wordListSets;
185 }
186
Lex(Sci_PositionU startPos,Sci_Position lengthDoc,int initStyle,IDocument * pAccess)187 void SCI_METHOD LexerDMIS::Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess)
188 {
189 const Sci_PositionU MAX_STR_LEN = 100;
190
191 LexAccessor styler(pAccess);
192 StyleContext scCTX(startPos, lengthDoc, initStyle, styler);
193 CharacterSet setDMISNumber(CharacterSet::setDigits, ".-+eE");
194 CharacterSet setDMISWordStart(CharacterSet::setAlpha, "-234", 0x80, true);
195 CharacterSet setDMISWord(CharacterSet::setAlpha);
196
197
198 bool isIFLine = false;
199
200 for (; scCTX.More(); scCTX.Forward()) {
201 if (scCTX.atLineEnd) {
202 isIFLine = false;
203 };
204
205 switch (scCTX.state) {
206 case SCE_DMIS_DEFAULT:
207 if (scCTX.Match('$', '$')) {
208 scCTX.SetState(SCE_DMIS_COMMENT);
209 scCTX.Forward();
210 };
211 if (scCTX.Match('\'')) {
212 scCTX.SetState(SCE_DMIS_STRING);
213 };
214 if (IsADigit(scCTX.ch) || ((scCTX.Match('-') || scCTX.Match('+')) && IsADigit(scCTX.chNext))) {
215 scCTX.SetState(SCE_DMIS_NUMBER);
216 break;
217 };
218 if (setDMISWordStart.Contains(scCTX.ch)) {
219 scCTX.SetState(SCE_DMIS_KEYWORD);
220 };
221 if (scCTX.Match('(') && (!isIFLine)) {
222 scCTX.SetState(SCE_DMIS_LABEL);
223 };
224 break;
225
226 case SCE_DMIS_COMMENT:
227 if (scCTX.atLineEnd) {
228 scCTX.SetState(SCE_DMIS_DEFAULT);
229 };
230 break;
231
232 case SCE_DMIS_STRING:
233 if (scCTX.Match('\'')) {
234 scCTX.SetState(SCE_DMIS_DEFAULT);
235 };
236 break;
237
238 case SCE_DMIS_NUMBER:
239 if (!setDMISNumber.Contains(scCTX.ch)) {
240 scCTX.SetState(SCE_DMIS_DEFAULT);
241 };
242 break;
243
244 case SCE_DMIS_KEYWORD:
245 if (!setDMISWord.Contains(scCTX.ch)) {
246 char tmpStr[MAX_STR_LEN];
247 memset(tmpStr, 0, MAX_STR_LEN*sizeof(char));
248 scCTX.GetCurrent(tmpStr, (MAX_STR_LEN-1));
249 strncpy(tmpStr, this->UpperCase(tmpStr), (MAX_STR_LEN-1));
250
251 if (this->m_minorWords.InList(tmpStr)) {
252 scCTX.ChangeState(SCE_DMIS_MINORWORD);
253 };
254 if (this->m_majorWords.InList(tmpStr)) {
255 isIFLine = (strcmp(tmpStr, "IF") == 0);
256 scCTX.ChangeState(SCE_DMIS_MAJORWORD);
257 };
258 if (this->m_unsupportedMajor.InList(tmpStr)) {
259 scCTX.ChangeState(SCE_DMIS_UNSUPPORTED_MAJOR);
260 };
261 if (this->m_unsupportedMinor.InList(tmpStr)) {
262 scCTX.ChangeState(SCE_DMIS_UNSUPPORTED_MINOR);
263 };
264
265 if (scCTX.Match('(') && (!isIFLine)) {
266 scCTX.SetState(SCE_DMIS_LABEL);
267 } else {
268 scCTX.SetState(SCE_DMIS_DEFAULT);
269 };
270 };
271 break;
272
273 case SCE_DMIS_LABEL:
274 if (scCTX.Match(')')) {
275 scCTX.SetState(SCE_DMIS_DEFAULT);
276 };
277 break;
278 };
279 };
280 scCTX.Complete();
281 }
282
Fold(Sci_PositionU startPos,Sci_Position lengthDoc,int,IDocument * pAccess)283 void SCI_METHOD LexerDMIS::Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int, IDocument *pAccess)
284 {
285 const int MAX_STR_LEN = 100;
286
287 LexAccessor styler(pAccess);
288 Sci_PositionU endPos = startPos + lengthDoc;
289 char chNext = styler[startPos];
290 Sci_Position lineCurrent = styler.GetLine(startPos);
291 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
292 int levelCurrent = levelPrev;
293 int strPos = 0;
294 bool foldWordPossible = false;
295 CharacterSet setDMISFoldWord(CharacterSet::setAlpha);
296 char *tmpStr;
297
298
299 tmpStr = new char[MAX_STR_LEN];
300 memset(tmpStr, 0, MAX_STR_LEN*sizeof(char));
301
302 for (Sci_PositionU i=startPos; i<endPos; i++) {
303 char ch = chNext;
304 chNext = styler.SafeGetCharAt(i+1);
305
306 bool atEOL = ((ch == '\r' && chNext != '\n') || (ch == '\n'));
307
308 if (strPos >= (MAX_STR_LEN-1)) {
309 strPos = MAX_STR_LEN-1;
310 };
311
312 int style = styler.StyleAt(i);
313 bool noFoldPos = ((style == SCE_DMIS_COMMENT) || (style == SCE_DMIS_STRING));
314
315 if (foldWordPossible) {
316 if (setDMISFoldWord.Contains(ch)) {
317 tmpStr[strPos++] = ch;
318 } else {
319 tmpStr = this->UpperCase(tmpStr);
320 if (this->m_codeFoldingStart.InList(tmpStr) && (!noFoldPos)) {
321 levelCurrent++;
322 };
323 if (this->m_codeFoldingEnd.InList(tmpStr) && (!noFoldPos)) {
324 levelCurrent--;
325 };
326 memset(tmpStr, 0, MAX_STR_LEN*sizeof(char));
327 strPos = 0;
328 foldWordPossible = false;
329 };
330 } else {
331 if (setDMISFoldWord.Contains(ch)) {
332 tmpStr[strPos++] = ch;
333 foldWordPossible = true;
334 };
335 };
336
337 if (atEOL || (i == (endPos-1))) {
338 int lev = levelPrev;
339
340 if (levelCurrent > levelPrev) {
341 lev |= SC_FOLDLEVELHEADERFLAG;
342 };
343 if (lev != styler.LevelAt(lineCurrent)) {
344 styler.SetLevel(lineCurrent, lev);
345 };
346 lineCurrent++;
347 levelPrev = levelCurrent;
348 };
349 };
350 delete[] tmpStr;
351 }
352
353
354 LexerModule lmDMIS(SCLEX_DMIS, LexerDMIS::LexerFactoryDMIS, "DMIS", DMISWordListDesc);
355