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