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