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