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>
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.
17 #include "Scintilla.h"
21 #include "LexAccessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
27 using namespace Scintilla
;
29 static inline bool IsAWordChar(const int ch
) {
30 return (ch
< 0x80) && (isalnum(ch
) || ch
== '.' ||
31 ch
== '_' || ch
== '?');
34 static inline bool IsAWordStart(const int ch
) {
35 return (ch
< 0x80) && (isalnum(ch
) || ch
== '_' || ch
== '.' ||
36 ch
== '%' || ch
== '@' || ch
== '$' || ch
== '?');
39 static inline bool IsCsoundOperator(char ch
) {
40 if (IsASCII(ch
) && isalnum(ch
))
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
== ':')
52 static void ColouriseCsoundDoc(Sci_PositionU startPos
, Sci_Position length
, int initStyle
, WordList
*keywordlists
[],
55 WordList
&opcode
= *keywordlists
[0];
56 WordList
&headerStmt
= *keywordlists
[1];
57 WordList
&otherKeyword
= *keywordlists
[2];
59 // Do not leak onto next line
60 if (initStyle
== SCE_CSOUND_STRINGEOL
)
61 initStyle
= SCE_CSOUND_DEFAULT
;
63 StyleContext
sc(startPos
, length
, initStyle
, styler
);
65 for (; sc
.More(); sc
.Forward())
67 // Handle line continuation generically.
69 if (sc
.chNext
== '\n' || sc
.chNext
== '\r') {
71 if (sc
.ch
== '\r' && sc
.chNext
== '\n') {
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
);
83 }else if (sc
.state
== SCE_CSOUND_NUMBER
) {
84 if (!IsAWordChar(sc
.ch
)) {
85 sc
.SetState(SCE_CSOUND_DEFAULT
);
87 } else if (sc
.state
== SCE_CSOUND_IDENTIFIER
) {
88 if (!IsAWordChar(sc
.ch
) ) {
90 sc
.GetCurrent(s
, sizeof(s
));
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
);
109 sc
.SetState(SCE_CSOUND_DEFAULT
);
112 else if (sc
.state
== SCE_CSOUND_COMMENT
) {
114 sc
.SetState(SCE_CSOUND_DEFAULT
);
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
);
125 // Determine if a new state should be entered.
126 if (sc
.state
== SCE_CSOUND_DEFAULT
) {
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
);
151 static void FoldCsoundInstruments(Sci_PositionU startPos
, Sci_Position length
, int /* initStyle */, WordList
*[],
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
];
160 int styleNext
= styler
.StyleAt(startPos
);
161 for (Sci_PositionU i
= startPos
; i
< lengthDoc
; i
++) {
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
)) {
170 while ((j
< (sizeof(s
) - 1)) && (iswordchar(styler
[i
+ j
]))) {
171 s
[j
] = styler
[i
+ j
];
176 if (strcmp(s
, "instr") == 0)
178 if (strcmp(s
, "endin") == 0)
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
);
192 levelPrev
= levelCurrent
;
195 if (!isspacechar(ch
))
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
);
205 static const char * const csoundWordListDesc
[] = {
212 LexerModule
lmCsound(SCLEX_CSOUND
, ColouriseCsoundDoc
, "csound", FoldCsoundInstruments
, csoundWordListDesc
);