1
// Scintilla source code edit control
2
/** @file LexABAQUS.cxx
3
** Lexer for ABAQUS. Based on the lexer for APDL by Hadar Raz.
5
** Sort of completely rewritten by Gertjan Kloosterman
7
// The License.txt file describes the conditions under which this software may be distributed.
9
// Code folding copyied and modified from LexBasic.cxx
21
#include "StyleContext.h"
23
#include "Scintilla.h"
27
using namespace Scintilla;
30
static inline bool IsAWordChar(const int ch) {
31
return (ch < 0x80 && (isalnum(ch) || (ch == '_')));
34
static inline bool IsAKeywordChar(const int ch) {
35
return (ch < 0x80 && (isalnum(ch) || (ch == '_') || (ch == ' ')));
38
static inline bool IsASetChar(const int ch) {
39
return (ch < 0x80 && (isalnum(ch) || (ch == '_') || (ch == '.') || (ch == '-')));
42
static inline bool IsAnOperator(char ch) {
43
// '.' left out as it is used to make up numbers
44
if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
45
ch == '(' || ch == ')' || ch == '=' || ch == '^' ||
46
ch == '[' || ch == ']' || ch == '<' || ch == '&' ||
47
ch == '>' || ch == ',' || ch == '|' || ch == '~' ||
48
ch == '$' || ch == ':' || ch == '%')
53
static void ColouriseABAQUSDoc(unsigned int startPos, int length, int initStyle, WordList*[] /* *keywordlists[] */,
55
enum localState { KW_LINE_KW, KW_LINE_COMMA, KW_LINE_PAR, KW_LINE_EQ, KW_LINE_VAL, \
56
DAT_LINE_VAL, DAT_LINE_COMMA,\
58
ST_ERROR, LINE_END } state ;
60
// Do not leak onto next line
62
initStyle = SCE_ABAQUS_DEFAULT;
63
StyleContext sc(startPos, length, initStyle, styler);
65
// Things are actually quite simple
66
// we have commentlines
67
// keywordlines and datalines
68
// On a data line there will only be colouring of numbers
69
// a keyword line is constructed as
70
// *word,[ paramname[=paramvalue]]*
71
// if the line ends with a , the keyword line continues onto the new line
73
for (; sc.More(); sc.Forward()) {
77
// finished the line in keyword state, switch to LINE_END
78
sc.SetState(SCE_ABAQUS_DEFAULT) ;
80
} else if ( IsAKeywordChar(sc.ch) ) {
83
} else if ( sc.ch == ',' ) {
84
// Well well we say a comma, arguments *MUST* follow
85
sc.SetState(SCE_ABAQUS_OPERATOR) ;
86
state = KW_LINE_COMMA ;
89
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
92
// Done with processing
95
// acomma on a keywordline was seen
96
if ( IsAKeywordChar(sc.ch)) {
97
sc.SetState(SCE_ABAQUS_ARGUMENT) ;
99
} else if ( sc.atLineEnd || (sc.ch == ',') ) {
100
// we remain in keyword mode
101
state = KW_LINE_COMMA ;
102
} else if ( sc.ch == ' ' ) {
103
sc.SetState(SCE_ABAQUS_DEFAULT) ;
104
state = KW_LINE_COMMA ;
106
// Anything else constitutes an error
107
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
112
if ( sc.atLineEnd ) {
113
sc.SetState(SCE_ABAQUS_DEFAULT) ;
115
} else if ( IsAKeywordChar(sc.ch) || (sc.ch == '-') ) {
116
// remain in this state
117
state = KW_LINE_PAR ;
118
} else if ( sc.ch == ',' ) {
119
sc.SetState(SCE_ABAQUS_OPERATOR) ;
120
state = KW_LINE_COMMA ;
121
} else if ( sc.ch == '=' ) {
122
sc.SetState(SCE_ABAQUS_OPERATOR) ;
125
// Anything else constitutes an error
126
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
131
if ( sc.ch == ' ' ) {
132
sc.SetState(SCE_ABAQUS_DEFAULT) ;
133
// remain in this state
135
} else if ( IsADigit(sc.ch) || (sc.ch == '-') || (sc.ch == '.' && IsADigit(sc.chNext)) ) {
136
sc.SetState(SCE_ABAQUS_NUMBER) ;
137
state = KW_LINE_VAL ;
138
} else if ( IsAKeywordChar(sc.ch) ) {
139
sc.SetState(SCE_ABAQUS_DEFAULT) ;
140
state = KW_LINE_VAL ;
141
} else if ( (sc.ch == '\'') || (sc.ch == '\"') ) {
142
sc.SetState(SCE_ABAQUS_STRING) ;
143
state = KW_LINE_VAL ;
145
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
150
if ( sc.atLineEnd ) {
151
sc.SetState(SCE_ABAQUS_DEFAULT) ;
153
} else if ( IsASetChar(sc.ch) && (sc.state == SCE_ABAQUS_DEFAULT) ) {
155
state = KW_LINE_VAL ;
156
} else if (( (IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') ||
157
((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) &&
158
(sc.state == SCE_ABAQUS_NUMBER)) {
159
// remain in number mode
160
state = KW_LINE_VAL ;
161
} else if (sc.state == SCE_ABAQUS_STRING) {
162
// accept everything until a closing quote
163
if ( sc.ch == '\'' || sc.ch == '\"' ) {
164
sc.SetState(SCE_ABAQUS_DEFAULT) ;
165
state = KW_LINE_VAL ;
167
} else if ( sc.ch == ',' ) {
168
sc.SetState(SCE_ABAQUS_OPERATOR) ;
169
state = KW_LINE_COMMA ;
171
// anything else is an error
172
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
177
if ( sc.atLineEnd ) {
178
sc.SetState(SCE_ABAQUS_DEFAULT) ;
180
} else if ( IsASetChar(sc.ch) && (sc.state == SCE_ABAQUS_DEFAULT) ) {
182
state = DAT_LINE_VAL ;
183
} else if (( (IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') ||
184
((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) &&
185
(sc.state == SCE_ABAQUS_NUMBER)) {
186
// remain in number mode
187
state = DAT_LINE_VAL ;
188
} else if (sc.state == SCE_ABAQUS_STRING) {
189
// accept everything until a closing quote
190
if ( sc.ch == '\'' || sc.ch == '\"' ) {
191
sc.SetState(SCE_ABAQUS_DEFAULT) ;
192
state = DAT_LINE_VAL ;
194
} else if ( sc.ch == ',' ) {
195
sc.SetState(SCE_ABAQUS_OPERATOR) ;
196
state = DAT_LINE_COMMA ;
198
// anything else is an error
199
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
203
case DAT_LINE_COMMA :
204
// a comma on a data line was seen
205
if ( sc.atLineEnd ) {
206
sc.SetState(SCE_ABAQUS_DEFAULT) ;
208
} else if ( sc.ch == ' ' ) {
209
sc.SetState(SCE_ABAQUS_DEFAULT) ;
210
state = DAT_LINE_COMMA ;
211
} else if (sc.ch == ',') {
212
sc.SetState(SCE_ABAQUS_OPERATOR) ;
213
state = DAT_LINE_COMMA ;
214
} else if ( IsADigit(sc.ch) || (sc.ch == '-')|| (sc.ch == '.' && IsADigit(sc.chNext)) ) {
215
sc.SetState(SCE_ABAQUS_NUMBER) ;
216
state = DAT_LINE_VAL ;
217
} else if ( IsAKeywordChar(sc.ch) ) {
218
sc.SetState(SCE_ABAQUS_DEFAULT) ;
219
state = DAT_LINE_VAL ;
220
} else if ( (sc.ch == '\'') || (sc.ch == '\"') ) {
221
sc.SetState(SCE_ABAQUS_STRING) ;
222
state = DAT_LINE_VAL ;
224
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
229
if ( sc.atLineEnd ) {
230
sc.SetState(SCE_ABAQUS_DEFAULT) ;
235
if ( sc.atLineEnd ) {
236
sc.SetState(SCE_ABAQUS_DEFAULT) ;
241
if ( sc.atLineEnd || sc.ch == ' ' ) {
244
} else if ( sc.ch == '*' ) {
245
if ( sc.chNext == '*' ) {
246
state = COMMENT_LINE ;
247
sc.SetState(SCE_ABAQUS_COMMENT) ;
250
sc.SetState(SCE_ABAQUS_STARCOMMAND) ;
253
// it must be a data line, things are as if we are in DAT_LINE_COMMA
254
if ( sc.ch == ',' ) {
255
sc.SetState(SCE_ABAQUS_OPERATOR) ;
256
state = DAT_LINE_COMMA ;
257
} else if ( IsADigit(sc.ch) || (sc.ch == '-')|| (sc.ch == '.' && IsADigit(sc.chNext)) ) {
258
sc.SetState(SCE_ABAQUS_NUMBER) ;
259
state = DAT_LINE_VAL ;
260
} else if ( IsAKeywordChar(sc.ch) ) {
261
sc.SetState(SCE_ABAQUS_DEFAULT) ;
262
state = DAT_LINE_VAL ;
263
} else if ( (sc.ch == '\'') || (sc.ch == '\"') ) {
264
sc.SetState(SCE_ABAQUS_STRING) ;
265
state = DAT_LINE_VAL ;
267
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
277
//------------------------------------------------------------------------------
278
// This copyied and modified from LexBasic.cxx
279
//------------------------------------------------------------------------------
289
static int character_classification[128] =
291
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
292
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
293
1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 10, 6,
294
60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2,
295
2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
296
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4,
297
2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
298
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0
301
static bool IsSpace(int c) {
302
return c < 128 && (character_classification[c] & 1);
305
static bool IsIdentifier(int c) {
306
return c < 128 && (character_classification[c] & 4);
309
static int LowerCase(int c)
311
if (c >= 'A' && c <= 'Z')
312
return 'a' + c - 'A';
316
static int LineEnd(int line, Accessor &styler)
318
const int docLines = styler.GetLine(styler.Length() - 1); // Available last line
320
// if the line is the last line, the eol_pos is styler.Length()
321
// eol will contain a new line, or a virtual new line
322
if ( docLines == line )
323
eol_pos = styler.Length() ;
325
eol_pos = styler.LineStart(line + 1) - 1;
329
static int LineStart(int line, Accessor &styler)
331
return styler.LineStart(line) ;
336
// bits determines the line type
338
// 2 : only whitespace
339
// 3 : data line with only whitespace
341
// 5 : block open keyword line
342
// 6 : block close keyword line
343
// 7 : keyword line in error
345
static int LineType(int line, Accessor &styler) {
346
int pos = LineStart(line, styler) ;
347
int eol_pos = LineEnd(line, styler) ;
353
while ( i < eol_pos ) {
354
c = styler.SafeGetCharAt(i);
355
ch = static_cast<char>(LowerCase(c));
356
// We can say something as soon as no whitespace
363
if ( i >= eol_pos ) {
364
// This is a whitespace line, currently
365
// classifies as data line
370
// This is a data line
374
if ( i == eol_pos - 1 ) {
375
// Only a single *, error but make keyword line
379
// This means we can have a second character
380
// if that is also a * this means a comment
381
// otherwise it is a keyword.
382
c = styler.SafeGetCharAt(i+1);
383
ch = static_cast<char>(LowerCase(c));
388
// At this point we know this is a keyword line
389
// the character at position i is a *
390
// it is not a comment line
398
while ( (i < eol_pos) && (wlen < 255) ) {
399
c = styler.SafeGetCharAt(i);
400
ch = static_cast<char>(LowerCase(c));
402
if ( (!IsSpace(c)) && (!IsIdentifier(c)) )
405
if ( IsIdentifier(c) ) {
416
if ( !strcmp(word, "*step") ||
417
!strcmp(word, "*part") ||
418
!strcmp(word, "*instance") ||
419
!strcmp(word, "*assembly")) {
423
if ( !strcmp(word, "*endstep") ||
424
!strcmp(word, "*endpart") ||
425
!strcmp(word, "*endinstance") ||
426
!strcmp(word, "*endassembly")) {
433
static void SafeSetLevel(int line, int level, Accessor &styler)
438
int mask = ((~SC_FOLDLEVELHEADERFLAG) | (~SC_FOLDLEVELWHITEFLAG));
440
if ( (level & mask) < 0 )
443
if ( styler.LevelAt(line) != level )
444
styler.SetLevel(line, level) ;
447
static void FoldABAQUSDoc(unsigned int startPos, int length, int,
448
WordList *[], Accessor &styler) {
449
int startLine = styler.GetLine(startPos) ;
450
int endLine = styler.GetLine(startPos+length-1) ;
452
// bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
453
// We want to deal with all the cases
454
// To know the correct indentlevel, we need to look back to the
455
// previous command line indentation level
456
// order of formatting keyline datalines commentlines
458
int beginComment = -1 ;
459
int prvKeyLine = startLine ;
460
int prvKeyLineTp = 0 ;
462
// Scan until we find the previous keyword line
463
// this will give us the level reference that we need
464
while ( prvKeyLine > 0 ) {
466
prvKeyLineTp = LineType(prvKeyLine, styler) ;
467
if ( prvKeyLineTp & 4 )
471
// Determine the base line level of all lines following
472
// the previous keyword
473
// new keyword lines are placed on this level
474
//if ( prvKeyLineTp & 4 ) {
475
int level = styler.LevelAt(prvKeyLine) & ~SC_FOLDLEVELHEADERFLAG ;
478
// uncomment line below if weird behaviour continues
481
// Now start scanning over the lines.
482
for ( int line = startLine; line <= endLine; line++ ) {
483
int lineType = LineType(line, styler) ;
485
// Check for comment line
486
if ( lineType == 8 ) {
487
if ( beginComment < 0 ) {
488
beginComment = line ;
492
// Check for data line
493
if ( (lineType == 1) || (lineType == 3) ) {
494
if ( beginData < 0 ) {
495
if ( beginComment >= 0 ) {
496
beginData = beginComment ;
504
// Check for keywordline.
505
// As soon as a keyword line is encountered, we can set the
506
// levels of everything from the previous keyword line to this one
507
if ( lineType & 4 ) {
508
// this is a keyword, we can now place the previous keyword
509
// all its data lines and the remainder
511
// Write comments and data line
512
if ( beginComment < 0 ) {
513
beginComment = line ;
516
if ( beginData < 0 ) {
517
beginData = beginComment ;
518
if ( prvKeyLineTp != 5 )
519
SafeSetLevel(prvKeyLine, level, styler) ;
521
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
523
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
526
int datLevel = level + 1 ;
527
if ( !(prvKeyLineTp & 4) ) {
531
for ( int ll = beginData; ll < beginComment; ll++ )
532
SafeSetLevel(ll, datLevel, styler) ;
534
// The keyword we just found is going to be written at another level
535
// if we have a type 5 and type 6
536
if ( prvKeyLineTp == 5 ) {
540
if ( prvKeyLineTp == 6 ) {
547
for ( int lll = beginComment; lll < line; lll++ )
548
SafeSetLevel(lll, level, styler) ;
554
prvKeyLineTp = lineType ;
559
if ( beginComment < 0 ) {
560
beginComment = endLine + 1 ;
562
// We need to find out whether this comment block is followed by
563
// a data line or a keyword line
564
const int docLines = styler.GetLine(styler.Length() - 1);
566
for ( int line = endLine + 1; line <= docLines; line++ ) {
567
int lineType = LineType(line, styler) ;
569
if ( lineType != 8 ) {
570
if ( !(lineType & 4) ) {
571
beginComment = endLine + 1 ;
578
if ( beginData < 0 ) {
579
beginData = beginComment ;
580
if ( prvKeyLineTp != 5 )
581
SafeSetLevel(prvKeyLine, level, styler) ;
583
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
585
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
588
int datLevel = level + 1 ;
589
if ( !(prvKeyLineTp & 4) ) {
593
for ( int ll = beginData; ll < beginComment; ll++ )
594
SafeSetLevel(ll, datLevel, styler) ;
596
if ( prvKeyLineTp == 5 ) {
600
if ( prvKeyLineTp == 6 ) {
603
for ( int m = beginComment; m <= endLine; m++ )
604
SafeSetLevel(m, level, styler) ;
607
static const char * const abaqusWordListDesc[] = {
617
LexerModule lmAbaqus(SCLEX_ABAQUS, ColouriseABAQUSDoc, "abaqus", FoldABAQUSDoc, abaqusWordListDesc);