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
19
#include "Scintilla.h"
23
#include "LexAccessor.h"
25
#include "StyleContext.h"
26
#include "CharacterSet.h"
27
#include "LexerModule.h"
30
using namespace Scintilla;
33
static inline bool IsAWordChar(const int ch) {
34
return (ch < 0x80 && (isalnum(ch) || (ch == '_')));
37
static inline bool IsAKeywordChar(const int ch) {
38
return (ch < 0x80 && (isalnum(ch) || (ch == '_') || (ch == ' ')));
41
static inline bool IsASetChar(const int ch) {
42
return (ch < 0x80 && (isalnum(ch) || (ch == '_') || (ch == '.') || (ch == '-')));
45
static inline bool IsAnOperator(char ch) {
46
// '.' left out as it is used to make up numbers
47
if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
48
ch == '(' || ch == ')' || ch == '=' || ch == '^' ||
49
ch == '[' || ch == ']' || ch == '<' || ch == '&' ||
50
ch == '>' || ch == ',' || ch == '|' || ch == '~' ||
51
ch == '$' || ch == ':' || ch == '%')
56
static void ColouriseABAQUSDoc(unsigned int startPos, int length, int initStyle, WordList*[] /* *keywordlists[] */,
58
enum localState { KW_LINE_KW, KW_LINE_COMMA, KW_LINE_PAR, KW_LINE_EQ, KW_LINE_VAL, \
59
DAT_LINE_VAL, DAT_LINE_COMMA,\
61
ST_ERROR, LINE_END } state ;
63
// Do not leak onto next line
65
initStyle = SCE_ABAQUS_DEFAULT;
66
StyleContext sc(startPos, length, initStyle, styler);
68
// Things are actually quite simple
69
// we have commentlines
70
// keywordlines and datalines
71
// On a data line there will only be colouring of numbers
72
// a keyword line is constructed as
73
// *word,[ paramname[=paramvalue]]*
74
// if the line ends with a , the keyword line continues onto the new line
76
for (; sc.More(); sc.Forward()) {
80
// finished the line in keyword state, switch to LINE_END
81
sc.SetState(SCE_ABAQUS_DEFAULT) ;
83
} else if ( IsAKeywordChar(sc.ch) ) {
86
} else if ( sc.ch == ',' ) {
87
// Well well we say a comma, arguments *MUST* follow
88
sc.SetState(SCE_ABAQUS_OPERATOR) ;
89
state = KW_LINE_COMMA ;
92
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
95
// Done with processing
98
// acomma on a keywordline was seen
99
if ( IsAKeywordChar(sc.ch)) {
100
sc.SetState(SCE_ABAQUS_ARGUMENT) ;
101
state = KW_LINE_PAR ;
102
} else if ( sc.atLineEnd || (sc.ch == ',') ) {
103
// we remain in keyword mode
104
state = KW_LINE_COMMA ;
105
} else if ( sc.ch == ' ' ) {
106
sc.SetState(SCE_ABAQUS_DEFAULT) ;
107
state = KW_LINE_COMMA ;
109
// Anything else constitutes an error
110
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
115
if ( sc.atLineEnd ) {
116
sc.SetState(SCE_ABAQUS_DEFAULT) ;
118
} else if ( IsAKeywordChar(sc.ch) || (sc.ch == '-') ) {
119
// remain in this state
120
state = KW_LINE_PAR ;
121
} else if ( sc.ch == ',' ) {
122
sc.SetState(SCE_ABAQUS_OPERATOR) ;
123
state = KW_LINE_COMMA ;
124
} else if ( sc.ch == '=' ) {
125
sc.SetState(SCE_ABAQUS_OPERATOR) ;
128
// Anything else constitutes an error
129
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
134
if ( sc.ch == ' ' ) {
135
sc.SetState(SCE_ABAQUS_DEFAULT) ;
136
// remain in this state
138
} else if ( IsADigit(sc.ch) || (sc.ch == '-') || (sc.ch == '.' && IsADigit(sc.chNext)) ) {
139
sc.SetState(SCE_ABAQUS_NUMBER) ;
140
state = KW_LINE_VAL ;
141
} else if ( IsAKeywordChar(sc.ch) ) {
142
sc.SetState(SCE_ABAQUS_DEFAULT) ;
143
state = KW_LINE_VAL ;
144
} else if ( (sc.ch == '\'') || (sc.ch == '\"') ) {
145
sc.SetState(SCE_ABAQUS_STRING) ;
146
state = KW_LINE_VAL ;
148
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
153
if ( sc.atLineEnd ) {
154
sc.SetState(SCE_ABAQUS_DEFAULT) ;
156
} else if ( IsASetChar(sc.ch) && (sc.state == SCE_ABAQUS_DEFAULT) ) {
158
state = KW_LINE_VAL ;
159
} else if (( (IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') ||
160
((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) &&
161
(sc.state == SCE_ABAQUS_NUMBER)) {
162
// remain in number mode
163
state = KW_LINE_VAL ;
164
} else if (sc.state == SCE_ABAQUS_STRING) {
165
// accept everything until a closing quote
166
if ( sc.ch == '\'' || sc.ch == '\"' ) {
167
sc.SetState(SCE_ABAQUS_DEFAULT) ;
168
state = KW_LINE_VAL ;
170
} else if ( sc.ch == ',' ) {
171
sc.SetState(SCE_ABAQUS_OPERATOR) ;
172
state = KW_LINE_COMMA ;
174
// anything else is an error
175
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
180
if ( sc.atLineEnd ) {
181
sc.SetState(SCE_ABAQUS_DEFAULT) ;
183
} else if ( IsASetChar(sc.ch) && (sc.state == SCE_ABAQUS_DEFAULT) ) {
185
state = DAT_LINE_VAL ;
186
} else if (( (IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') ||
187
((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) &&
188
(sc.state == SCE_ABAQUS_NUMBER)) {
189
// remain in number mode
190
state = DAT_LINE_VAL ;
191
} else if (sc.state == SCE_ABAQUS_STRING) {
192
// accept everything until a closing quote
193
if ( sc.ch == '\'' || sc.ch == '\"' ) {
194
sc.SetState(SCE_ABAQUS_DEFAULT) ;
195
state = DAT_LINE_VAL ;
197
} else if ( sc.ch == ',' ) {
198
sc.SetState(SCE_ABAQUS_OPERATOR) ;
199
state = DAT_LINE_COMMA ;
201
// anything else is an error
202
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
206
case DAT_LINE_COMMA :
207
// a comma on a data line was seen
208
if ( sc.atLineEnd ) {
209
sc.SetState(SCE_ABAQUS_DEFAULT) ;
211
} else if ( sc.ch == ' ' ) {
212
sc.SetState(SCE_ABAQUS_DEFAULT) ;
213
state = DAT_LINE_COMMA ;
214
} else if (sc.ch == ',') {
215
sc.SetState(SCE_ABAQUS_OPERATOR) ;
216
state = DAT_LINE_COMMA ;
217
} else if ( IsADigit(sc.ch) || (sc.ch == '-')|| (sc.ch == '.' && IsADigit(sc.chNext)) ) {
218
sc.SetState(SCE_ABAQUS_NUMBER) ;
219
state = DAT_LINE_VAL ;
220
} else if ( IsAKeywordChar(sc.ch) ) {
221
sc.SetState(SCE_ABAQUS_DEFAULT) ;
222
state = DAT_LINE_VAL ;
223
} else if ( (sc.ch == '\'') || (sc.ch == '\"') ) {
224
sc.SetState(SCE_ABAQUS_STRING) ;
225
state = DAT_LINE_VAL ;
227
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
232
if ( sc.atLineEnd ) {
233
sc.SetState(SCE_ABAQUS_DEFAULT) ;
238
if ( sc.atLineEnd ) {
239
sc.SetState(SCE_ABAQUS_DEFAULT) ;
244
if ( sc.atLineEnd || sc.ch == ' ' ) {
247
} else if ( sc.ch == '*' ) {
248
if ( sc.chNext == '*' ) {
249
state = COMMENT_LINE ;
250
sc.SetState(SCE_ABAQUS_COMMENT) ;
253
sc.SetState(SCE_ABAQUS_STARCOMMAND) ;
256
// it must be a data line, things are as if we are in DAT_LINE_COMMA
257
if ( sc.ch == ',' ) {
258
sc.SetState(SCE_ABAQUS_OPERATOR) ;
259
state = DAT_LINE_COMMA ;
260
} else if ( IsADigit(sc.ch) || (sc.ch == '-')|| (sc.ch == '.' && IsADigit(sc.chNext)) ) {
261
sc.SetState(SCE_ABAQUS_NUMBER) ;
262
state = DAT_LINE_VAL ;
263
} else if ( IsAKeywordChar(sc.ch) ) {
264
sc.SetState(SCE_ABAQUS_DEFAULT) ;
265
state = DAT_LINE_VAL ;
266
} else if ( (sc.ch == '\'') || (sc.ch == '\"') ) {
267
sc.SetState(SCE_ABAQUS_STRING) ;
268
state = DAT_LINE_VAL ;
270
sc.SetState(SCE_ABAQUS_PROCESSOR) ;
280
//------------------------------------------------------------------------------
281
// This copyied and modified from LexBasic.cxx
282
//------------------------------------------------------------------------------
292
static int character_classification[128] =
294
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
295
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
296
1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 10, 6,
297
60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2,
298
2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
299
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4,
300
2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
301
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0
304
static bool IsSpace(int c) {
305
return c < 128 && (character_classification[c] & 1);
308
static bool IsIdentifier(int c) {
309
return c < 128 && (character_classification[c] & 4);
312
static int LowerCase(int c)
314
if (c >= 'A' && c <= 'Z')
315
return 'a' + c - 'A';
319
static int LineEnd(int line, Accessor &styler)
321
const int docLines = styler.GetLine(styler.Length() - 1); // Available last line
323
// if the line is the last line, the eol_pos is styler.Length()
324
// eol will contain a new line, or a virtual new line
325
if ( docLines == line )
326
eol_pos = styler.Length() ;
328
eol_pos = styler.LineStart(line + 1) - 1;
332
static int LineStart(int line, Accessor &styler)
334
return styler.LineStart(line) ;
339
// bits determines the line type
341
// 2 : only whitespace
342
// 3 : data line with only whitespace
344
// 5 : block open keyword line
345
// 6 : block close keyword line
346
// 7 : keyword line in error
348
static int LineType(int line, Accessor &styler) {
349
int pos = LineStart(line, styler) ;
350
int eol_pos = LineEnd(line, styler) ;
356
while ( i < eol_pos ) {
357
c = styler.SafeGetCharAt(i);
358
ch = static_cast<char>(LowerCase(c));
359
// We can say something as soon as no whitespace
366
if ( i >= eol_pos ) {
367
// This is a whitespace line, currently
368
// classifies as data line
373
// This is a data line
377
if ( i == eol_pos - 1 ) {
378
// Only a single *, error but make keyword line
382
// This means we can have a second character
383
// if that is also a * this means a comment
384
// otherwise it is a keyword.
385
c = styler.SafeGetCharAt(i+1);
386
ch = static_cast<char>(LowerCase(c));
391
// At this point we know this is a keyword line
392
// the character at position i is a *
393
// it is not a comment line
401
while ( (i < eol_pos) && (wlen < 255) ) {
402
c = styler.SafeGetCharAt(i);
403
ch = static_cast<char>(LowerCase(c));
405
if ( (!IsSpace(c)) && (!IsIdentifier(c)) )
408
if ( IsIdentifier(c) ) {
419
if ( !strcmp(word, "*step") ||
420
!strcmp(word, "*part") ||
421
!strcmp(word, "*instance") ||
422
!strcmp(word, "*assembly")) {
426
if ( !strcmp(word, "*endstep") ||
427
!strcmp(word, "*endpart") ||
428
!strcmp(word, "*endinstance") ||
429
!strcmp(word, "*endassembly")) {
436
static void SafeSetLevel(int line, int level, Accessor &styler)
441
int mask = ((~SC_FOLDLEVELHEADERFLAG) | (~SC_FOLDLEVELWHITEFLAG));
443
if ( (level & mask) < 0 )
446
if ( styler.LevelAt(line) != level )
447
styler.SetLevel(line, level) ;
450
static void FoldABAQUSDoc(unsigned int startPos, int length, int,
451
WordList *[], Accessor &styler) {
452
int startLine = styler.GetLine(startPos) ;
453
int endLine = styler.GetLine(startPos+length-1) ;
455
// bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
456
// We want to deal with all the cases
457
// To know the correct indentlevel, we need to look back to the
458
// previous command line indentation level
459
// order of formatting keyline datalines commentlines
461
int beginComment = -1 ;
462
int prvKeyLine = startLine ;
463
int prvKeyLineTp = 0 ;
465
// Scan until we find the previous keyword line
466
// this will give us the level reference that we need
467
while ( prvKeyLine > 0 ) {
469
prvKeyLineTp = LineType(prvKeyLine, styler) ;
470
if ( prvKeyLineTp & 4 )
474
// Determine the base line level of all lines following
475
// the previous keyword
476
// new keyword lines are placed on this level
477
//if ( prvKeyLineTp & 4 ) {
478
int level = styler.LevelAt(prvKeyLine) & ~SC_FOLDLEVELHEADERFLAG ;
481
// uncomment line below if weird behaviour continues
484
// Now start scanning over the lines.
485
for ( int line = startLine; line <= endLine; line++ ) {
486
int lineType = LineType(line, styler) ;
488
// Check for comment line
489
if ( lineType == 8 ) {
490
if ( beginComment < 0 ) {
491
beginComment = line ;
495
// Check for data line
496
if ( (lineType == 1) || (lineType == 3) ) {
497
if ( beginData < 0 ) {
498
if ( beginComment >= 0 ) {
499
beginData = beginComment ;
507
// Check for keywordline.
508
// As soon as a keyword line is encountered, we can set the
509
// levels of everything from the previous keyword line to this one
510
if ( lineType & 4 ) {
511
// this is a keyword, we can now place the previous keyword
512
// all its data lines and the remainder
514
// Write comments and data line
515
if ( beginComment < 0 ) {
516
beginComment = line ;
519
if ( beginData < 0 ) {
520
beginData = beginComment ;
521
if ( prvKeyLineTp != 5 )
522
SafeSetLevel(prvKeyLine, level, styler) ;
524
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
526
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
529
int datLevel = level + 1 ;
530
if ( !(prvKeyLineTp & 4) ) {
534
for ( int ll = beginData; ll < beginComment; ll++ )
535
SafeSetLevel(ll, datLevel, styler) ;
537
// The keyword we just found is going to be written at another level
538
// if we have a type 5 and type 6
539
if ( prvKeyLineTp == 5 ) {
543
if ( prvKeyLineTp == 6 ) {
550
for ( int lll = beginComment; lll < line; lll++ )
551
SafeSetLevel(lll, level, styler) ;
557
prvKeyLineTp = lineType ;
562
if ( beginComment < 0 ) {
563
beginComment = endLine + 1 ;
565
// We need to find out whether this comment block is followed by
566
// a data line or a keyword line
567
const int docLines = styler.GetLine(styler.Length() - 1);
569
for ( int line = endLine + 1; line <= docLines; line++ ) {
570
int lineType = LineType(line, styler) ;
572
if ( lineType != 8 ) {
573
if ( !(lineType & 4) ) {
574
beginComment = endLine + 1 ;
581
if ( beginData < 0 ) {
582
beginData = beginComment ;
583
if ( prvKeyLineTp != 5 )
584
SafeSetLevel(prvKeyLine, level, styler) ;
586
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
588
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
591
int datLevel = level + 1 ;
592
if ( !(prvKeyLineTp & 4) ) {
596
for ( int ll = beginData; ll < beginComment; ll++ )
597
SafeSetLevel(ll, datLevel, styler) ;
599
if ( prvKeyLineTp == 5 ) {
603
if ( prvKeyLineTp == 6 ) {
606
for ( int m = beginComment; m <= endLine; m++ )
607
SafeSetLevel(m, level, styler) ;
610
static const char * const abaqusWordListDesc[] = {
620
LexerModule lmAbaqus(SCLEX_ABAQUS, ColouriseABAQUSDoc, "abaqus", FoldABAQUSDoc, abaqusWordListDesc);