1 // Scintilla source code edit control
2 /** @file LexAPDL.cxx
3  ** Lexer for APDL. Based on the lexer for Assembler by The Black Horus.
4  ** By Hadar Raz.
5  **/
6 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8 
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
15 
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
19 
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
26 
27 using namespace Scintilla;
28 
IsAWordChar(const int ch)29 static inline bool IsAWordChar(const int ch) {
30 	return (ch < 0x80 && (isalnum(ch) || ch == '_'));
31 }
32 
IsAnOperator(char ch)33 static inline bool IsAnOperator(char ch) {
34 	// '.' left out as it is used to make up numbers
35 	if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
36 		ch == '(' || ch == ')' || ch == '=' || ch == '^' ||
37 		ch == '[' || ch == ']' || ch == '<' || ch == '&' ||
38 		ch == '>' || ch == ',' || ch == '|' || ch == '~' ||
39 		ch == '$' || ch == ':' || ch == '%')
40 		return true;
41 	return false;
42 }
43 
ColouriseAPDLDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler)44 static void ColouriseAPDLDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
45                             Accessor &styler) {
46 
47 	int stringStart = ' ';
48 
49 	WordList &processors = *keywordlists[0];
50 	WordList &commands = *keywordlists[1];
51 	WordList &slashcommands = *keywordlists[2];
52 	WordList &starcommands = *keywordlists[3];
53 	WordList &arguments = *keywordlists[4];
54 	WordList &functions = *keywordlists[5];
55 
56 	// Do not leak onto next line
57 	initStyle = SCE_APDL_DEFAULT;
58 	StyleContext sc(startPos, length, initStyle, styler);
59 
60 	for (; sc.More(); sc.Forward()) {
61 		// Determine if the current state should terminate.
62 		if (sc.state == SCE_APDL_NUMBER) {
63 			if (!(IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') ||
64 				((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) {
65 				sc.SetState(SCE_APDL_DEFAULT);
66 			}
67 		} else if (sc.state == SCE_APDL_COMMENT) {
68 			if (sc.atLineEnd) {
69 				sc.SetState(SCE_APDL_DEFAULT);
70 			}
71 		} else if (sc.state == SCE_APDL_COMMENTBLOCK) {
72 			if (sc.atLineEnd) {
73 				if (sc.ch == '\r') {
74 				sc.Forward();
75 				}
76 				sc.ForwardSetState(SCE_APDL_DEFAULT);
77 			}
78 		} else if (sc.state == SCE_APDL_STRING) {
79 			if (sc.atLineEnd) {
80 				sc.SetState(SCE_APDL_DEFAULT);
81 			} else if ((sc.ch == '\'' && stringStart == '\'') || (sc.ch == '\"' && stringStart == '\"')) {
82 				sc.ForwardSetState(SCE_APDL_DEFAULT);
83 			}
84 		} else if (sc.state == SCE_APDL_WORD) {
85 			if (!IsAWordChar(sc.ch)) {
86 				char s[100];
87 				sc.GetCurrentLowered(s, sizeof(s));
88 				if (processors.InList(s)) {
89 					sc.ChangeState(SCE_APDL_PROCESSOR);
90 				} else if (slashcommands.InList(s)) {
91 					sc.ChangeState(SCE_APDL_SLASHCOMMAND);
92 				} else if (starcommands.InList(s)) {
93 					sc.ChangeState(SCE_APDL_STARCOMMAND);
94 				} else if (commands.InList(s)) {
95 					sc.ChangeState(SCE_APDL_COMMAND);
96 				} else if (arguments.InList(s)) {
97 					sc.ChangeState(SCE_APDL_ARGUMENT);
98 				} else if (functions.InList(s)) {
99 					sc.ChangeState(SCE_APDL_FUNCTION);
100 				}
101 				sc.SetState(SCE_APDL_DEFAULT);
102 			}
103 		} else if (sc.state == SCE_APDL_OPERATOR) {
104 			if (!IsAnOperator(static_cast<char>(sc.ch))) {
105 			    sc.SetState(SCE_APDL_DEFAULT);
106 			}
107 		}
108 
109 		// Determine if a new state should be entered.
110 		if (sc.state == SCE_APDL_DEFAULT) {
111 			if (sc.ch == '!' && sc.chNext == '!') {
112 				sc.SetState(SCE_APDL_COMMENTBLOCK);
113 			} else if (sc.ch == '!') {
114 				sc.SetState(SCE_APDL_COMMENT);
115 			} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
116 				sc.SetState(SCE_APDL_NUMBER);
117 			} else if (sc.ch == '\'' || sc.ch == '\"') {
118 				sc.SetState(SCE_APDL_STRING);
119 				stringStart = sc.ch;
120 			} else if (IsAWordChar(sc.ch) || ((sc.ch == '*' || sc.ch == '/') && !isgraph(sc.chPrev))) {
121 				sc.SetState(SCE_APDL_WORD);
122 			} else if (IsAnOperator(static_cast<char>(sc.ch))) {
123 				sc.SetState(SCE_APDL_OPERATOR);
124 			}
125 		}
126 	}
127 	sc.Complete();
128 }
129 
130 //------------------------------------------------------------------------------
131 // 06-27-07 Sergio Lucato
132 // - Included code folding for Ansys APDL lexer
133 // - Copyied from LexBasic.cxx and modified for APDL
134 //------------------------------------------------------------------------------
135 
136 /* Bits:
137  * 1  - whitespace
138  * 2  - operator
139  * 4  - identifier
140  * 8  - decimal digit
141  * 16 - hex digit
142  * 32 - bin digit
143  */
144 static int character_classification[128] =
145 {
146     0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0,  0,  1,  0,  0,
147     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
148     1,  2,  0,  2,  2,  2,  2,  2,  2,  2,  6,  2,  2,  2,  10, 6,
149     60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2,  2,  2,  2,  2,  2,
150     2,  20, 20, 20, 20, 20, 20, 4,  4,  4,  4,  4,  4,  4,  4,  4,
151     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  2,  4,
152     2,  20, 20, 20, 20, 20, 20, 4,  4,  4,  4,  4,  4,  4,  4,  4,
153     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  2,  0
154 };
155 
IsSpace(int c)156 static bool IsSpace(int c) {
157 	return c < 128 && (character_classification[c] & 1);
158 }
159 
IsIdentifier(int c)160 static bool IsIdentifier(int c) {
161 	return c < 128 && (character_classification[c] & 4);
162 }
163 
LowerCase(int c)164 static int LowerCase(int c)
165 {
166 	if (c >= 'A' && c <= 'Z')
167 		return 'a' + c - 'A';
168 	return c;
169 }
170 
CheckAPDLFoldPoint(char const * token,int & level)171 static int CheckAPDLFoldPoint(char const *token, int &level) {
172 	if (!strcmp(token, "*if") ||
173 		!strcmp(token, "*do") ||
174 		!strcmp(token, "*dowhile") ) {
175 		level |= SC_FOLDLEVELHEADERFLAG;
176 		return 1;
177 	}
178 	if (!strcmp(token, "*endif") ||
179 		!strcmp(token, "*enddo") ) {
180 		return -1;
181 	}
182 	return 0;
183 }
184 
FoldAPDLDoc(Sci_PositionU startPos,Sci_Position length,int,WordList * [],Accessor & styler)185 static void FoldAPDLDoc(Sci_PositionU startPos, Sci_Position length, int,
186 	WordList *[], Accessor &styler) {
187 
188 	Sci_Position line = styler.GetLine(startPos);
189 	int level = styler.LevelAt(line);
190 	int go = 0, done = 0;
191 	Sci_Position endPos = startPos + length;
192 	char word[256];
193 	int wordlen = 0;
194 	Sci_Position i;
195     bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
196 	// Scan for tokens at the start of the line (they may include
197 	// whitespace, for tokens like "End Function"
198 	for (i = startPos; i < endPos; i++) {
199 		int c = styler.SafeGetCharAt(i);
200 		if (!done && !go) {
201 			if (wordlen) { // are we scanning a token already?
202 				word[wordlen] = static_cast<char>(LowerCase(c));
203 				if (!IsIdentifier(c)) { // done with token
204 					word[wordlen] = '\0';
205 					go = CheckAPDLFoldPoint(word, level);
206 					if (!go) {
207 						// Treat any whitespace as single blank, for
208 						// things like "End   Function".
209 						if (IsSpace(c) && IsIdentifier(word[wordlen - 1])) {
210 							word[wordlen] = ' ';
211 							if (wordlen < 255)
212 								wordlen++;
213 						}
214 						else // done with this line
215 							done = 1;
216 					}
217 				} else if (wordlen < 255) {
218 					wordlen++;
219 				}
220 			} else { // start scanning at first non-whitespace character
221 				if (!IsSpace(c)) {
222 					if (IsIdentifier(c)) {
223 						word[0] = static_cast<char>(LowerCase(c));
224 						wordlen = 1;
225 					} else // done with this line
226 						done = 1;
227 				}
228 			}
229 		}
230 		if (c == '\n') { // line end
231 			if (!done && wordlen == 0 && foldCompact) // line was only space
232 				level |= SC_FOLDLEVELWHITEFLAG;
233 			if (level != styler.LevelAt(line))
234 				styler.SetLevel(line, level);
235 			level += go;
236 			line++;
237 			// reset state
238 			wordlen = 0;
239 			level &= ~SC_FOLDLEVELHEADERFLAG;
240 			level &= ~SC_FOLDLEVELWHITEFLAG;
241 			go = 0;
242 			done = 0;
243 		}
244 	}
245 }
246 
247 static const char * const apdlWordListDesc[] = {
248     "processors",
249     "commands",
250     "slashommands",
251     "starcommands",
252     "arguments",
253     "functions",
254     0
255 };
256 
257 LexerModule lmAPDL(SCLEX_APDL, ColouriseAPDLDoc, "apdl", FoldAPDLDoc, apdlWordListDesc);
258