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 IsAKeywordChar(const int ch
) {
34 return (ch
< 0x80 && (isalnum(ch
) || (ch
== '_') || (ch
== ' ')));
37 static inline bool IsASetChar(const int ch
) {
38 return (ch
< 0x80 && (isalnum(ch
) || (ch
== '_') || (ch
== '.') || (ch
== '-')));
41 static void ColouriseABAQUSDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*[] /* *keywordlists[] */,
43 enum localState
{ KW_LINE_KW
, KW_LINE_COMMA
, KW_LINE_PAR
, KW_LINE_EQ
, KW_LINE_VAL
, \
44 DAT_LINE_VAL
, DAT_LINE_COMMA
,\
46 ST_ERROR
, LINE_END
} state
;
48 // Do not leak onto next line
50 initStyle
= SCE_ABAQUS_DEFAULT
;
51 StyleContext
sc(startPos
, length
, initStyle
, styler
);
53 // Things are actually quite simple
54 // we have commentlines
55 // keywordlines and datalines
56 // On a data line there will only be colouring of numbers
57 // a keyword line is constructed as
58 // *word,[ paramname[=paramvalue]]*
59 // if the line ends with a , the keyword line continues onto the new line
61 for (; sc
.More(); sc
.Forward()) {
65 // finished the line in keyword state, switch to LINE_END
66 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
68 } else if ( IsAKeywordChar(sc
.ch
) ) {
71 } else if ( sc
.ch
== ',' ) {
72 // Well well we say a comma, arguments *MUST* follow
73 sc
.SetState(SCE_ABAQUS_OPERATOR
) ;
74 state
= KW_LINE_COMMA
;
77 sc
.SetState(SCE_ABAQUS_PROCESSOR
) ;
80 // Done with processing
83 // acomma on a keywordline was seen
84 if ( IsAKeywordChar(sc
.ch
)) {
85 sc
.SetState(SCE_ABAQUS_ARGUMENT
) ;
87 } else if ( sc
.atLineEnd
|| (sc
.ch
== ',') ) {
88 // we remain in keyword mode
89 state
= KW_LINE_COMMA
;
90 } else if ( sc
.ch
== ' ' ) {
91 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
92 state
= KW_LINE_COMMA
;
94 // Anything else constitutes an error
95 sc
.SetState(SCE_ABAQUS_PROCESSOR
) ;
100 if ( sc
.atLineEnd
) {
101 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
103 } else if ( IsAKeywordChar(sc
.ch
) || (sc
.ch
== '-') ) {
104 // remain in this state
105 state
= KW_LINE_PAR
;
106 } else if ( sc
.ch
== ',' ) {
107 sc
.SetState(SCE_ABAQUS_OPERATOR
) ;
108 state
= KW_LINE_COMMA
;
109 } else if ( sc
.ch
== '=' ) {
110 sc
.SetState(SCE_ABAQUS_OPERATOR
) ;
113 // Anything else constitutes an error
114 sc
.SetState(SCE_ABAQUS_PROCESSOR
) ;
119 if ( sc
.ch
== ' ' ) {
120 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
121 // remain in this state
123 } else if ( IsADigit(sc
.ch
) || (sc
.ch
== '-') || (sc
.ch
== '.' && IsADigit(sc
.chNext
)) ) {
124 sc
.SetState(SCE_ABAQUS_NUMBER
) ;
125 state
= KW_LINE_VAL
;
126 } else if ( IsAKeywordChar(sc
.ch
) ) {
127 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
128 state
= KW_LINE_VAL
;
129 } else if ( (sc
.ch
== '\'') || (sc
.ch
== '\"') ) {
130 sc
.SetState(SCE_ABAQUS_STRING
) ;
131 state
= KW_LINE_VAL
;
133 sc
.SetState(SCE_ABAQUS_PROCESSOR
) ;
138 if ( sc
.atLineEnd
) {
139 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
141 } else if ( IsASetChar(sc
.ch
) && (sc
.state
== SCE_ABAQUS_DEFAULT
) ) {
143 state
= KW_LINE_VAL
;
144 } else if (( (IsADigit(sc
.ch
) || sc
.ch
== '.' || (sc
.ch
== 'e' || sc
.ch
== 'E') ||
145 ((sc
.ch
== '+' || sc
.ch
== '-') && (sc
.chPrev
== 'e' || sc
.chPrev
== 'E')))) &&
146 (sc
.state
== SCE_ABAQUS_NUMBER
)) {
147 // remain in number mode
148 state
= KW_LINE_VAL
;
149 } else if (sc
.state
== SCE_ABAQUS_STRING
) {
150 // accept everything until a closing quote
151 if ( sc
.ch
== '\'' || sc
.ch
== '\"' ) {
152 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
153 state
= KW_LINE_VAL
;
155 } else if ( sc
.ch
== ',' ) {
156 sc
.SetState(SCE_ABAQUS_OPERATOR
) ;
157 state
= KW_LINE_COMMA
;
159 // anything else is an error
160 sc
.SetState(SCE_ABAQUS_PROCESSOR
) ;
165 if ( sc
.atLineEnd
) {
166 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
168 } else if ( IsASetChar(sc
.ch
) && (sc
.state
== SCE_ABAQUS_DEFAULT
) ) {
170 state
= DAT_LINE_VAL
;
171 } else if (( (IsADigit(sc
.ch
) || sc
.ch
== '.' || (sc
.ch
== 'e' || sc
.ch
== 'E') ||
172 ((sc
.ch
== '+' || sc
.ch
== '-') && (sc
.chPrev
== 'e' || sc
.chPrev
== 'E')))) &&
173 (sc
.state
== SCE_ABAQUS_NUMBER
)) {
174 // remain in number mode
175 state
= DAT_LINE_VAL
;
176 } else if (sc
.state
== SCE_ABAQUS_STRING
) {
177 // accept everything until a closing quote
178 if ( sc
.ch
== '\'' || sc
.ch
== '\"' ) {
179 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
180 state
= DAT_LINE_VAL
;
182 } else if ( sc
.ch
== ',' ) {
183 sc
.SetState(SCE_ABAQUS_OPERATOR
) ;
184 state
= DAT_LINE_COMMA
;
186 // anything else is an error
187 sc
.SetState(SCE_ABAQUS_PROCESSOR
) ;
191 case DAT_LINE_COMMA
:
192 // a comma on a data line was seen
193 if ( sc
.atLineEnd
) {
194 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
196 } else if ( sc
.ch
== ' ' ) {
197 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
198 state
= DAT_LINE_COMMA
;
199 } else if (sc
.ch
== ',') {
200 sc
.SetState(SCE_ABAQUS_OPERATOR
) ;
201 state
= DAT_LINE_COMMA
;
202 } else if ( IsADigit(sc
.ch
) || (sc
.ch
== '-')|| (sc
.ch
== '.' && IsADigit(sc
.chNext
)) ) {
203 sc
.SetState(SCE_ABAQUS_NUMBER
) ;
204 state
= DAT_LINE_VAL
;
205 } else if ( IsAKeywordChar(sc
.ch
) ) {
206 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
207 state
= DAT_LINE_VAL
;
208 } else if ( (sc
.ch
== '\'') || (sc
.ch
== '\"') ) {
209 sc
.SetState(SCE_ABAQUS_STRING
) ;
210 state
= DAT_LINE_VAL
;
212 sc
.SetState(SCE_ABAQUS_PROCESSOR
) ;
217 if ( sc
.atLineEnd
) {
218 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
223 if ( sc
.atLineEnd
) {
224 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
229 if ( sc
.atLineEnd
|| sc
.ch
== ' ' ) {
232 } else if ( sc
.ch
== '*' ) {
233 if ( sc
.chNext
== '*' ) {
234 state
= COMMENT_LINE
;
235 sc
.SetState(SCE_ABAQUS_COMMENT
) ;
238 sc
.SetState(SCE_ABAQUS_STARCOMMAND
) ;
241 // it must be a data line, things are as if we are in DAT_LINE_COMMA
242 if ( sc
.ch
== ',' ) {
243 sc
.SetState(SCE_ABAQUS_OPERATOR
) ;
244 state
= DAT_LINE_COMMA
;
245 } else if ( IsADigit(sc
.ch
) || (sc
.ch
== '-')|| (sc
.ch
== '.' && IsADigit(sc
.chNext
)) ) {
246 sc
.SetState(SCE_ABAQUS_NUMBER
) ;
247 state
= DAT_LINE_VAL
;
248 } else if ( IsAKeywordChar(sc
.ch
) ) {
249 sc
.SetState(SCE_ABAQUS_DEFAULT
) ;
250 state
= DAT_LINE_VAL
;
251 } else if ( (sc
.ch
== '\'') || (sc
.ch
== '\"') ) {
252 sc
.SetState(SCE_ABAQUS_STRING
) ;
253 state
= DAT_LINE_VAL
;
255 sc
.SetState(SCE_ABAQUS_PROCESSOR
) ;
265 //------------------------------------------------------------------------------
266 // This copyied and modified from LexBasic.cxx
267 //------------------------------------------------------------------------------
277 static int character_classification
[128] =
279 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
280 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
281 1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 10, 6,
282 60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2,
283 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
284 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4,
285 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
286 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0
289 static bool IsSpace(int c
) {
290 return c
< 128 && (character_classification
[c
] & 1);
293 static bool IsIdentifier(int c
) {
294 return c
< 128 && (character_classification
[c
] & 4);
297 static int LowerCase(int c
)
299 if (c
>= 'A' && c
<= 'Z')
300 return 'a' + c
- 'A';
304 static int LineEnd(int line
, Accessor
&styler
)
306 const int docLines
= styler
.GetLine(styler
.Length() - 1); // Available last line
308 // if the line is the last line, the eol_pos is styler.Length()
309 // eol will contain a new line, or a virtual new line
310 if ( docLines
== line
)
311 eol_pos
= styler
.Length() ;
313 eol_pos
= styler
.LineStart(line
+ 1) - 1;
317 static int LineStart(int line
, Accessor
&styler
)
319 return styler
.LineStart(line
) ;
324 // bits determines the line type
326 // 2 : only whitespace
327 // 3 : data line with only whitespace
329 // 5 : block open keyword line
330 // 6 : block close keyword line
331 // 7 : keyword line in error
333 static int LineType(int line
, Accessor
&styler
) {
334 int pos
= LineStart(line
, styler
) ;
335 int eol_pos
= LineEnd(line
, styler
) ;
341 while ( i
< eol_pos
) {
342 c
= styler
.SafeGetCharAt(i
);
343 ch
= static_cast<char>(LowerCase(c
));
344 // We can say something as soon as no whitespace
351 if ( i
>= eol_pos
) {
352 // This is a whitespace line, currently
353 // classifies as data line
358 // This is a data line
362 if ( i
== eol_pos
- 1 ) {
363 // Only a single *, error but make keyword line
367 // This means we can have a second character
368 // if that is also a * this means a comment
369 // otherwise it is a keyword.
370 c
= styler
.SafeGetCharAt(i
+1);
371 ch
= static_cast<char>(LowerCase(c
));
376 // At this point we know this is a keyword line
377 // the character at position i is a *
378 // it is not a comment line
386 while ( (i
< eol_pos
) && (wlen
< 255) ) {
387 c
= styler
.SafeGetCharAt(i
);
388 ch
= static_cast<char>(LowerCase(c
));
390 if ( (!IsSpace(c
)) && (!IsIdentifier(c
)) )
393 if ( IsIdentifier(c
) ) {
404 if ( !strcmp(word
, "*step") ||
405 !strcmp(word
, "*part") ||
406 !strcmp(word
, "*instance") ||
407 !strcmp(word
, "*assembly")) {
411 if ( !strcmp(word
, "*endstep") ||
412 !strcmp(word
, "*endpart") ||
413 !strcmp(word
, "*endinstance") ||
414 !strcmp(word
, "*endassembly")) {
421 static void SafeSetLevel(int line
, int level
, Accessor
&styler
)
426 int mask
= ((~SC_FOLDLEVELHEADERFLAG
) | (~SC_FOLDLEVELWHITEFLAG
));
428 if ( (level
& mask
) < 0 )
431 if ( styler
.LevelAt(line
) != level
)
432 styler
.SetLevel(line
, level
) ;
435 static void FoldABAQUSDoc(unsigned int startPos
, int length
, int,
436 WordList
*[], Accessor
&styler
) {
437 int startLine
= styler
.GetLine(startPos
) ;
438 int endLine
= styler
.GetLine(startPos
+length
-1) ;
440 // bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
441 // We want to deal with all the cases
442 // To know the correct indentlevel, we need to look back to the
443 // previous command line indentation level
444 // order of formatting keyline datalines commentlines
446 int beginComment
= -1 ;
447 int prvKeyLine
= startLine
;
448 int prvKeyLineTp
= 0 ;
450 // Scan until we find the previous keyword line
451 // this will give us the level reference that we need
452 while ( prvKeyLine
> 0 ) {
454 prvKeyLineTp
= LineType(prvKeyLine
, styler
) ;
455 if ( prvKeyLineTp
& 4 )
459 // Determine the base line level of all lines following
460 // the previous keyword
461 // new keyword lines are placed on this level
462 //if ( prvKeyLineTp & 4 ) {
463 int level
= styler
.LevelAt(prvKeyLine
) & ~SC_FOLDLEVELHEADERFLAG
;
466 // uncomment line below if weird behaviour continues
469 // Now start scanning over the lines.
470 for ( int line
= startLine
; line
<= endLine
; line
++ ) {
471 int lineType
= LineType(line
, styler
) ;
473 // Check for comment line
474 if ( lineType
== 8 ) {
475 if ( beginComment
< 0 ) {
476 beginComment
= line
;
480 // Check for data line
481 if ( (lineType
== 1) || (lineType
== 3) ) {
482 if ( beginData
< 0 ) {
483 if ( beginComment
>= 0 ) {
484 beginData
= beginComment
;
492 // Check for keywordline.
493 // As soon as a keyword line is encountered, we can set the
494 // levels of everything from the previous keyword line to this one
495 if ( lineType
& 4 ) {
496 // this is a keyword, we can now place the previous keyword
497 // all its data lines and the remainder
499 // Write comments and data line
500 if ( beginComment
< 0 ) {
501 beginComment
= line
;
504 if ( beginData
< 0 ) {
505 beginData
= beginComment
;
506 if ( prvKeyLineTp
!= 5 )
507 SafeSetLevel(prvKeyLine
, level
, styler
) ;
509 SafeSetLevel(prvKeyLine
, level
| SC_FOLDLEVELHEADERFLAG
, styler
) ;
511 SafeSetLevel(prvKeyLine
, level
| SC_FOLDLEVELHEADERFLAG
, styler
) ;
514 int datLevel
= level
+ 1 ;
515 if ( !(prvKeyLineTp
& 4) ) {
519 for ( int ll
= beginData
; ll
< beginComment
; ll
++ )
520 SafeSetLevel(ll
, datLevel
, styler
) ;
522 // The keyword we just found is going to be written at another level
523 // if we have a type 5 and type 6
524 if ( prvKeyLineTp
== 5 ) {
528 if ( prvKeyLineTp
== 6 ) {
535 for ( int lll
= beginComment
; lll
< line
; lll
++ )
536 SafeSetLevel(lll
, level
, styler
) ;
542 prvKeyLineTp
= lineType
;
547 if ( beginComment
< 0 ) {
548 beginComment
= endLine
+ 1 ;
550 // We need to find out whether this comment block is followed by
551 // a data line or a keyword line
552 const int docLines
= styler
.GetLine(styler
.Length() - 1);
554 for ( int line
= endLine
+ 1; line
<= docLines
; line
++ ) {
555 int lineType
= LineType(line
, styler
) ;
557 if ( lineType
!= 8 ) {
558 if ( !(lineType
& 4) ) {
559 beginComment
= endLine
+ 1 ;
566 if ( beginData
< 0 ) {
567 beginData
= beginComment
;
568 if ( prvKeyLineTp
!= 5 )
569 SafeSetLevel(prvKeyLine
, level
, styler
) ;
571 SafeSetLevel(prvKeyLine
, level
| SC_FOLDLEVELHEADERFLAG
, styler
) ;
573 SafeSetLevel(prvKeyLine
, level
| SC_FOLDLEVELHEADERFLAG
, styler
) ;
576 int datLevel
= level
+ 1 ;
577 if ( !(prvKeyLineTp
& 4) ) {
581 for ( int ll
= beginData
; ll
< beginComment
; ll
++ )
582 SafeSetLevel(ll
, datLevel
, styler
) ;
584 if ( prvKeyLineTp
== 5 ) {
588 if ( prvKeyLineTp
== 6 ) {
591 for ( int m
= beginComment
; m
<= endLine
; m
++ )
592 SafeSetLevel(m
, level
, styler
) ;
595 static const char * const abaqusWordListDesc
[] = {
605 LexerModule
lmAbaqus(SCLEX_ABAQUS
, ColouriseABAQUSDoc
, "abaqus", FoldABAQUSDoc
, abaqusWordListDesc
);