1 // Scintilla source code edit control
2 /** @file LexCsound.cxx
3 ** Lexer for Csound (Orchestra & Score)
4 ** Written by Georg Ritter - <ritterfuture A T gmail D O T com>
5 **/
6 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
15
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
19
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
26
27 #ifdef SCI_NAMESPACE
28 using namespace Scintilla;
29 #endif
30
IsAWordChar(const int ch)31 static inline bool IsAWordChar(const int ch) {
32 return (ch < 0x80) && (isalnum(ch) || ch == '.' ||
33 ch == '_' || ch == '?');
34 }
35
IsAWordStart(const int ch)36 static inline bool IsAWordStart(const int ch) {
37 return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.' ||
38 ch == '%' || ch == '@' || ch == '$' || ch == '?');
39 }
40
IsCsoundOperator(char ch)41 static inline bool IsCsoundOperator(char ch) {
42 if (IsASCII(ch) && isalnum(ch))
43 return false;
44 // '.' left out as it is used to make up numbers
45 if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
46 ch == '(' || ch == ')' || ch == '=' || ch == '^' ||
47 ch == '[' || ch == ']' || ch == '<' || ch == '&' ||
48 ch == '>' || ch == ',' || ch == '|' || ch == '~' ||
49 ch == '%' || ch == ':')
50 return true;
51 return false;
52 }
53
ColouriseCsoundDoc(unsigned int startPos,int length,int initStyle,WordList * keywordlists[],Accessor & styler)54 static void ColouriseCsoundDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
55 Accessor &styler) {
56
57 WordList &opcode = *keywordlists[0];
58 WordList &headerStmt = *keywordlists[1];
59 WordList &otherKeyword = *keywordlists[2];
60
61 // Do not leak onto next line
62 if (initStyle == SCE_CSOUND_STRINGEOL)
63 initStyle = SCE_CSOUND_DEFAULT;
64
65 StyleContext sc(startPos, length, initStyle, styler);
66
67 for (; sc.More(); sc.Forward())
68 {
69 // Handle line continuation generically.
70 if (sc.ch == '\\') {
71 if (sc.chNext == '\n' || sc.chNext == '\r') {
72 sc.Forward();
73 if (sc.ch == '\r' && sc.chNext == '\n') {
74 sc.Forward();
75 }
76 continue;
77 }
78 }
79
80 // Determine if the current state should terminate.
81 if (sc.state == SCE_CSOUND_OPERATOR) {
82 if (!IsCsoundOperator(static_cast<char>(sc.ch))) {
83 sc.SetState(SCE_CSOUND_DEFAULT);
84 }
85 }else if (sc.state == SCE_CSOUND_NUMBER) {
86 if (!IsAWordChar(sc.ch)) {
87 sc.SetState(SCE_CSOUND_DEFAULT);
88 }
89 } else if (sc.state == SCE_CSOUND_IDENTIFIER) {
90 if (!IsAWordChar(sc.ch) ) {
91 char s[100];
92 sc.GetCurrent(s, sizeof(s));
93
94 if (opcode.InList(s)) {
95 sc.ChangeState(SCE_CSOUND_OPCODE);
96 } else if (headerStmt.InList(s)) {
97 sc.ChangeState(SCE_CSOUND_HEADERSTMT);
98 } else if (otherKeyword.InList(s)) {
99 sc.ChangeState(SCE_CSOUND_USERKEYWORD);
100 } else if (s[0] == 'p') {
101 sc.ChangeState(SCE_CSOUND_PARAM);
102 } else if (s[0] == 'a') {
103 sc.ChangeState(SCE_CSOUND_ARATE_VAR);
104 } else if (s[0] == 'k') {
105 sc.ChangeState(SCE_CSOUND_KRATE_VAR);
106 } else if (s[0] == 'i') { // covers both i-rate variables and i-statements
107 sc.ChangeState(SCE_CSOUND_IRATE_VAR);
108 } else if (s[0] == 'g') {
109 sc.ChangeState(SCE_CSOUND_GLOBAL_VAR);
110 }
111 sc.SetState(SCE_CSOUND_DEFAULT);
112 }
113 }
114 else if (sc.state == SCE_CSOUND_COMMENT ) {
115 if (sc.atLineEnd) {
116 sc.SetState(SCE_CSOUND_DEFAULT);
117 }
118 }
119 else if ((sc.state == SCE_CSOUND_ARATE_VAR) ||
120 (sc.state == SCE_CSOUND_KRATE_VAR) ||
121 (sc.state == SCE_CSOUND_IRATE_VAR)) {
122 if (!IsAWordChar(sc.ch)) {
123 sc.SetState(SCE_CSOUND_DEFAULT);
124 }
125 }
126
127 // Determine if a new state should be entered.
128 if (sc.state == SCE_CSOUND_DEFAULT) {
129 if (sc.ch == ';'){
130 sc.SetState(SCE_CSOUND_COMMENT);
131 } else if (isdigit(sc.ch) || (sc.ch == '.' && isdigit(sc.chNext))) {
132 sc.SetState(SCE_CSOUND_NUMBER);
133 } else if (IsAWordStart(sc.ch)) {
134 sc.SetState(SCE_CSOUND_IDENTIFIER);
135 } else if (IsCsoundOperator(static_cast<char>(sc.ch))) {
136 sc.SetState(SCE_CSOUND_OPERATOR);
137 } else if (sc.ch == 'p') {
138 sc.SetState(SCE_CSOUND_PARAM);
139 } else if (sc.ch == 'a') {
140 sc.SetState(SCE_CSOUND_ARATE_VAR);
141 } else if (sc.ch == 'k') {
142 sc.SetState(SCE_CSOUND_KRATE_VAR);
143 } else if (sc.ch == 'i') { // covers both i-rate variables and i-statements
144 sc.SetState(SCE_CSOUND_IRATE_VAR);
145 } else if (sc.ch == 'g') {
146 sc.SetState(SCE_CSOUND_GLOBAL_VAR);
147 }
148 }
149 }
150 sc.Complete();
151 }
152
FoldCsoundInstruments(unsigned int startPos,int length,int,WordList * [],Accessor & styler)153 static void FoldCsoundInstruments(unsigned int startPos, int length, int /* initStyle */, WordList *[],
154 Accessor &styler) {
155 unsigned int lengthDoc = startPos + length;
156 int visibleChars = 0;
157 int lineCurrent = styler.GetLine(startPos);
158 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
159 int levelCurrent = levelPrev;
160 char chNext = styler[startPos];
161 int stylePrev = 0;
162 int styleNext = styler.StyleAt(startPos);
163 for (unsigned int i = startPos; i < lengthDoc; i++) {
164 char ch = chNext;
165 chNext = styler.SafeGetCharAt(i + 1);
166 int style = styleNext;
167 styleNext = styler.StyleAt(i + 1);
168 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
169 if ((stylePrev != SCE_CSOUND_OPCODE) && (style == SCE_CSOUND_OPCODE)) {
170 char s[20];
171 unsigned int j = 0;
172 while ((j < (sizeof(s) - 1)) && (iswordchar(styler[i + j]))) {
173 s[j] = styler[i + j];
174 j++;
175 }
176 s[j] = '\0';
177
178 if (strcmp(s, "instr") == 0)
179 levelCurrent++;
180 if (strcmp(s, "endin") == 0)
181 levelCurrent--;
182 }
183
184 if (atEOL) {
185 int lev = levelPrev;
186 if (visibleChars == 0)
187 lev |= SC_FOLDLEVELWHITEFLAG;
188 if ((levelCurrent > levelPrev) && (visibleChars > 0))
189 lev |= SC_FOLDLEVELHEADERFLAG;
190 if (lev != styler.LevelAt(lineCurrent)) {
191 styler.SetLevel(lineCurrent, lev);
192 }
193 lineCurrent++;
194 levelPrev = levelCurrent;
195 visibleChars = 0;
196 }
197 if (!isspacechar(ch))
198 visibleChars++;
199 stylePrev = style;
200 }
201 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
202 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
203 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
204 }
205
206
207 static const char * const csoundWordListDesc[] = {
208 "Opcodes",
209 "Header Statements",
210 "User keywords",
211 0
212 };
213
214 LexerModule lmCsound(SCLEX_CSOUND, ColouriseCsoundDoc, "csound", FoldCsoundInstruments, csoundWordListDesc);
215