notepad-plus-plus/lexilla/lexers/LexDMIS.cxx

368 lines
8.6 KiB
C++

// 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);