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