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