/[svn]/linuxsampler/trunk/src/scriptvm/editor/nksp.l
ViewVC logotype

Contents of /linuxsampler/trunk/src/scriptvm/editor/nksp.l

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3332 - (show annotations) (download)
Mon Jul 24 18:51:21 2017 UTC (6 years, 8 months ago) by schoenebeck
File size: 8394 byte(s)
* NKSP script editor syntax highlighting API: catch all fatal lexer
  errors, to avoid the editor app to crash on ill-formed text input.
* Bumped version (2.0.0.svn74).

1 /*
2 * Copyright (c) 2015-2017 Christian Schoenebeck
3 *
4 * http://www.linuxsampler.org
5 *
6 * This file is part of LinuxSampler and released under the same terms.
7 * See README file for details.
8 */
9
10 /* Token scanner used for generating syntax highlighting for NKSP instrument
11 script language code (this is not used by the sampler itself, but rather
12 provided for external script editor applications). */
13
14 %{
15
16 #include "NkspScanner.h"
17 // reentrant scanner data context
18 #define YY_EXTRA_TYPE NkspScanner*
19 // custom (f)lex input for reading from std::istream object
20 #define YY_INPUT(buf,result,max_size) \
21 { \
22 char c = yyextra->is->get(); \
23 if (yyextra->is->eof()) \
24 result = YY_NULL; \
25 else { \
26 buf[0] = c; \
27 result = 1; \
28 } \
29 }
30 // handle position (line, column) for each recognized token
31 #define YY_USER_ACTION \
32 yyextra->line = yylineno - 1; \
33 yyextra->column = yycolumn; \
34 yycolumn += yyleng;
35
36 using namespace LinuxSampler;
37
38 static int countNewLineChars(const char* txt) {
39 int n = 0;
40 for (int i = 0; txt[i]; ++i)
41 if (txt[i] == '\n') ++n;
42 return n;
43 }
44
45 // shut up warning that 'register' keyword is deprecated as of C++11
46 #if defined(__cplusplus) && __cplusplus >= 201103L
47 # define register
48 #endif
49
50 // Since this parser is solely used by script code editors, thus not used in a
51 // real-time context, always throw an exception instead of exiting on fatal
52 // lexer errors (so the debugger may pause with the appropriate back trace)
53 #include <stdexcept>
54 #define YY_FATAL_ERROR(msg) throw std::runtime_error(msg)
55
56 %}
57
58 /* generate a reentrant safe scanner */
59 %option reentrant
60 /* avoid symbol collision with ones of other scanners */
61 %option prefix="Nksp_"
62 /* yywrap() would be called at EOF, we don't need it */
63 %option noyywrap
64 /* enable functions yy_push_state(), yy_pop_state(), yy_top_state() */
65 %option stack
66
67 /* inclusive scanner conditions */
68 %s PREPROC_BODY_USE
69 /* exclusive scanner conditions */
70 %x PREPROC_SET_COND PREPROC_RESET_COND PREPROC_IF PREPROC_IF_NOT PREPROC_BODY_EAT PREPROC_PRE_BODY_USE PREPROC_PRE_BODY_EAT PREPROC_EVENT_NAME PREPROC_END_NAME
71
72 DIGIT [0-9]
73 ID [a-zA-Z0-9_]+
74 END_ID on|while|if|select|function|synchronized
75
76 %%
77
78 \"[^"]*\" {
79 yyextra->token = StringLiteralToken(yytext);
80 return yyextra->token.baseType;
81 }
82
83 {DIGIT}+ {
84 yyextra->token = NumberLiteralToken(yytext);
85 return yyextra->token.baseType;
86 }
87
88 /* there is currently no support for floating point numbers in NKSP yet */
89 /*{DIGIT}+"."{DIGIT}* {
90 yyextra->token = NumberLiteralToken(yytext);
91 return yyextra->token.baseType;
92 }*/
93
94
95 /* Preprocessor statement: SET_CONDITION(name) */
96
97 <*>"SET_CONDITION"[ \t]*"(" {
98 //printf("SET_CONDITION\n");
99 yy_push_state(PREPROC_SET_COND, yyscanner);
100 yyextra->token = PreprocessorToken(yytext);
101 return yyextra->token.baseType;
102 }
103 <PREPROC_SET_COND>{ID} {
104 //printf("preproc set condition '%s'\n", yytext);
105 yyextra->token = PreprocessorToken(yytext);
106 return yyextra->token.baseType;
107 }
108 <PREPROC_SET_COND>[ \t]*")" {
109 //printf("End of PREPROC_SET_COND\n");
110 yy_pop_state(yyscanner);
111 yyextra->token = PreprocessorToken(yytext);
112 return yyextra->token.baseType;
113 }
114
115
116 /* Preprocessor statement: RESET_CONDITION(name) */
117
118 <*>"RESET_CONDITION"[ \t]*"(" {
119 //printf("RESET_CONDITION\n");
120 yy_push_state(PREPROC_RESET_COND, yyscanner);
121 yyextra->token = PreprocessorToken(yytext);
122 return yyextra->token.baseType;
123 }
124 <PREPROC_RESET_COND>{ID} {
125 //printf("preproc reset condition '%s'\n", yytext);
126 yyextra->token = PreprocessorToken(yytext);
127 return yyextra->token.baseType;
128 }
129 <PREPROC_RESET_COND>[ \t]*")" {
130 //printf("End of RESET_CONDITION\n");
131 yy_pop_state(yyscanner);
132 yyextra->token = PreprocessorToken(yytext);
133 return yyextra->token.baseType;
134 }
135
136
137 /* Preprocessor conditional statements:
138
139 USE_CODE_IF(name)
140 ...
141 END_USE_CODE
142
143 and:
144
145 USE_CODE_IF_NOT(name)
146 ...
147 END_USE_CODE
148 */
149
150 <*>"USE_CODE_IF"[ \t]*"(" {
151 //printf("USE_CODE_IF\n");
152 yy_push_state(PREPROC_IF, yyscanner);
153 yyextra->token = PreprocessorToken(yytext);
154 return yyextra->token.baseType;
155 }
156 <*>"USE_CODE_IF_NOT"[ \t]*"(" {
157 //printf("USE_CODE_IF_NOT\n");
158 yy_push_state(PREPROC_IF_NOT, yyscanner);
159 yyextra->token = PreprocessorToken(yytext);
160 return yyextra->token.baseType;
161 }
162 <PREPROC_IF>{ID} {
163 //printf("preproc use code if '%s'\n", yytext);
164 yy_pop_state(yyscanner);
165 yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);
166 //yy_push_state(PREPROC_PRE_BODY_EAT, yyscanner);
167 yyextra->token = PreprocessorToken(yytext);
168 return yyextra->token.baseType;
169 }
170 <PREPROC_IF_NOT>{ID} {
171 //printf("preproc use code if not '%s'\n", yytext);
172 yy_pop_state(yyscanner);
173 yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);
174 //yy_push_state(PREPROC_PRE_BODY_EAT, yyscanner);
175 yyextra->token = PreprocessorToken(yytext);
176 return yyextra->token.baseType;
177 }
178 <PREPROC_PRE_BODY_USE>[ \t]*")" {
179 yy_pop_state(yyscanner);
180 yy_push_state(PREPROC_BODY_USE, yyscanner);
181 yyextra->token = PreprocessorToken(yytext);
182 return yyextra->token.baseType;
183 }
184 <PREPROC_PRE_BODY_EAT>[ \t]*")" {
185 //printf("PREPROCESSOR EAT : \n");
186 yy_pop_state(yyscanner);
187 yy_push_state(PREPROC_BODY_EAT, yyscanner);
188 yyextra->token = PreprocessorToken(yytext);
189 return yyextra->token.baseType;
190 }
191 <*>.*"END_USE_CODE" {
192 //printf("-->END_USE_CODE\n");
193 yy_pop_state(yyscanner);
194 yyextra->token = PreprocessorToken(yytext);
195 return yyextra->token.baseType;
196 }
197 <PREPROC_BODY_EAT>[ \t\r\n]* /* eat up code block filtered out by preprocessor */
198 <PREPROC_BODY_EAT>.* /* eat up code block filtered out by preprocessor */
199
200
201 /* Event Handler Names (only if they occur alone in a document!) */
202
203 ^\s*(init|note|release|controller) {
204 yyextra->token = EventHandlerNameToken(yytext);
205 return yyextra->token.baseType;
206 }
207
208
209 /* Language keywords */
210
211 on {
212 yy_push_state(PREPROC_EVENT_NAME, yyscanner);
213 yyextra->token = KeywordToken(yytext);
214 return yyextra->token.baseType;
215 }
216
217 <PREPROC_EVENT_NAME>[ \t]*{ID} {
218 yy_pop_state(yyscanner);
219 yyextra->token = EventHandlerNameToken(yytext);
220 return yyextra->token.baseType;
221 }
222
223 end {
224 yy_push_state(PREPROC_END_NAME, yyscanner);
225 yyextra->token = KeywordToken(yytext);
226 return yyextra->token.baseType;
227 }
228
229 <PREPROC_END_NAME>[ \t]*{END_ID}? {
230 yy_pop_state(yyscanner);
231 yyextra->token = KeywordToken(yytext);
232 return yyextra->token.baseType;
233 }
234
235 ".or."|".and."|".not." {
236 yyextra->token = KeywordToken(yytext);
237 return yyextra->token.baseType;
238 }
239
240 declare|while|if|or|and|not|else|case|select|to|mod|const|polyphonic|function|call|synchronized {
241 yyextra->token = KeywordToken(yytext);
242 return yyextra->token.baseType;
243 }
244
245
246 /* Variables */
247
248 "$"{ID} {
249 yyextra->token = IntegerVariableToken(yytext);
250 return yyextra->token.baseType;
251 }
252
253 "@"{ID} {
254 yyextra->token = StringVariableToken(yytext);
255 return yyextra->token.baseType;
256 }
257
258 "%"{ID} {
259 yyextra->token = ArrayVariableToken(yytext);
260 return yyextra->token.baseType;
261 }
262
263 {ID} {
264 yyextra->token = IdentifierToken(yytext);
265 return yyextra->token.baseType;
266 }
267
268
269 /* other */
270
271 <*>\n {
272 yyextra->token = NewLineToken();
273 ++yylineno;
274 yycolumn = 0;
275 return yyextra->token.baseType;
276 }
277
278 "{"[^}]*"}" {
279 yyextra->token = CommentToken(yytext);
280 yylineno += countNewLineChars(yytext);
281 return yyextra->token.baseType;
282 }
283
284 <*>\t {
285 yyextra->token = OtherToken(" ");
286 return yyextra->token.baseType;
287 }
288
289 \r+ /* eat up \r */
290
291 <<EOF>> {
292 yyextra->token = EofToken();
293 yyterminate();
294 }
295
296 <*>. {
297 yyextra->token = OtherToken(yytext);
298 return yyextra->token.baseType;
299 }
300
301
302 %%
303
304 namespace LinuxSampler {
305
306 int NkspScanner::processScanner() {
307 return Nksp_lex(scanner);
308 }
309
310 void NkspScanner::createScanner(std::istream* is) {
311 if (scanner) destroyScanner();
312 this->is = is;
313 Nksp_lex_init(&scanner);
314 Nksp_set_extra(this, scanner);
315 }
316
317 void NkspScanner::destroyScanner() {
318 if (!scanner) return;
319 Nksp_lex_destroy(scanner);
320 scanner = NULL;
321 }
322
323 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC