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