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