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 lvRelease5;
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
PropertyGet(const char *)82 const char * SCI_METHOD PropertyGet(const char *) override {
83 return NULL;
84 }
85
86 Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
87
PrivateCall(int,void *)88 void * SCI_METHOD PrivateCall(int, void *) override {
89 return NULL;
90 }
91
LexerFactoryDMIS()92 static ILexer5 *LexerFactoryDMIS() {
93 return new LexerDMIS;
94 }
95
96 const char * SCI_METHOD DescribeWordListSets() override;
97 void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override;
98 void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) override;
99 };
100
101
UpperCase(char * item)102 char * SCI_METHOD LexerDMIS::UpperCase(char *item)
103 {
104 char *itemStart;
105
106
107 itemStart = item;
108 while (item && *item) {
109 *item = toupper(*item);
110 item++;
111 };
112 return itemStart;
113 }
114
InitWordListSets(void)115 void SCI_METHOD LexerDMIS::InitWordListSets(void)
116 {
117 size_t totalLen = 0;
118
119
120 for (int i=0; DMISWordListDesc[i]; i++) {
121 totalLen += strlen(DMISWordListDesc[i]);
122 totalLen++;
123 };
124
125 totalLen++;
126 this->m_wordListSets = new char[totalLen];
127 memset(this->m_wordListSets, 0, totalLen);
128
129 for (int i=0; DMISWordListDesc[i]; i++) {
130 strcat(this->m_wordListSets, DMISWordListDesc[i]);
131 strcat(this->m_wordListSets, "\n");
132 };
133 }
134
135
LexerDMIS(void)136 LexerDMIS::LexerDMIS(void) : DefaultLexer("DMIS", SCLEX_DMIS) {
137 this->InitWordListSets();
138
139 this->m_majorWords.Clear();
140 this->m_minorWords.Clear();
141 this->m_unsupportedMajor.Clear();
142 this->m_unsupportedMinor.Clear();
143 this->m_codeFoldingStart.Clear();
144 this->m_codeFoldingEnd.Clear();
145 }
146
~LexerDMIS(void)147 LexerDMIS::~LexerDMIS(void) {
148 delete[] this->m_wordListSets;
149 }
150
WordListSet(int n,const char * wl)151 Sci_Position SCI_METHOD LexerDMIS::WordListSet(int n, const char *wl)
152 {
153 switch (n) {
154 case 0:
155 this->m_majorWords.Clear();
156 this->m_majorWords.Set(wl);
157 break;
158 case 1:
159 this->m_minorWords.Clear();
160 this->m_minorWords.Set(wl);
161 break;
162 case 2:
163 this->m_unsupportedMajor.Clear();
164 this->m_unsupportedMajor.Set(wl);
165 break;
166 case 3:
167 this->m_unsupportedMinor.Clear();
168 this->m_unsupportedMinor.Set(wl);
169 break;
170 case 4:
171 this->m_codeFoldingStart.Clear();
172 this->m_codeFoldingStart.Set(wl);
173 break;
174 case 5:
175 this->m_codeFoldingEnd.Clear();
176 this->m_codeFoldingEnd.Set(wl);
177 break;
178 default:
179 return -1;
180 break;
181 }
182
183 return 0;
184 }
185
DescribeWordListSets()186 const char * SCI_METHOD LexerDMIS::DescribeWordListSets()
187 {
188 return this->m_wordListSets;
189 }
190
Lex(Sci_PositionU startPos,Sci_Position lengthDoc,int initStyle,IDocument * pAccess)191 void SCI_METHOD LexerDMIS::Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess)
192 {
193 const Sci_PositionU MAX_STR_LEN = 100;
194
195 LexAccessor styler(pAccess);
196 StyleContext scCTX(startPos, lengthDoc, initStyle, styler);
197 CharacterSet setDMISNumber(CharacterSet::setDigits, ".-+eE");
198 CharacterSet setDMISWordStart(CharacterSet::setAlpha, "-234", 0x80, true);
199 CharacterSet setDMISWord(CharacterSet::setAlpha);
200
201
202 bool isIFLine = false;
203
204 for (; scCTX.More(); scCTX.Forward()) {
205 if (scCTX.atLineEnd) {
206 isIFLine = false;
207 };
208
209 switch (scCTX.state) {
210 case SCE_DMIS_DEFAULT:
211 if (scCTX.Match('$', '$')) {
212 scCTX.SetState(SCE_DMIS_COMMENT);
213 scCTX.Forward();
214 };
215 if (scCTX.Match('\'')) {
216 scCTX.SetState(SCE_DMIS_STRING);
217 };
218 if (IsADigit(scCTX.ch) || ((scCTX.Match('-') || scCTX.Match('+')) && IsADigit(scCTX.chNext))) {
219 scCTX.SetState(SCE_DMIS_NUMBER);
220 break;
221 };
222 if (setDMISWordStart.Contains(scCTX.ch)) {
223 scCTX.SetState(SCE_DMIS_KEYWORD);
224 };
225 if (scCTX.Match('(') && (!isIFLine)) {
226 scCTX.SetState(SCE_DMIS_LABEL);
227 };
228 break;
229
230 case SCE_DMIS_COMMENT:
231 if (scCTX.atLineEnd) {
232 scCTX.SetState(SCE_DMIS_DEFAULT);
233 };
234 break;
235
236 case SCE_DMIS_STRING:
237 if (scCTX.Match('\'')) {
238 scCTX.SetState(SCE_DMIS_DEFAULT);
239 };
240 break;
241
242 case SCE_DMIS_NUMBER:
243 if (!setDMISNumber.Contains(scCTX.ch)) {
244 scCTX.SetState(SCE_DMIS_DEFAULT);
245 };
246 break;
247
248 case SCE_DMIS_KEYWORD:
249 if (!setDMISWord.Contains(scCTX.ch)) {
250 char tmpStr[MAX_STR_LEN];
251 memset(tmpStr, 0, MAX_STR_LEN*sizeof(char));
252 scCTX.GetCurrent(tmpStr, (MAX_STR_LEN-1));
253 strncpy(tmpStr, this->UpperCase(tmpStr), (MAX_STR_LEN-1));
254
255 if (this->m_minorWords.InList(tmpStr)) {
256 scCTX.ChangeState(SCE_DMIS_MINORWORD);
257 };
258 if (this->m_majorWords.InList(tmpStr)) {
259 isIFLine = (strcmp(tmpStr, "IF") == 0);
260 scCTX.ChangeState(SCE_DMIS_MAJORWORD);
261 };
262 if (this->m_unsupportedMajor.InList(tmpStr)) {
263 scCTX.ChangeState(SCE_DMIS_UNSUPPORTED_MAJOR);
264 };
265 if (this->m_unsupportedMinor.InList(tmpStr)) {
266 scCTX.ChangeState(SCE_DMIS_UNSUPPORTED_MINOR);
267 };
268
269 if (scCTX.Match('(') && (!isIFLine)) {
270 scCTX.SetState(SCE_DMIS_LABEL);
271 } else {
272 scCTX.SetState(SCE_DMIS_DEFAULT);
273 };
274 };
275 break;
276
277 case SCE_DMIS_LABEL:
278 if (scCTX.Match(')')) {
279 scCTX.SetState(SCE_DMIS_DEFAULT);
280 };
281 break;
282 };
283 };
284 scCTX.Complete();
285 }
286
Fold(Sci_PositionU startPos,Sci_Position lengthDoc,int,IDocument * pAccess)287 void SCI_METHOD LexerDMIS::Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int, IDocument *pAccess)
288 {
289 const int MAX_STR_LEN = 100;
290
291 LexAccessor styler(pAccess);
292 Sci_PositionU endPos = startPos + lengthDoc;
293 char chNext = styler[startPos];
294 Sci_Position lineCurrent = styler.GetLine(startPos);
295 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
296 int levelCurrent = levelPrev;
297 int strPos = 0;
298 bool foldWordPossible = false;
299 CharacterSet setDMISFoldWord(CharacterSet::setAlpha);
300 char *tmpStr;
301
302
303 tmpStr = new char[MAX_STR_LEN];
304 memset(tmpStr, 0, MAX_STR_LEN*sizeof(char));
305
306 for (Sci_PositionU i=startPos; i<endPos; i++) {
307 char ch = chNext;
308 chNext = styler.SafeGetCharAt(i+1);
309
310 bool atEOL = ((ch == '\r' && chNext != '\n') || (ch == '\n'));
311
312 if (strPos >= (MAX_STR_LEN-1)) {
313 strPos = MAX_STR_LEN-1;
314 };
315
316 int style = styler.StyleAt(i);
317 bool noFoldPos = ((style == SCE_DMIS_COMMENT) || (style == SCE_DMIS_STRING));
318
319 if (foldWordPossible) {
320 if (setDMISFoldWord.Contains(ch)) {
321 tmpStr[strPos++] = ch;
322 } else {
323 tmpStr = this->UpperCase(tmpStr);
324 if (this->m_codeFoldingStart.InList(tmpStr) && (!noFoldPos)) {
325 levelCurrent++;
326 };
327 if (this->m_codeFoldingEnd.InList(tmpStr) && (!noFoldPos)) {
328 levelCurrent--;
329 };
330 memset(tmpStr, 0, MAX_STR_LEN*sizeof(char));
331 strPos = 0;
332 foldWordPossible = false;
333 };
334 } else {
335 if (setDMISFoldWord.Contains(ch)) {
336 tmpStr[strPos++] = ch;
337 foldWordPossible = true;
338 };
339 };
340
341 if (atEOL || (i == (endPos-1))) {
342 int lev = levelPrev;
343
344 if (levelCurrent > levelPrev) {
345 lev |= SC_FOLDLEVELHEADERFLAG;
346 };
347 if (lev != styler.LevelAt(lineCurrent)) {
348 styler.SetLevel(lineCurrent, lev);
349 };
350 lineCurrent++;
351 levelPrev = levelCurrent;
352 };
353 };
354 delete[] tmpStr;
355 }
356
357
358 LexerModule lmDMIS(SCLEX_DMIS, LexerDMIS::LexerFactoryDMIS, "DMIS", DMISWordListDesc);
359