|
|
|
// Scintilla source code edit control
|
|
|
|
/** @file LexDMIS.cxx
|
|
|
|
** Lexer for DMIS.
|
|
|
|
**/
|
|
|
|
// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
|
|
|
|
// Copyright 2013-2014 by Andreas Tscharner <andy@vis.ethz.ch>
|
|
|
|
// The License.txt file describes the conditions under which this software may be distributed.
|
|
|
|
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cctype>
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <string_view>
|
|
|
|
|
|
|
|
#include "ILexer.h"
|
|
|
|
#include "Scintilla.h"
|
|
|
|
#include "SciLexer.h"
|
|
|
|
|
|
|
|
#include "WordList.h"
|
|
|
|
#include "LexAccessor.h"
|
|
|
|
#include "StyleContext.h"
|
|
|
|
#include "CharacterSet.h"
|
|
|
|
#include "LexerModule.h"
|
|
|
|
#include "DefaultLexer.h"
|
|
|
|
|
|
|
|
using namespace Lexilla;
|
|
|
|
|
|
|
|
|
|
|
|
static const char *const DMISWordListDesc[] = {
|
|
|
|
"DMIS Major Words",
|
|
|
|
"DMIS Minor Words",
|
|
|
|
"Unsupported DMIS Major Words",
|
|
|
|
"Unsupported DMIS Minor Words",
|
|
|
|
"Keywords for code folding start",
|
|
|
|
"Corresponding keywords for code folding end",
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class LexerDMIS : public DefaultLexer
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
char *m_wordListSets;
|
|
|
|
WordList m_majorWords;
|
|
|
|
WordList m_minorWords;
|
|
|
|
WordList m_unsupportedMajor;
|
|
|
|
WordList m_unsupportedMinor;
|
|
|
|
WordList m_codeFoldingStart;
|
|
|
|
WordList m_codeFoldingEnd;
|
|
|
|
|
|
|
|
char * SCI_METHOD UpperCase(char *item);
|
|
|
|
void SCI_METHOD InitWordListSets(void);
|
|
|
|
|
|
|
|
public:
|
|
|
|
LexerDMIS(void);
|
|
|
|
virtual ~LexerDMIS(void);
|
|
|
|
|
|
|
|
int SCI_METHOD Version() const override {
|
|
|
|
return Scintilla::lvRelease5;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SCI_METHOD Release() override {
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char * SCI_METHOD PropertyNames() override {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SCI_METHOD PropertyType(const char *) override {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char * SCI_METHOD DescribeProperty(const char *) override {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sci_Position SCI_METHOD PropertySet(const char *, const char *) override {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char * SCI_METHOD PropertyGet(const char *) override {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
|
|
|
|
|
|
|
|
void * SCI_METHOD PrivateCall(int, void *) override {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ILexer5 *LexerFactoryDMIS() {
|
|
|
|
return new LexerDMIS;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char * SCI_METHOD DescribeWordListSets() override;
|
|
|
|
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, Scintilla::IDocument *pAccess) override;
|
|
|
|
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, Scintilla::IDocument *pAccess) override;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
char * SCI_METHOD LexerDMIS::UpperCase(char *item)
|
|
|
|
{
|
|
|
|
char *itemStart;
|
|
|
|
|
|
|
|
|
|
|
|
itemStart = item;
|
|
|
|
while (item && *item) {
|
|
|
|
*item = toupper(*item);
|
|
|
|
item++;
|
|
|
|
};
|
|
|
|
return itemStart;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SCI_METHOD LexerDMIS::InitWordListSets(void)
|
|
|
|
{
|
|
|
|
size_t totalLen = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; DMISWordListDesc[i]; i++) {
|
|
|
|
totalLen += strlen(DMISWordListDesc[i]);
|
|
|
|
totalLen++;
|
|
|
|
};
|
|
|
|
|
|
|
|
totalLen++;
|
|
|
|
this->m_wordListSets = new char[totalLen];
|
|
|
|
memset(this->m_wordListSets, 0, totalLen);
|
|
|
|
|
|
|
|
for (int i=0; DMISWordListDesc[i]; i++) {
|
|
|
|
strcat(this->m_wordListSets, DMISWordListDesc[i]);
|
|
|
|
strcat(this->m_wordListSets, "\n");
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LexerDMIS::LexerDMIS(void) : DefaultLexer("DMIS", SCLEX_DMIS) {
|
|
|
|
this->InitWordListSets();
|
|
|
|
|
|
|
|
this->m_majorWords.Clear();
|
|
|
|
this->m_minorWords.Clear();
|
|
|
|
this->m_unsupportedMajor.Clear();
|
|
|
|
this->m_unsupportedMinor.Clear();
|
|
|
|
this->m_codeFoldingStart.Clear();
|
|
|
|
this->m_codeFoldingEnd.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
LexerDMIS::~LexerDMIS(void) {
|
|
|
|
delete[] this->m_wordListSets;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sci_Position SCI_METHOD LexerDMIS::WordListSet(int n, const char *wl)
|
|
|
|
{
|
|
|
|
switch (n) {
|
|
|
|
case 0:
|
|
|
|
this->m_majorWords.Clear();
|
|
|
|
this->m_majorWords.Set(wl);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
this->m_minorWords.Clear();
|
|
|
|
this->m_minorWords.Set(wl);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
this->m_unsupportedMajor.Clear();
|
|
|
|
this->m_unsupportedMajor.Set(wl);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
this->m_unsupportedMinor.Clear();
|
|
|
|
this->m_unsupportedMinor.Set(wl);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
this->m_codeFoldingStart.Clear();
|
|
|
|
this->m_codeFoldingStart.Set(wl);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
this->m_codeFoldingEnd.Clear();
|
|
|
|
this->m_codeFoldingEnd.Set(wl);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char * SCI_METHOD LexerDMIS::DescribeWordListSets()
|
|
|
|
{
|
|
|
|
return this->m_wordListSets;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SCI_METHOD LexerDMIS::Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, Scintilla::IDocument *pAccess)
|
|
|
|
{
|
|
|
|
const Sci_PositionU MAX_STR_LEN = 100;
|
|
|
|
|
|
|
|
LexAccessor styler(pAccess);
|
|
|
|
StyleContext scCTX(startPos, lengthDoc, initStyle, styler);
|
|
|
|
CharacterSet setDMISNumber(CharacterSet::setDigits, ".-+eE");
|
|
|
|
CharacterSet setDMISWordStart(CharacterSet::setAlpha, "-234", 0x80, true);
|
|
|
|
CharacterSet setDMISWord(CharacterSet::setAlpha);
|
|
|
|
|
|
|
|
|
|
|
|
bool isIFLine = false;
|
|
|
|
|
|
|
|
for (; scCTX.More(); scCTX.Forward()) {
|
|
|
|
if (scCTX.atLineEnd) {
|
|
|
|
isIFLine = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
switch (scCTX.state) {
|
|
|
|
case SCE_DMIS_DEFAULT:
|
|
|
|
if (scCTX.Match('$', '$')) {
|
|
|
|
scCTX.SetState(SCE_DMIS_COMMENT);
|
|
|
|
scCTX.Forward();
|
|
|
|
};
|
|
|
|
if (scCTX.Match('\'')) {
|
|
|
|
scCTX.SetState(SCE_DMIS_STRING);
|
|
|
|
};
|
|
|
|
if (IsADigit(scCTX.ch) || ((scCTX.Match('-') || scCTX.Match('+')) && IsADigit(scCTX.chNext))) {
|
|
|
|
scCTX.SetState(SCE_DMIS_NUMBER);
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
if (setDMISWordStart.Contains(scCTX.ch)) {
|
|
|
|
scCTX.SetState(SCE_DMIS_KEYWORD);
|
|
|
|
};
|
|
|
|
if (scCTX.Match('(') && (!isIFLine)) {
|
|
|
|
scCTX.SetState(SCE_DMIS_LABEL);
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCE_DMIS_COMMENT:
|
|
|
|
if (scCTX.atLineEnd) {
|
|
|
|
scCTX.SetState(SCE_DMIS_DEFAULT);
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCE_DMIS_STRING:
|
|
|
|
if (scCTX.Match('\'')) {
|
|
|
|
scCTX.SetState(SCE_DMIS_DEFAULT);
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCE_DMIS_NUMBER:
|
|
|
|
if (!setDMISNumber.Contains(scCTX.ch)) {
|
|
|
|
scCTX.SetState(SCE_DMIS_DEFAULT);
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCE_DMIS_KEYWORD:
|
|
|
|
if (!setDMISWord.Contains(scCTX.ch)) {
|
|
|
|
char tmpStr[MAX_STR_LEN];
|
|
|
|
memset(tmpStr, 0, MAX_STR_LEN*sizeof(char));
|
|
|
|
scCTX.GetCurrent(tmpStr, (MAX_STR_LEN-1));
|
|
|
|
// The following strncpy is copying from a string back onto itself which is weird and causes warnings
|
|
|
|
// but is harmless so turn off the warning
|
|
|
|
#if defined(__GNUC__) && !defined(__clang__)
|
|
|
|
// Disable warning for strncpy
|
|
|
|
#pragma GCC diagnostic ignored "-Wrestrict"
|
|
|
|
#endif
|
|
|
|
strncpy(tmpStr, this->UpperCase(tmpStr), (MAX_STR_LEN-1));
|
|
|
|
|
|
|
|
if (this->m_minorWords.InList(tmpStr)) {
|
|
|
|
scCTX.ChangeState(SCE_DMIS_MINORWORD);
|
|
|
|
};
|
|
|
|
if (this->m_majorWords.InList(tmpStr)) {
|
|
|
|
isIFLine = (strcmp(tmpStr, "IF") == 0);
|
|
|
|
scCTX.ChangeState(SCE_DMIS_MAJORWORD);
|
|
|
|
};
|
|
|
|
if (this->m_unsupportedMajor.InList(tmpStr)) {
|
|
|
|
scCTX.ChangeState(SCE_DMIS_UNSUPPORTED_MAJOR);
|
|
|
|
};
|
|
|
|
if (this->m_unsupportedMinor.InList(tmpStr)) {
|
|
|
|
scCTX.ChangeState(SCE_DMIS_UNSUPPORTED_MINOR);
|
|
|
|
};
|
|
|
|
|
|
|
|
if (scCTX.Match('(') && (!isIFLine)) {
|
|
|
|
scCTX.SetState(SCE_DMIS_LABEL);
|
|
|
|
} else {
|
|
|
|
scCTX.SetState(SCE_DMIS_DEFAULT);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCE_DMIS_LABEL:
|
|
|
|
if (scCTX.Match(')')) {
|
|
|
|
scCTX.SetState(SCE_DMIS_DEFAULT);
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
scCTX.Complete();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SCI_METHOD LexerDMIS::Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int, Scintilla::IDocument *pAccess)
|
|
|
|
{
|
|
|
|
const int MAX_STR_LEN = 100;
|
|
|
|
|
|
|
|
LexAccessor styler(pAccess);
|
|
|
|
Sci_PositionU endPos = startPos + lengthDoc;
|
|
|
|
char chNext = styler[startPos];
|
|
|
|
Sci_Position lineCurrent = styler.GetLine(startPos);
|
|
|
|
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
|
|
|
|
int levelCurrent = levelPrev;
|
|
|
|
int strPos = 0;
|
|
|
|
bool foldWordPossible = false;
|
|
|
|
CharacterSet setDMISFoldWord(CharacterSet::setAlpha);
|
|
|
|
char *tmpStr;
|
|
|
|
|
|
|
|
|
|
|
|
tmpStr = new char[MAX_STR_LEN];
|
|
|
|
memset(tmpStr, 0, MAX_STR_LEN*sizeof(char));
|
|
|
|
|
|
|
|
for (Sci_PositionU i=startPos; i<endPos; i++) {
|
|
|
|
char ch = chNext;
|
|
|
|
chNext = styler.SafeGetCharAt(i+1);
|
|
|
|
|
|
|
|
bool atEOL = ((ch == '\r' && chNext != '\n') || (ch == '\n'));
|
|
|
|
|
|
|
|
if (strPos >= (MAX_STR_LEN-1)) {
|
|
|
|
strPos = MAX_STR_LEN-1;
|
|
|
|
};
|
|
|
|
|
|
|
|
int style = styler.StyleAt(i);
|
|
|
|
bool noFoldPos = ((style == SCE_DMIS_COMMENT) || (style == SCE_DMIS_STRING));
|
|
|
|
|
|
|
|
if (foldWordPossible) {
|
|
|
|
if (setDMISFoldWord.Contains(ch)) {
|
|
|
|
tmpStr[strPos++] = ch;
|
|
|
|
} else {
|
|
|
|
tmpStr = this->UpperCase(tmpStr);
|
|
|
|
if (this->m_codeFoldingStart.InList(tmpStr) && (!noFoldPos)) {
|
|
|
|
levelCurrent++;
|
|
|
|
};
|
|
|
|
if (this->m_codeFoldingEnd.InList(tmpStr) && (!noFoldPos)) {
|
|
|
|
levelCurrent--;
|
|
|
|
};
|
|
|
|
memset(tmpStr, 0, MAX_STR_LEN*sizeof(char));
|
|
|
|
strPos = 0;
|
|
|
|
foldWordPossible = false;
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
if (setDMISFoldWord.Contains(ch)) {
|
|
|
|
tmpStr[strPos++] = ch;
|
|
|
|
foldWordPossible = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
if (atEOL || (i == (endPos-1))) {
|
|
|
|
int lev = levelPrev;
|
|
|
|
|
|
|
|
if (levelCurrent > levelPrev) {
|
|
|
|
lev |= SC_FOLDLEVELHEADERFLAG;
|
|
|
|
};
|
|
|
|
if (lev != styler.LevelAt(lineCurrent)) {
|
|
|
|
styler.SetLevel(lineCurrent, lev);
|
|
|
|
};
|
|
|
|
lineCurrent++;
|
|
|
|
levelPrev = levelCurrent;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
delete[] tmpStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LexerModule lmDMIS(SCLEX_DMIS, LexerDMIS::LexerFactoryDMIS, "DMIS", DMISWordListDesc);
|