231 lines
6.8 KiB
C++
231 lines
6.8 KiB
C++
|
// Scintilla source code edit control
|
||
|
/** @file LexSpice.cxx
|
||
|
** Lexer for Spice
|
||
|
**/
|
||
|
// Copyright 2006 by Fabien Proriol
|
||
|
// The License.txt file describes the conditions under which this software may be distributed.
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <assert.h>
|
||
|
|
||
|
#include <string>
|
||
|
|
||
|
#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"
|
||
|
|
||
|
#ifdef SCI_NAMESPACE
|
||
|
using namespace Scintilla;
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* Interface
|
||
|
*/
|
||
|
|
||
|
static void ColouriseDocument(
|
||
|
unsigned int startPos,
|
||
|
int length,
|
||
|
int initStyle,
|
||
|
WordList *keywordlists[],
|
||
|
Accessor &styler);
|
||
|
|
||
|
static const char * const spiceWordListDesc[] = {
|
||
|
"Keywords", // SPICE command
|
||
|
"Keywords2", // SPICE functions
|
||
|
"Keywords3", // SPICE params
|
||
|
0
|
||
|
};
|
||
|
|
||
|
LexerModule lmSpice(SCLEX_SPICE, ColouriseDocument, "spice", NULL, spiceWordListDesc);
|
||
|
|
||
|
/*
|
||
|
* Implementation
|
||
|
*/
|
||
|
|
||
|
static void ColouriseComment(StyleContext& sc, bool& apostropheStartsAttribute);
|
||
|
static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute);
|
||
|
static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute);
|
||
|
static void ColouriseWhiteSpace(StyleContext& sc, bool& apostropheStartsAttribute);
|
||
|
static void ColouriseWord(StyleContext& sc, WordList& keywords, WordList& keywords2, WordList& keywords3, bool& apostropheStartsAttribute);
|
||
|
|
||
|
static inline bool IsDelimiterCharacter(int ch);
|
||
|
static inline bool IsNumberStartCharacter(int ch);
|
||
|
static inline bool IsNumberCharacter(int ch);
|
||
|
static inline bool IsSeparatorOrDelimiterCharacter(int ch);
|
||
|
static inline bool IsWordStartCharacter(int ch);
|
||
|
static inline bool IsWordCharacter(int ch);
|
||
|
|
||
|
static void ColouriseComment(StyleContext& sc, bool&) {
|
||
|
sc.SetState(SCE_SPICE_COMMENTLINE);
|
||
|
while (!sc.atLineEnd) {
|
||
|
sc.Forward();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute) {
|
||
|
apostropheStartsAttribute = sc.Match (')');
|
||
|
sc.SetState(SCE_SPICE_DELIMITER);
|
||
|
sc.ForwardSetState(SCE_SPICE_DEFAULT);
|
||
|
}
|
||
|
|
||
|
static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute) {
|
||
|
apostropheStartsAttribute = true;
|
||
|
std::string number;
|
||
|
sc.SetState(SCE_SPICE_NUMBER);
|
||
|
// Get all characters up to a delimiter or a separator, including points, but excluding
|
||
|
// double points (ranges).
|
||
|
while (!IsSeparatorOrDelimiterCharacter(sc.ch) || (sc.ch == '.' && sc.chNext != '.')) {
|
||
|
number += static_cast<char>(sc.ch);
|
||
|
sc.Forward();
|
||
|
}
|
||
|
// Special case: exponent with sign
|
||
|
if ((sc.chPrev == 'e' || sc.chPrev == 'E') &&
|
||
|
(sc.ch == '+' || sc.ch == '-')) {
|
||
|
number += static_cast<char>(sc.ch);
|
||
|
sc.Forward ();
|
||
|
while (!IsSeparatorOrDelimiterCharacter(sc.ch)) {
|
||
|
number += static_cast<char>(sc.ch);
|
||
|
sc.Forward();
|
||
|
}
|
||
|
}
|
||
|
sc.SetState(SCE_SPICE_DEFAULT);
|
||
|
}
|
||
|
|
||
|
static void ColouriseWhiteSpace(StyleContext& sc, bool& ) {
|
||
|
sc.SetState(SCE_SPICE_DEFAULT);
|
||
|
sc.ForwardSetState(SCE_SPICE_DEFAULT);
|
||
|
}
|
||
|
|
||
|
static void ColouriseWord(StyleContext& sc, WordList& keywords, WordList& keywords2, WordList& keywords3, bool& apostropheStartsAttribute) {
|
||
|
apostropheStartsAttribute = true;
|
||
|
sc.SetState(SCE_SPICE_IDENTIFIER);
|
||
|
std::string word;
|
||
|
while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
|
||
|
word += static_cast<char>(tolower(sc.ch));
|
||
|
sc.Forward();
|
||
|
}
|
||
|
if (keywords.InList(word.c_str())) {
|
||
|
sc.ChangeState(SCE_SPICE_KEYWORD);
|
||
|
if (word != "all") {
|
||
|
apostropheStartsAttribute = false;
|
||
|
}
|
||
|
}
|
||
|
else if (keywords2.InList(word.c_str())) {
|
||
|
sc.ChangeState(SCE_SPICE_KEYWORD2);
|
||
|
if (word != "all") {
|
||
|
apostropheStartsAttribute = false;
|
||
|
}
|
||
|
}
|
||
|
else if (keywords3.InList(word.c_str())) {
|
||
|
sc.ChangeState(SCE_SPICE_KEYWORD3);
|
||
|
if (word != "all") {
|
||
|
apostropheStartsAttribute = false;
|
||
|
}
|
||
|
}
|
||
|
sc.SetState(SCE_SPICE_DEFAULT);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// ColouriseDocument
|
||
|
//
|
||
|
static void ColouriseDocument(
|
||
|
unsigned int startPos,
|
||
|
int length,
|
||
|
int initStyle,
|
||
|
WordList *keywordlists[],
|
||
|
Accessor &styler) {
|
||
|
WordList &keywords = *keywordlists[0];
|
||
|
WordList &keywords2 = *keywordlists[1];
|
||
|
WordList &keywords3 = *keywordlists[2];
|
||
|
StyleContext sc(startPos, length, initStyle, styler);
|
||
|
int lineCurrent = styler.GetLine(startPos);
|
||
|
bool apostropheStartsAttribute = (styler.GetLineState(lineCurrent) & 1) != 0;
|
||
|
while (sc.More()) {
|
||
|
if (sc.atLineEnd) {
|
||
|
// Go to the next line
|
||
|
sc.Forward();
|
||
|
lineCurrent++;
|
||
|
// Remember the line state for future incremental lexing
|
||
|
styler.SetLineState(lineCurrent, apostropheStartsAttribute);
|
||
|
// Don't continue any styles on the next line
|
||
|
sc.SetState(SCE_SPICE_DEFAULT);
|
||
|
}
|
||
|
// Comments
|
||
|
if ((sc.Match('*') && sc.atLineStart) || sc.Match('*','~')) {
|
||
|
ColouriseComment(sc, apostropheStartsAttribute);
|
||
|
// Whitespace
|
||
|
} else if (IsASpace(sc.ch)) {
|
||
|
ColouriseWhiteSpace(sc, apostropheStartsAttribute);
|
||
|
// Delimiters
|
||
|
} else if (IsDelimiterCharacter(sc.ch)) {
|
||
|
ColouriseDelimiter(sc, apostropheStartsAttribute);
|
||
|
// Numbers
|
||
|
} else if (IsADigit(sc.ch) || sc.ch == '#') {
|
||
|
ColouriseNumber(sc, apostropheStartsAttribute);
|
||
|
// Keywords or identifiers
|
||
|
} else {
|
||
|
ColouriseWord(sc, keywords, keywords2, keywords3, apostropheStartsAttribute);
|
||
|
}
|
||
|
}
|
||
|
sc.Complete();
|
||
|
}
|
||
|
|
||
|
static inline bool IsDelimiterCharacter(int ch) {
|
||
|
switch (ch) {
|
||
|
case '&':
|
||
|
case '\'':
|
||
|
case '(':
|
||
|
case ')':
|
||
|
case '*':
|
||
|
case '+':
|
||
|
case ',':
|
||
|
case '-':
|
||
|
case '.':
|
||
|
case '/':
|
||
|
case ':':
|
||
|
case ';':
|
||
|
case '<':
|
||
|
case '=':
|
||
|
case '>':
|
||
|
case '|':
|
||
|
return true;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline bool IsNumberCharacter(int ch) {
|
||
|
return IsNumberStartCharacter(ch) ||
|
||
|
ch == '_' ||
|
||
|
ch == '.' ||
|
||
|
ch == '#' ||
|
||
|
(ch >= 'a' && ch <= 'f') ||
|
||
|
(ch >= 'A' && ch <= 'F');
|
||
|
}
|
||
|
|
||
|
static inline bool IsNumberStartCharacter(int ch) {
|
||
|
return IsADigit(ch);
|
||
|
}
|
||
|
|
||
|
static inline bool IsSeparatorOrDelimiterCharacter(int ch) {
|
||
|
return IsASpace(ch) || IsDelimiterCharacter(ch);
|
||
|
}
|
||
|
|
||
|
static inline bool IsWordCharacter(int ch) {
|
||
|
return IsWordStartCharacter(ch) || IsADigit(ch);
|
||
|
}
|
||
|
|
||
|
static inline bool IsWordStartCharacter(int ch) {
|
||
|
return (isascii(ch) && isalpha(ch)) || ch == '_';
|
||
|
}
|