1 // Scintilla source code edit control
2 /** @file LexSpice.cxx
3 ** Lexer for Spice
4 **/
5 // Copyright 2006 by Fabien Proriol
6 // The License.txt file describes the conditions under which this software may be distributed.
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include <stdarg.h>
12 #include <assert.h>
13 #include <ctype.h>
14
15 #include <string>
16
17 #include "ILexer.h"
18 #include "Scintilla.h"
19 #include "SciLexer.h"
20
21 #include "WordList.h"
22 #include "LexAccessor.h"
23 #include "Accessor.h"
24 #include "StyleContext.h"
25 #include "CharacterSet.h"
26 #include "LexerModule.h"
27
28 using namespace Scintilla;
29
30 /*
31 * Interface
32 */
33
34 static void ColouriseDocument(
35 Sci_PositionU startPos,
36 Sci_Position length,
37 int initStyle,
38 WordList *keywordlists[],
39 Accessor &styler);
40
41 static const char * const spiceWordListDesc[] = {
42 "Keywords", // SPICE command
43 "Keywords2", // SPICE functions
44 "Keywords3", // SPICE params
45 0
46 };
47
48 LexerModule lmSpice(SCLEX_SPICE, ColouriseDocument, "spice", NULL, spiceWordListDesc);
49
50 /*
51 * Implementation
52 */
53
54 static void ColouriseComment(StyleContext& sc, bool& apostropheStartsAttribute);
55 static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute);
56 static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute);
57 static void ColouriseWhiteSpace(StyleContext& sc, bool& apostropheStartsAttribute);
58 static void ColouriseWord(StyleContext& sc, WordList& keywords, WordList& keywords2, WordList& keywords3, bool& apostropheStartsAttribute);
59
60 static inline bool IsDelimiterCharacter(int ch);
61 static inline bool IsSeparatorOrDelimiterCharacter(int ch);
62
ColouriseComment(StyleContext & sc,bool &)63 static void ColouriseComment(StyleContext& sc, bool&) {
64 sc.SetState(SCE_SPICE_COMMENTLINE);
65 while (!sc.atLineEnd) {
66 sc.Forward();
67 }
68 }
69
ColouriseDelimiter(StyleContext & sc,bool & apostropheStartsAttribute)70 static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute) {
71 apostropheStartsAttribute = sc.Match (')');
72 sc.SetState(SCE_SPICE_DELIMITER);
73 sc.ForwardSetState(SCE_SPICE_DEFAULT);
74 }
75
ColouriseNumber(StyleContext & sc,bool & apostropheStartsAttribute)76 static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute) {
77 apostropheStartsAttribute = true;
78 std::string number;
79 sc.SetState(SCE_SPICE_NUMBER);
80 // Get all characters up to a delimiter or a separator, including points, but excluding
81 // double points (ranges).
82 while (!IsSeparatorOrDelimiterCharacter(sc.ch) || (sc.ch == '.' && sc.chNext != '.')) {
83 number += static_cast<char>(sc.ch);
84 sc.Forward();
85 }
86 // Special case: exponent with sign
87 if ((sc.chPrev == 'e' || sc.chPrev == 'E') &&
88 (sc.ch == '+' || sc.ch == '-')) {
89 number += static_cast<char>(sc.ch);
90 sc.Forward ();
91 while (!IsSeparatorOrDelimiterCharacter(sc.ch)) {
92 number += static_cast<char>(sc.ch);
93 sc.Forward();
94 }
95 }
96 sc.SetState(SCE_SPICE_DEFAULT);
97 }
98
ColouriseWhiteSpace(StyleContext & sc,bool &)99 static void ColouriseWhiteSpace(StyleContext& sc, bool& ) {
100 sc.SetState(SCE_SPICE_DEFAULT);
101 sc.ForwardSetState(SCE_SPICE_DEFAULT);
102 }
103
ColouriseWord(StyleContext & sc,WordList & keywords,WordList & keywords2,WordList & keywords3,bool & apostropheStartsAttribute)104 static void ColouriseWord(StyleContext& sc, WordList& keywords, WordList& keywords2, WordList& keywords3, bool& apostropheStartsAttribute) {
105 apostropheStartsAttribute = true;
106 sc.SetState(SCE_SPICE_IDENTIFIER);
107 std::string word;
108 while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
109 word += static_cast<char>(tolower(sc.ch));
110 sc.Forward();
111 }
112 if (keywords.InList(word.c_str())) {
113 sc.ChangeState(SCE_SPICE_KEYWORD);
114 if (word != "all") {
115 apostropheStartsAttribute = false;
116 }
117 }
118 else if (keywords2.InList(word.c_str())) {
119 sc.ChangeState(SCE_SPICE_KEYWORD2);
120 if (word != "all") {
121 apostropheStartsAttribute = false;
122 }
123 }
124 else if (keywords3.InList(word.c_str())) {
125 sc.ChangeState(SCE_SPICE_KEYWORD3);
126 if (word != "all") {
127 apostropheStartsAttribute = false;
128 }
129 }
130 sc.SetState(SCE_SPICE_DEFAULT);
131 }
132
133 //
134 // ColouriseDocument
135 //
ColouriseDocument(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler)136 static void ColouriseDocument(
137 Sci_PositionU startPos,
138 Sci_Position length,
139 int initStyle,
140 WordList *keywordlists[],
141 Accessor &styler) {
142 WordList &keywords = *keywordlists[0];
143 WordList &keywords2 = *keywordlists[1];
144 WordList &keywords3 = *keywordlists[2];
145 StyleContext sc(startPos, length, initStyle, styler);
146 Sci_Position lineCurrent = styler.GetLine(startPos);
147 bool apostropheStartsAttribute = (styler.GetLineState(lineCurrent) & 1) != 0;
148 while (sc.More()) {
149 if (sc.atLineEnd) {
150 // Go to the next line
151 sc.Forward();
152 lineCurrent++;
153 // Remember the line state for future incremental lexing
154 styler.SetLineState(lineCurrent, apostropheStartsAttribute);
155 // Don't continue any styles on the next line
156 sc.SetState(SCE_SPICE_DEFAULT);
157 }
158 // Comments
159 if ((sc.Match('*') && sc.atLineStart) || sc.Match('*','~')) {
160 ColouriseComment(sc, apostropheStartsAttribute);
161 // Whitespace
162 } else if (IsASpace(sc.ch)) {
163 ColouriseWhiteSpace(sc, apostropheStartsAttribute);
164 // Delimiters
165 } else if (IsDelimiterCharacter(sc.ch)) {
166 ColouriseDelimiter(sc, apostropheStartsAttribute);
167 // Numbers
168 } else if (IsADigit(sc.ch) || sc.ch == '#') {
169 ColouriseNumber(sc, apostropheStartsAttribute);
170 // Keywords or identifiers
171 } else {
172 ColouriseWord(sc, keywords, keywords2, keywords3, apostropheStartsAttribute);
173 }
174 }
175 sc.Complete();
176 }
177
IsDelimiterCharacter(int ch)178 static inline bool IsDelimiterCharacter(int ch) {
179 switch (ch) {
180 case '&':
181 case '\'':
182 case '(':
183 case ')':
184 case '*':
185 case '+':
186 case ',':
187 case '-':
188 case '.':
189 case '/':
190 case ':':
191 case ';':
192 case '<':
193 case '=':
194 case '>':
195 case '|':
196 return true;
197 default:
198 return false;
199 }
200 }
201
IsSeparatorOrDelimiterCharacter(int ch)202 static inline bool IsSeparatorOrDelimiterCharacter(int ch) {
203 return IsASpace(ch) || IsDelimiterCharacter(ch);
204 }
205