]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexAbaqus.cxx
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
);