You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
606 lines
19 KiB
606 lines
19 KiB
// Scintilla source code edit control |
|
/** @file LexAbaqus.cxx |
|
** Lexer for ABAQUS. Based on the lexer for APDL by Hadar Raz. |
|
** By Sergio Lucato. |
|
** Sort of completely rewritten by Gertjan Kloosterman |
|
**/ |
|
// The License.txt file describes the conditions under which this software may be distributed. |
|
|
|
// Code folding copyied and modified from LexBasic.cxx |
|
|
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <stdio.h> |
|
#include <stdarg.h> |
|
#include <assert.h> |
|
#include <ctype.h> |
|
|
|
#include <string> |
|
#include <string_view> |
|
|
|
#include "ILexer.h" |
|
#include "Scintilla.h" |
|
#include "SciLexer.h" |
|
|
|
#include "WordList.h" |
|
#include "LexAccessor.h" |
|
#include "Accessor.h" |
|
#include "StyleContext.h" |
|
#include "CharacterSet.h" |
|
#include "LexerModule.h" |
|
|
|
using namespace Lexilla; |
|
|
|
static inline bool IsAKeywordChar(const int ch) { |
|
return (ch < 0x80 && (isalnum(ch) || (ch == '_') || (ch == ' '))); |
|
} |
|
|
|
static inline bool IsASetChar(const int ch) { |
|
return (ch < 0x80 && (isalnum(ch) || (ch == '_') || (ch == '.') || (ch == '-'))); |
|
} |
|
|
|
static void ColouriseABAQUSDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList*[] /* *keywordlists[] */, |
|
Accessor &styler) { |
|
enum localState { KW_LINE_KW, KW_LINE_COMMA, KW_LINE_PAR, KW_LINE_EQ, KW_LINE_VAL, \ |
|
DAT_LINE_VAL, DAT_LINE_COMMA,\ |
|
COMMENT_LINE,\ |
|
ST_ERROR, LINE_END } state ; |
|
|
|
// Do not leak onto next line |
|
state = LINE_END ; |
|
initStyle = SCE_ABAQUS_DEFAULT; |
|
StyleContext sc(startPos, length, initStyle, styler); |
|
|
|
// Things are actually quite simple |
|
// we have commentlines |
|
// keywordlines and datalines |
|
// On a data line there will only be colouring of numbers |
|
// a keyword line is constructed as |
|
// *word,[ paramname[=paramvalue]]* |
|
// if the line ends with a , the keyword line continues onto the new line |
|
|
|
for (; sc.More(); sc.Forward()) { |
|
switch ( state ) { |
|
case KW_LINE_KW : |
|
if ( sc.atLineEnd ) { |
|
// finished the line in keyword state, switch to LINE_END |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = LINE_END ; |
|
} else if ( IsAKeywordChar(sc.ch) ) { |
|
// nothing changes |
|
state = KW_LINE_KW ; |
|
} else if ( sc.ch == ',' ) { |
|
// Well well we say a comma, arguments *MUST* follow |
|
sc.SetState(SCE_ABAQUS_OPERATOR) ; |
|
state = KW_LINE_COMMA ; |
|
} else { |
|
// Flag an error |
|
sc.SetState(SCE_ABAQUS_PROCESSOR) ; |
|
state = ST_ERROR ; |
|
} |
|
// Done with processing |
|
break ; |
|
case KW_LINE_COMMA : |
|
// acomma on a keywordline was seen |
|
if ( IsAKeywordChar(sc.ch)) { |
|
sc.SetState(SCE_ABAQUS_ARGUMENT) ; |
|
state = KW_LINE_PAR ; |
|
} else if ( sc.atLineEnd || (sc.ch == ',') ) { |
|
// we remain in keyword mode |
|
state = KW_LINE_COMMA ; |
|
} else if ( sc.ch == ' ' ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = KW_LINE_COMMA ; |
|
} else { |
|
// Anything else constitutes an error |
|
sc.SetState(SCE_ABAQUS_PROCESSOR) ; |
|
state = ST_ERROR ; |
|
} |
|
break ; |
|
case KW_LINE_PAR : |
|
if ( sc.atLineEnd ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = LINE_END ; |
|
} else if ( IsAKeywordChar(sc.ch) || (sc.ch == '-') ) { |
|
// remain in this state |
|
state = KW_LINE_PAR ; |
|
} else if ( sc.ch == ',' ) { |
|
sc.SetState(SCE_ABAQUS_OPERATOR) ; |
|
state = KW_LINE_COMMA ; |
|
} else if ( sc.ch == '=' ) { |
|
sc.SetState(SCE_ABAQUS_OPERATOR) ; |
|
state = KW_LINE_EQ ; |
|
} else { |
|
// Anything else constitutes an error |
|
sc.SetState(SCE_ABAQUS_PROCESSOR) ; |
|
state = ST_ERROR ; |
|
} |
|
break ; |
|
case KW_LINE_EQ : |
|
if ( sc.ch == ' ' ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
// remain in this state |
|
state = KW_LINE_EQ ; |
|
} else if ( IsADigit(sc.ch) || (sc.ch == '-') || (sc.ch == '.' && IsADigit(sc.chNext)) ) { |
|
sc.SetState(SCE_ABAQUS_NUMBER) ; |
|
state = KW_LINE_VAL ; |
|
} else if ( IsAKeywordChar(sc.ch) ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = KW_LINE_VAL ; |
|
} else if ( (sc.ch == '\'') || (sc.ch == '\"') ) { |
|
sc.SetState(SCE_ABAQUS_STRING) ; |
|
state = KW_LINE_VAL ; |
|
} else { |
|
sc.SetState(SCE_ABAQUS_PROCESSOR) ; |
|
state = ST_ERROR ; |
|
} |
|
break ; |
|
case KW_LINE_VAL : |
|
if ( sc.atLineEnd ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = LINE_END ; |
|
} else if ( IsASetChar(sc.ch) && (sc.state == SCE_ABAQUS_DEFAULT) ) { |
|
// nothing changes |
|
state = KW_LINE_VAL ; |
|
} else if (( (IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') || |
|
((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) && |
|
(sc.state == SCE_ABAQUS_NUMBER)) { |
|
// remain in number mode |
|
state = KW_LINE_VAL ; |
|
} else if (sc.state == SCE_ABAQUS_STRING) { |
|
// accept everything until a closing quote |
|
if ( sc.ch == '\'' || sc.ch == '\"' ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = KW_LINE_VAL ; |
|
} |
|
} else if ( sc.ch == ',' ) { |
|
sc.SetState(SCE_ABAQUS_OPERATOR) ; |
|
state = KW_LINE_COMMA ; |
|
} else { |
|
// anything else is an error |
|
sc.SetState(SCE_ABAQUS_PROCESSOR) ; |
|
state = ST_ERROR ; |
|
} |
|
break ; |
|
case DAT_LINE_VAL : |
|
if ( sc.atLineEnd ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = LINE_END ; |
|
} else if ( IsASetChar(sc.ch) && (sc.state == SCE_ABAQUS_DEFAULT) ) { |
|
// nothing changes |
|
state = DAT_LINE_VAL ; |
|
} else if (( (IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') || |
|
((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) && |
|
(sc.state == SCE_ABAQUS_NUMBER)) { |
|
// remain in number mode |
|
state = DAT_LINE_VAL ; |
|
} else if (sc.state == SCE_ABAQUS_STRING) { |
|
// accept everything until a closing quote |
|
if ( sc.ch == '\'' || sc.ch == '\"' ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = DAT_LINE_VAL ; |
|
} |
|
} else if ( sc.ch == ',' ) { |
|
sc.SetState(SCE_ABAQUS_OPERATOR) ; |
|
state = DAT_LINE_COMMA ; |
|
} else { |
|
// anything else is an error |
|
sc.SetState(SCE_ABAQUS_PROCESSOR) ; |
|
state = ST_ERROR ; |
|
} |
|
break ; |
|
case DAT_LINE_COMMA : |
|
// a comma on a data line was seen |
|
if ( sc.atLineEnd ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = LINE_END ; |
|
} else if ( sc.ch == ' ' ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = DAT_LINE_COMMA ; |
|
} else if (sc.ch == ',') { |
|
sc.SetState(SCE_ABAQUS_OPERATOR) ; |
|
state = DAT_LINE_COMMA ; |
|
} else if ( IsADigit(sc.ch) || (sc.ch == '-')|| (sc.ch == '.' && IsADigit(sc.chNext)) ) { |
|
sc.SetState(SCE_ABAQUS_NUMBER) ; |
|
state = DAT_LINE_VAL ; |
|
} else if ( IsAKeywordChar(sc.ch) ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = DAT_LINE_VAL ; |
|
} else if ( (sc.ch == '\'') || (sc.ch == '\"') ) { |
|
sc.SetState(SCE_ABAQUS_STRING) ; |
|
state = DAT_LINE_VAL ; |
|
} else { |
|
sc.SetState(SCE_ABAQUS_PROCESSOR) ; |
|
state = ST_ERROR ; |
|
} |
|
break ; |
|
case COMMENT_LINE : |
|
if ( sc.atLineEnd ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = LINE_END ; |
|
} |
|
break ; |
|
case ST_ERROR : |
|
if ( sc.atLineEnd ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = LINE_END ; |
|
} |
|
break ; |
|
case LINE_END : |
|
if ( sc.atLineEnd || sc.ch == ' ' ) { |
|
// nothing changes |
|
state = LINE_END ; |
|
} else if ( sc.ch == '*' ) { |
|
if ( sc.chNext == '*' ) { |
|
state = COMMENT_LINE ; |
|
sc.SetState(SCE_ABAQUS_COMMENT) ; |
|
} else { |
|
state = KW_LINE_KW ; |
|
sc.SetState(SCE_ABAQUS_STARCOMMAND) ; |
|
} |
|
} else { |
|
// it must be a data line, things are as if we are in DAT_LINE_COMMA |
|
if ( sc.ch == ',' ) { |
|
sc.SetState(SCE_ABAQUS_OPERATOR) ; |
|
state = DAT_LINE_COMMA ; |
|
} else if ( IsADigit(sc.ch) || (sc.ch == '-')|| (sc.ch == '.' && IsADigit(sc.chNext)) ) { |
|
sc.SetState(SCE_ABAQUS_NUMBER) ; |
|
state = DAT_LINE_VAL ; |
|
} else if ( IsAKeywordChar(sc.ch) ) { |
|
sc.SetState(SCE_ABAQUS_DEFAULT) ; |
|
state = DAT_LINE_VAL ; |
|
} else if ( (sc.ch == '\'') || (sc.ch == '\"') ) { |
|
sc.SetState(SCE_ABAQUS_STRING) ; |
|
state = DAT_LINE_VAL ; |
|
} else { |
|
sc.SetState(SCE_ABAQUS_PROCESSOR) ; |
|
state = ST_ERROR ; |
|
} |
|
} |
|
break ; |
|
} |
|
} |
|
sc.Complete(); |
|
} |
|
|
|
//------------------------------------------------------------------------------ |
|
// This copyied and modified from LexBasic.cxx |
|
//------------------------------------------------------------------------------ |
|
|
|
/* Bits: |
|
* 1 - whitespace |
|
* 2 - operator |
|
* 4 - identifier |
|
* 8 - decimal digit |
|
* 16 - hex digit |
|
* 32 - bin digit |
|
*/ |
|
static int character_classification[128] = |
|
{ |
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 10, 6, |
|
60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2, |
|
2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4, |
|
2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0 |
|
}; |
|
|
|
static bool IsSpace(int c) { |
|
return c < 128 && (character_classification[c] & 1); |
|
} |
|
|
|
static bool IsIdentifier(int c) { |
|
return c < 128 && (character_classification[c] & 4); |
|
} |
|
|
|
static int LowerCase(int c) |
|
{ |
|
if (c >= 'A' && c <= 'Z') |
|
return 'a' + c - 'A'; |
|
return c; |
|
} |
|
|
|
static Sci_Position LineEnd(Sci_Position line, Accessor &styler) |
|
{ |
|
const Sci_Position docLines = styler.GetLine(styler.Length() - 1); // Available last line |
|
Sci_Position eol_pos ; |
|
// if the line is the last line, the eol_pos is styler.Length() |
|
// eol will contain a new line, or a virtual new line |
|
if ( docLines == line ) |
|
eol_pos = styler.Length() ; |
|
else |
|
eol_pos = styler.LineStart(line + 1) - 1; |
|
return eol_pos ; |
|
} |
|
|
|
static Sci_Position LineStart(Sci_Position line, Accessor &styler) |
|
{ |
|
return styler.LineStart(line) ; |
|
} |
|
|
|
// LineType |
|
// |
|
// bits determines the line type |
|
// 1 : data line |
|
// 2 : only whitespace |
|
// 3 : data line with only whitespace |
|
// 4 : keyword line |
|
// 5 : block open keyword line |
|
// 6 : block close keyword line |
|
// 7 : keyword line in error |
|
// 8 : comment line |
|
static int LineType(Sci_Position line, Accessor &styler) { |
|
Sci_Position pos = LineStart(line, styler) ; |
|
Sci_Position eol_pos = LineEnd(line, styler) ; |
|
|
|
int c ; |
|
char ch = ' '; |
|
|
|
Sci_Position i = pos ; |
|
while ( i < eol_pos ) { |
|
c = styler.SafeGetCharAt(i); |
|
ch = static_cast<char>(LowerCase(c)); |
|
// We can say something as soon as no whitespace |
|
// was encountered |
|
if ( !IsSpace(c) ) |
|
break ; |
|
i++ ; |
|
} |
|
|
|
if ( i >= eol_pos ) { |
|
// This is a whitespace line, currently |
|
// classifies as data line |
|
return 3 ; |
|
} |
|
|
|
if ( ch != '*' ) { |
|
// This is a data line |
|
return 1 ; |
|
} |
|
|
|
if ( i == eol_pos - 1 ) { |
|
// Only a single *, error but make keyword line |
|
return 4+3 ; |
|
} |
|
|
|
// This means we can have a second character |
|
// if that is also a * this means a comment |
|
// otherwise it is a keyword. |
|
c = styler.SafeGetCharAt(i+1); |
|
ch = static_cast<char>(LowerCase(c)); |
|
if ( ch == '*' ) { |
|
return 8 ; |
|
} |
|
|
|
// At this point we know this is a keyword line |
|
// the character at position i is a * |
|
// it is not a comment line |
|
char word[256] ; |
|
int wlen = 0; |
|
|
|
word[wlen] = '*' ; |
|
wlen++ ; |
|
|
|
i++ ; |
|
while ( (i < eol_pos) && (wlen < 255) ) { |
|
c = styler.SafeGetCharAt(i); |
|
ch = static_cast<char>(LowerCase(c)); |
|
|
|
if ( (!IsSpace(c)) && (!IsIdentifier(c)) ) |
|
break ; |
|
|
|
if ( IsIdentifier(c) ) { |
|
word[wlen] = ch ; |
|
wlen++ ; |
|
} |
|
|
|
i++ ; |
|
} |
|
|
|
word[wlen] = 0 ; |
|
|
|
// Make a comparison |
|
if ( !strcmp(word, "*step") || |
|
!strcmp(word, "*part") || |
|
!strcmp(word, "*instance") || |
|
!strcmp(word, "*assembly")) { |
|
return 4+1 ; |
|
} |
|
|
|
if ( !strcmp(word, "*endstep") || |
|
!strcmp(word, "*endpart") || |
|
!strcmp(word, "*endinstance") || |
|
!strcmp(word, "*endassembly")) { |
|
return 4+2 ; |
|
} |
|
|
|
return 4 ; |
|
} |
|
|
|
static void SafeSetLevel(Sci_Position line, int level, Accessor &styler) |
|
{ |
|
if ( line < 0 ) |
|
return ; |
|
|
|
int mask = ((~SC_FOLDLEVELHEADERFLAG) | (~SC_FOLDLEVELWHITEFLAG)); |
|
|
|
if ( (level & mask) < 0 ) |
|
return ; |
|
|
|
if ( styler.LevelAt(line) != level ) |
|
styler.SetLevel(line, level) ; |
|
} |
|
|
|
static void FoldABAQUSDoc(Sci_PositionU startPos, Sci_Position length, int, |
|
WordList *[], Accessor &styler) { |
|
Sci_Position startLine = styler.GetLine(startPos) ; |
|
Sci_Position endLine = styler.GetLine(startPos+length-1) ; |
|
|
|
// bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; |
|
// We want to deal with all the cases |
|
// To know the correct indentlevel, we need to look back to the |
|
// previous command line indentation level |
|
// order of formatting keyline datalines commentlines |
|
Sci_Position beginData = -1 ; |
|
Sci_Position beginComment = -1 ; |
|
Sci_Position prvKeyLine = startLine ; |
|
Sci_Position prvKeyLineTp = 0 ; |
|
|
|
// Scan until we find the previous keyword line |
|
// this will give us the level reference that we need |
|
while ( prvKeyLine > 0 ) { |
|
prvKeyLine-- ; |
|
prvKeyLineTp = LineType(prvKeyLine, styler) ; |
|
if ( prvKeyLineTp & 4 ) |
|
break ; |
|
} |
|
|
|
// Determine the base line level of all lines following |
|
// the previous keyword |
|
// new keyword lines are placed on this level |
|
//if ( prvKeyLineTp & 4 ) { |
|
int level = styler.LevelAt(prvKeyLine) & ~SC_FOLDLEVELHEADERFLAG ; |
|
//} |
|
|
|
// uncomment line below if weird behaviour continues |
|
prvKeyLine = -1 ; |
|
|
|
// Now start scanning over the lines. |
|
for ( Sci_Position line = startLine; line <= endLine; line++ ) { |
|
int lineType = LineType(line, styler) ; |
|
|
|
// Check for comment line |
|
if ( lineType == 8 ) { |
|
if ( beginComment < 0 ) { |
|
beginComment = line ; |
|
} |
|
} |
|
|
|
// Check for data line |
|
if ( (lineType == 1) || (lineType == 3) ) { |
|
if ( beginData < 0 ) { |
|
if ( beginComment >= 0 ) { |
|
beginData = beginComment ; |
|
} else { |
|
beginData = line ; |
|
} |
|
} |
|
beginComment = -1 ; |
|
} |
|
|
|
// Check for keywordline. |
|
// As soon as a keyword line is encountered, we can set the |
|
// levels of everything from the previous keyword line to this one |
|
if ( lineType & 4 ) { |
|
// this is a keyword, we can now place the previous keyword |
|
// all its data lines and the remainder |
|
|
|
// Write comments and data line |
|
if ( beginComment < 0 ) { |
|
beginComment = line ; |
|
} |
|
|
|
if ( beginData < 0 ) { |
|
beginData = beginComment ; |
|
if ( prvKeyLineTp != 5 ) |
|
SafeSetLevel(prvKeyLine, level, styler) ; |
|
else |
|
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ; |
|
} else { |
|
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ; |
|
} |
|
|
|
int datLevel = level + 1 ; |
|
if ( !(prvKeyLineTp & 4) ) { |
|
datLevel = level ; |
|
} |
|
|
|
for ( Sci_Position ll = beginData; ll < beginComment; ll++ ) |
|
SafeSetLevel(ll, datLevel, styler) ; |
|
|
|
// The keyword we just found is going to be written at another level |
|
// if we have a type 5 and type 6 |
|
if ( prvKeyLineTp == 5 ) { |
|
level += 1 ; |
|
} |
|
|
|
if ( prvKeyLineTp == 6 ) { |
|
level -= 1 ; |
|
if ( level < 0 ) { |
|
level = 0 ; |
|
} |
|
} |
|
|
|
for ( Sci_Position lll = beginComment; lll < line; lll++ ) |
|
SafeSetLevel(lll, level, styler) ; |
|
|
|
// wrap and reset |
|
beginComment = -1 ; |
|
beginData = -1 ; |
|
prvKeyLine = line ; |
|
prvKeyLineTp = lineType ; |
|
} |
|
|
|
} |
|
|
|
if ( beginComment < 0 ) { |
|
beginComment = endLine + 1 ; |
|
} else { |
|
// We need to find out whether this comment block is followed by |
|
// a data line or a keyword line |
|
const Sci_Position docLines = styler.GetLine(styler.Length() - 1); |
|
|
|
for ( Sci_Position line = endLine + 1; line <= docLines; line++ ) { |
|
Sci_Position lineType = LineType(line, styler) ; |
|
|
|
if ( lineType != 8 ) { |
|
if ( !(lineType & 4) ) { |
|
beginComment = endLine + 1 ; |
|
} |
|
break ; |
|
} |
|
} |
|
} |
|
|
|
if ( beginData < 0 ) { |
|
beginData = beginComment ; |
|
if ( prvKeyLineTp != 5 ) |
|
SafeSetLevel(prvKeyLine, level, styler) ; |
|
else |
|
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ; |
|
} else { |
|
SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ; |
|
} |
|
|
|
int datLevel = level + 1 ; |
|
if ( !(prvKeyLineTp & 4) ) { |
|
datLevel = level ; |
|
} |
|
|
|
for ( Sci_Position ll = beginData; ll < beginComment; ll++ ) |
|
SafeSetLevel(ll, datLevel, styler) ; |
|
|
|
if ( prvKeyLineTp == 5 ) { |
|
level += 1 ; |
|
} |
|
|
|
if ( prvKeyLineTp == 6 ) { |
|
level -= 1 ; |
|
} |
|
for ( Sci_Position m = beginComment; m <= endLine; m++ ) |
|
SafeSetLevel(m, level, styler) ; |
|
} |
|
|
|
static const char * const abaqusWordListDesc[] = { |
|
"processors", |
|
"commands", |
|
"slashommands", |
|
"starcommands", |
|
"arguments", |
|
"functions", |
|
0 |
|
}; |
|
|
|
extern const LexerModule lmAbaqus(SCLEX_ABAQUS, ColouriseABAQUSDoc, "abaqus", FoldABAQUSDoc, abaqusWordListDesc);
|
|
|