/[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 3562 - (show annotations) (download)
Fri Aug 23 12:51:58 2019 UTC (4 years, 7 months ago) by schoenebeck
File size: 9200 byte(s)
* NKSP script editor API: Added support for detecting standard unit tokens
  and their potential metric prefix token.

1 /*
2 * Copyright (c) 2015-2019 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 METRIC UNIT
71
72 DIGIT [0-9]
73 ID [a-zA-Z][a-zA-Z0-9_]*
74 METRIC (k|h|da|d|c|m|u)
75 UNIT (s|Hz|B)
76 END_ID on|while|if|select|function|synchronized
77
78 %%
79
80 \"[^"]*\" {
81 yyextra->token = StringLiteralToken(yytext);
82 return yyextra->token.baseType;
83 }
84
85 {DIGIT}+ {
86 yyextra->token = NumberLiteralToken(yytext);
87 return yyextra->token.baseType;
88 }
89
90 {DIGIT}+/{METRIC}{1,2} {
91 yy_push_state(METRIC, yyscanner);
92 yyextra->token = NumberLiteralToken(yytext);
93 return yyextra->token.baseType;
94 }
95
96 {DIGIT}+/{UNIT} {
97 yy_push_state(UNIT, yyscanner);
98 yyextra->token = NumberLiteralToken(yytext);
99 return yyextra->token.baseType;
100 }
101
102 <METRIC>{METRIC}{1,2} {
103 yyextra->token = MetrixPrefixToken(yytext);
104 yy_pop_state(yyscanner);
105 return yyextra->token.baseType;
106 }
107
108 <METRIC>{METRIC}{1,2}/{UNIT} {
109 yyextra->token = MetrixPrefixToken(yytext);
110 yy_pop_state(yyscanner);
111 yy_push_state(UNIT, yyscanner);
112 return yyextra->token.baseType;
113 }
114
115 <UNIT>{UNIT} {
116 yyextra->token = StdUnitToken(yytext);
117 yy_pop_state(yyscanner);
118 return yyextra->token.baseType;
119 }
120
121 /* there is currently no support for floating point numbers in NKSP yet */
122 /*{DIGIT}+"."{DIGIT}* {
123 yyextra->token = NumberLiteralToken(yytext);
124 return yyextra->token.baseType;
125 }*/
126
127
128 /* Preprocessor statement: SET_CONDITION(name) */
129
130 <*>"SET_CONDITION"[ \t]*"(" {
131 //printf("SET_CONDITION\n");
132 yy_push_state(PREPROC_SET_COND, yyscanner);
133 yyextra->token = PreprocessorToken(yytext);
134 return yyextra->token.baseType;
135 }
136 <PREPROC_SET_COND>{ID} {
137 //printf("preproc set condition '%s'\n", yytext);
138 yyextra->token = PreprocessorToken(yytext);
139 return yyextra->token.baseType;
140 }
141 <PREPROC_SET_COND>[ \t]*")" {
142 //printf("End of PREPROC_SET_COND\n");
143 yy_pop_state(yyscanner);
144 yyextra->token = PreprocessorToken(yytext);
145 return yyextra->token.baseType;
146 }
147
148
149 /* Preprocessor statement: RESET_CONDITION(name) */
150
151 <*>"RESET_CONDITION"[ \t]*"(" {
152 //printf("RESET_CONDITION\n");
153 yy_push_state(PREPROC_RESET_COND, yyscanner);
154 yyextra->token = PreprocessorToken(yytext);
155 return yyextra->token.baseType;
156 }
157 <PREPROC_RESET_COND>{ID} {
158 //printf("preproc reset condition '%s'\n", yytext);
159 yyextra->token = PreprocessorToken(yytext);
160 return yyextra->token.baseType;
161 }
162 <PREPROC_RESET_COND>[ \t]*")" {
163 //printf("End of RESET_CONDITION\n");
164 yy_pop_state(yyscanner);
165 yyextra->token = PreprocessorToken(yytext);
166 return yyextra->token.baseType;
167 }
168
169
170 /* Preprocessor conditional statements:
171
172 USE_CODE_IF(name)
173 ...
174 END_USE_CODE
175
176 and:
177
178 USE_CODE_IF_NOT(name)
179 ...
180 END_USE_CODE
181 */
182
183 <*>"USE_CODE_IF"[ \t]*"(" {
184 //printf("USE_CODE_IF\n");
185 yy_push_state(PREPROC_IF, yyscanner);
186 yyextra->token = PreprocessorToken(yytext);
187 return yyextra->token.baseType;
188 }
189 <*>"USE_CODE_IF_NOT"[ \t]*"(" {
190 //printf("USE_CODE_IF_NOT\n");
191 yy_push_state(PREPROC_IF_NOT, yyscanner);
192 yyextra->token = PreprocessorToken(yytext);
193 return yyextra->token.baseType;
194 }
195 <PREPROC_IF>{ID} {
196 //printf("preproc use code if '%s'\n", yytext);
197 yy_pop_state(yyscanner);
198 yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);
199 //yy_push_state(PREPROC_PRE_BODY_EAT, yyscanner);
200 yyextra->token = PreprocessorToken(yytext);
201 return yyextra->token.baseType;
202 }
203 <PREPROC_IF_NOT>{ID} {
204 //printf("preproc use code if not '%s'\n", yytext);
205 yy_pop_state(yyscanner);
206 yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);
207 //yy_push_state(PREPROC_PRE_BODY_EAT, yyscanner);
208 yyextra->token = PreprocessorToken(yytext);
209 return yyextra->token.baseType;
210 }
211 <PREPROC_PRE_BODY_USE>[ \t]*")" {
212 yy_pop_state(yyscanner);
213 yy_push_state(PREPROC_BODY_USE, yyscanner);
214 yyextra->token = PreprocessorToken(yytext);
215 return yyextra->token.baseType;
216 }
217 <PREPROC_PRE_BODY_EAT>[ \t]*")" {
218 //printf("PREPROCESSOR EAT : \n");
219 yy_pop_state(yyscanner);
220 yy_push_state(PREPROC_BODY_EAT, yyscanner);
221 yyextra->token = PreprocessorToken(yytext);
222 return yyextra->token.baseType;
223 }
224 <*>.*"END_USE_CODE" {
225 //printf("-->END_USE_CODE\n");
226 yy_pop_state(yyscanner);
227 yyextra->token = PreprocessorToken(yytext);
228 return yyextra->token.baseType;
229 }
230 <PREPROC_BODY_EAT>[ \t\r\n]* /* eat up code block filtered out by preprocessor */
231 <PREPROC_BODY_EAT>.* /* eat up code block filtered out by preprocessor */
232
233
234 /* Event Handler Names (only if they occur alone in a document!) */
235
236 ^\s*(init|note|release|controller) {
237 yyextra->token = EventHandlerNameToken(yytext);
238 return yyextra->token.baseType;
239 }
240
241
242 /* Language keywords */
243
244 on {
245 yy_push_state(PREPROC_EVENT_NAME, yyscanner);
246 yyextra->token = KeywordToken(yytext);
247 return yyextra->token.baseType;
248 }
249
250 <PREPROC_EVENT_NAME>[ \t]*{ID} {
251 yy_pop_state(yyscanner);
252 yyextra->token = EventHandlerNameToken(yytext);
253 return yyextra->token.baseType;
254 }
255
256 end {
257 yy_push_state(PREPROC_END_NAME, yyscanner);
258 yyextra->token = KeywordToken(yytext);
259 return yyextra->token.baseType;
260 }
261
262 <PREPROC_END_NAME>[ \t]*{END_ID}? {
263 yy_pop_state(yyscanner);
264 yyextra->token = KeywordToken(yytext);
265 return yyextra->token.baseType;
266 }
267
268 ".or."|".and."|".not." {
269 yyextra->token = KeywordToken(yytext);
270 return yyextra->token.baseType;
271 }
272
273 declare|while|if|or|and|not|else|case|select|to|mod|const|polyphonic|function|call|synchronized {
274 yyextra->token = KeywordToken(yytext);
275 return yyextra->token.baseType;
276 }
277
278
279 /* Variables */
280
281 "$"{ID} {
282 yyextra->token = IntegerVariableToken(yytext);
283 return yyextra->token.baseType;
284 }
285
286 "@"{ID} {
287 yyextra->token = StringVariableToken(yytext);
288 return yyextra->token.baseType;
289 }
290
291 "%"{ID} {
292 yyextra->token = ArrayVariableToken(yytext);
293 return yyextra->token.baseType;
294 }
295
296 {ID} {
297 yyextra->token = IdentifierToken(yytext);
298 return yyextra->token.baseType;
299 }
300
301
302 /* other */
303
304 <*>\n {
305 yyextra->token = NewLineToken();
306 ++yylineno;
307 yycolumn = 0;
308 return yyextra->token.baseType;
309 }
310
311 "{"[^}]*"}" {
312 yyextra->token = CommentToken(yytext);
313 yylineno += countNewLineChars(yytext);
314 return yyextra->token.baseType;
315 }
316
317 <*>\t {
318 yyextra->token = OtherToken(" ");
319 return yyextra->token.baseType;
320 }
321
322 \r+ /* eat up \r */
323
324 <<EOF>> {
325 yyextra->token = EofToken();
326 yyterminate();
327 }
328
329 <*>. {
330 yyextra->token = OtherToken(yytext);
331 return yyextra->token.baseType;
332 }
333
334
335 %%
336
337 namespace LinuxSampler {
338
339 int NkspScanner::processScanner() {
340 return Nksp_lex(scanner);
341 }
342
343 void NkspScanner::createScanner(std::istream* is) {
344 if (scanner) destroyScanner();
345 this->is = is;
346 Nksp_lex_init(&scanner);
347 Nksp_set_extra(this, scanner);
348 }
349
350 void NkspScanner::destroyScanner() {
351 if (!scanner) return;
352 Nksp_lex_destroy(scanner);
353 scanner = NULL;
354 }
355
356 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC