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

Annotation of /linuxsampler/trunk/src/scriptvm/scanner.l

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3733 - (hide annotations) (download)
Sat Feb 1 18:11:20 2020 UTC (4 years, 2 months ago) by schoenebeck
File size: 12590 byte(s)
NKSP: Added support for 'patch' variables.

* NKSP language: Added support for 'patch' variable qualifier
  (as new dedicated keyword 'patch').

* NKSP parser: capture locations of 'patch' variable declarations
  in script's source code.

* ScriptVM: Allow patching 'patch' script variables by replacing
  their default assignment expression with a supplied replacement
  variable initialization expression by optional 2nd argument when
  calling loadScript().

* ScriptVM: Allow retrieval of default initialization expressions
  of all 'patch' variables by optional 3rd argument when calling
  loadScript() (i.e. for instrument editors).

* gig engine: Implemented support for loading real-time instrument
  scripts with 'patch' variables bundled with gig instruments.

* Bumped version (2.1.1.svn46).


1 schoenebeck 2581 /*
2 schoenebeck 3259 * Copyright (c) 2014-2017 Christian Schoenebeck and Andreas Persson
3 schoenebeck 2581 *
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 schoenebeck 2888 /* Token scanner for NKSP real-time instrument script language. */
11 schoenebeck 2581
12     %{
13    
14     #include "parser_shared.h"
15     #include <math.h>
16     // reentrant scanner data context
17     #define YY_EXTRA_TYPE ParserContext*
18     // set line number each time a token is recognized
19     #define YY_USER_ACTION \
20     { \
21     yylloc->first_line = yylineno; \
22     yylloc->last_line = yylineno; \
23 schoenebeck 2888 yylloc->first_column = yycolumn; \
24 schoenebeck 3729 yylloc->first_byte = yyextra->nbytes; \
25     yylloc->length_bytes = (int) yyleng; \
26 schoenebeck 2888 yycolumn += yyleng; \
27 schoenebeck 3729 yyextra->nbytes += (int) yyleng; \
28 schoenebeck 2888 yylloc->last_column = yycolumn - 1; \
29 schoenebeck 2581 /*printf("lex: line '%s'\n", yytext);*/ \
30     }
31     // custom (f)lex input for reading from std::istream object
32     #define YY_INPUT(buf,result,max_size) \
33     { \
34     char c = yyextra->is->get(); \
35     if (yyextra->is->eof()) \
36     result = YY_NULL; \
37     else { \
38     buf[0] = c; \
39     result = 1; \
40     } \
41     }
42    
43     static void scanner_error(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* err) {
44 schoenebeck 3729 context->addErr(locp->first_line, locp->last_line, locp->first_column,
45     locp->last_column, locp->first_byte, locp->length_bytes,
46     err);
47 schoenebeck 2581 }
48    
49     static void scanner_warning(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* txt) {
50 schoenebeck 3729 context->addWrn(locp->first_line, locp->last_line, locp->first_column,
51     locp->last_column, locp->first_byte, locp->length_bytes,
52     txt);
53 schoenebeck 2581 }
54    
55     #define SCANNER_ERR(txt) scanner_error(yylloc, yyextra, txt)
56     #define SCANNER_WRN(txt) scanner_warning(yylloc, yyextra, txt)
57    
58 schoenebeck 3054 // shut up warning that 'register' keyword is deprecated as of C++11
59     #if defined(__cplusplus) && __cplusplus >= 201103L
60     # define register
61     #endif
62    
63 schoenebeck 2581 using namespace LinuxSampler;
64    
65 schoenebeck 2888 static int countNewLineChars(const char* txt) {
66     int n = 0;
67     for (int i = 0; txt[i]; ++i)
68     if (txt[i] == '\n') ++n;
69     return n;
70     }
71    
72     static int countCharsPastLastNewLine(const char* txt) {
73 schoenebeck 3054 const int n = (int)strlen(txt);
74 schoenebeck 2888 for (int i = n - 1; i >= 0; --i)
75     if (txt[i] == '\n')
76     return n - i - 1;
77     return n;
78     }
79    
80     #define processLocation() { \
81     const int nl = countNewLineChars(yytext); \
82     yylineno += nl; \
83     if (nl) yycolumn = countCharsPastLastNewLine(yytext); \
84     }
85    
86 schoenebeck 3308 // if compiled for debugging, throw an exception instead of exiting on fatal
87     // lexer errors (so the debugger may pause with the appropriate back trace)
88     #if DEBUG
89     # include <stdexcept>
90     # define YY_FATAL_ERROR(msg) throw std::runtime_error(msg)
91     #endif
92    
93 schoenebeck 2581 %}
94    
95 schoenebeck 2888 /* use Flex's built-in support for line numbers
96     (disabled, because it seems to be unreliable, so we are using our own
97     tracking code in the respective scanner rules below) */
98     /*%option yylineno*/
99 schoenebeck 2581 /* generate a reentrant safe scanner */
100     %option reentrant
101     /* avoid symbol collision with other (i.e. future) scanner symbols */
102     %option prefix="InstrScript_"
103     /* bison-bridge adds an argument yylval to yylex, and bison-locations adds an
104     argument code yylloc for location tracking. */
105     %option bison-bridge
106     %option bison-locations
107     /* yywrap() would be called at EOF, we don't need it */
108     %option noyywrap
109     /* enable functions yy_push_state(), yy_pop_state(), yy_top_state() */
110     %option stack
111    
112     /* inclusive scanner conditions */
113     %s PREPROC_BODY_USE
114     /* exclusive scanner conditions */
115     %x PREPROC_SET_COND PREPROC_RESET_COND PREPROC_IF PREPROC_IF_NOT PREPROC_BODY_EAT PREPROC_PRE_BODY_USE PREPROC_PRE_BODY_EAT
116    
117     DIGIT [0-9]
118 schoenebeck 3561 ID [a-zA-Z][a-zA-Z0-9_]*
119     METRIC (k|h|(da)|d|c|m|u)
120     UNIT (s|(Hz)|B)
121 schoenebeck 2581
122     %%
123    
124     \"[^"]*\" {
125     yylval->sValue = strdup(yytext + 1);
126     yylval->sValue[strlen(yylval->sValue) - 1] = '\0';
127     return STRING;
128     }
129    
130     {DIGIT}+ {
131 schoenebeck 3557 if (sizeof(vmint) < 8)
132     yylval->iValue = atoi(yytext);
133     else
134     yylval->iValue = atoll(yytext);
135 schoenebeck 2581 return INTEGER;
136     }
137    
138 schoenebeck 3573 {DIGIT}+"."{DIGIT}+ {
139     yylval->fValue = atof(yytext);
140     return REAL;
141     }
142    
143 schoenebeck 3561 {DIGIT}+({METRIC}{1,2}|({METRIC}{0,2}{UNIT}?)) {
144     int pos = 0;
145    
146     // parse number portion
147     vmint value = 0;
148     for (; yytext[pos] >= '0' && yytext[pos] <= '9'; ++pos) {
149     value *= 10;
150     value += yytext[pos] - '0';
151     }
152     yylval->iUnitValue.iValue = value;
153    
154     // parse metric prefix portion
155     for (int i = 0; i < 2; ++i, ++pos) {
156     switch (yytext[pos]) {
157     case 'k': yylval->iUnitValue.prefix[i] = VM_KILO; continue;
158     case 'h': yylval->iUnitValue.prefix[i] = VM_HECTO; continue;
159     case 'c': yylval->iUnitValue.prefix[i] = VM_CENTI; continue;
160     case 'm': yylval->iUnitValue.prefix[i] = VM_MILLI; continue;
161     case 'u': yylval->iUnitValue.prefix[i] = VM_MICRO; continue;
162     case 'd':
163     if (yytext[pos+1] == 'a') {
164     yylval->iUnitValue.prefix[i] = VM_DECA;
165     ++pos;
166     } else {
167     yylval->iUnitValue.prefix[i] = VM_DECI;
168     }
169     continue;
170     default:
171     yylval->iUnitValue.prefix[i] = VM_NO_PREFIX;
172 schoenebeck 3573 goto parseIntStdUnit;
173 schoenebeck 3561 }
174     }
175    
176 schoenebeck 3573 parseIntStdUnit:
177 schoenebeck 3561
178     // parse standard measurement unit
179     switch (yytext[pos]) {
180     case 's': yylval->iUnitValue.unit = VM_SECOND; break;
181     case 'H': yylval->iUnitValue.unit = VM_HERTZ; break;
182     case 'B': yylval->iUnitValue.unit = VM_BEL; break;
183     default: yylval->iUnitValue.unit = VM_NO_UNIT; break;
184     }
185    
186     return INTEGER_UNIT;
187     }
188    
189 schoenebeck 3573 {DIGIT}+"."{DIGIT}+({METRIC}{1,2}|({METRIC}{0,2}{UNIT}?)) {
190     int pos = 0;
191 schoenebeck 2581
192 schoenebeck 3573 // parse number portion
193     for (; (yytext[pos] >= '0' && yytext[pos] <= '9') || yytext[pos] == '.'; ++pos) {
194     }
195     {
196     const char tmp = yytext[pos];
197     yytext[pos] = 0; // mark temporary end of string
198     yylval->fUnitValue.fValue = atof(yytext);
199     yytext[pos] = tmp; // restore
200     }
201 schoenebeck 2581
202 schoenebeck 3573 // parse metric prefix portion
203     for (int i = 0; i < 2; ++i, ++pos) {
204     switch (yytext[pos]) {
205     case 'k': yylval->fUnitValue.prefix[i] = VM_KILO; continue;
206     case 'h': yylval->fUnitValue.prefix[i] = VM_HECTO; continue;
207     case 'c': yylval->fUnitValue.prefix[i] = VM_CENTI; continue;
208     case 'm': yylval->fUnitValue.prefix[i] = VM_MILLI; continue;
209     case 'u': yylval->fUnitValue.prefix[i] = VM_MICRO; continue;
210     case 'd':
211     if (yytext[pos+1] == 'a') {
212     yylval->fUnitValue.prefix[i] = VM_DECA;
213     ++pos;
214     } else {
215     yylval->fUnitValue.prefix[i] = VM_DECI;
216     }
217     continue;
218     default:
219     yylval->fUnitValue.prefix[i] = VM_NO_PREFIX;
220     goto parseRealStdUnit;
221     }
222     }
223    
224     parseRealStdUnit:
225    
226     // parse standard measurement unit
227     switch (yytext[pos]) {
228     case 's': yylval->fUnitValue.unit = VM_SECOND; break;
229     case 'H': yylval->fUnitValue.unit = VM_HERTZ; break;
230     case 'B': yylval->fUnitValue.unit = VM_BEL; break;
231     default: yylval->fUnitValue.unit = VM_NO_UNIT; break;
232     }
233    
234     return REAL_UNIT;
235     }
236    
237    
238 schoenebeck 2581 /* Preprocessor statement: SET_CONDITION(name) */
239    
240     <*>"SET_CONDITION"[ \t]*"(" {
241 schoenebeck 2588 //printf("SET_CONDITION\n");
242 schoenebeck 2581 yy_push_state(PREPROC_SET_COND, yyscanner);
243     }
244     <PREPROC_SET_COND>{ID} {
245 schoenebeck 2588 //printf("preproc set condition '%s'\n", yytext);
246 schoenebeck 2581 bool success = yyextra->setPreprocessorCondition(yytext);
247     if (!success) {
248     SCANNER_WRN((String("Preprocessor: Condition '") +
249     yytext + "' is already set.").c_str());
250     }
251     }
252     <PREPROC_SET_COND>[ \t]*")" {
253 schoenebeck 2588 //printf("End of PREPROC_SET_COND\n");
254 schoenebeck 2581 yy_pop_state(yyscanner);
255     }
256    
257    
258     /* Preprocessor statement: RESET_CONDITION(name) */
259    
260     <*>"RESET_CONDITION"[ \t]*"(" {
261 schoenebeck 2588 //printf("RESET_CONDITION\n");
262 schoenebeck 2581 yy_push_state(PREPROC_RESET_COND, yyscanner);
263     }
264     <PREPROC_RESET_COND>{ID} {
265 schoenebeck 2588 //printf("preproc reset condition '%s'\n", yytext);
266 schoenebeck 2581 bool success = yyextra->resetPreprocessorCondition(yytext);
267     if (!success) {
268     SCANNER_ERR((String("Preprocessor: could not reset condition '") +
269     yytext + "' (either not set or a built-in condition).").c_str());
270     }
271     }
272     <PREPROC_RESET_COND>[ \t]*")" {
273 schoenebeck 2588 //printf("End of RESET_CONDITION\n");
274 schoenebeck 2581 yy_pop_state(yyscanner);
275     }
276    
277    
278     /* Preprocessor conditional statements:
279    
280     USE_CODE_IF(name)
281     ...
282     END_USE_CODE
283    
284     and:
285    
286     USE_CODE_IF_NOT(name)
287     ...
288     END_USE_CODE
289     */
290    
291     <*>"USE_CODE_IF"[ \t]*"(" {
292 schoenebeck 3308 //printf("{%s}\n", yytext);
293 schoenebeck 2581 yy_push_state(PREPROC_IF, yyscanner);
294     }
295 schoenebeck 3308 <PREPROC_BODY_EAT>"USE_CODE_IF"[ \t]*"("{ID}")" {
296     //printf("[EAT{%s}\n", yytext);
297     yy_push_state(PREPROC_BODY_EAT, yyscanner);
298     }
299 schoenebeck 2581 <*>"USE_CODE_IF_NOT"[ \t]*"(" {
300 schoenebeck 2588 //printf("USE_CODE_IF_NOT\n");
301 schoenebeck 2581 yy_push_state(PREPROC_IF_NOT, yyscanner);
302     }
303 schoenebeck 3308 <PREPROC_BODY_EAT>"USE_CODE_IF_NOT"[ \t]*"("{ID}")" {
304     //printf("[EAT{%s}\n", yytext);
305     yy_push_state(PREPROC_BODY_EAT, yyscanner);
306     }
307 schoenebeck 2581 <PREPROC_IF>{ID} {
308 schoenebeck 2588 //printf("preproc use code if '%s'\n", yytext);
309 schoenebeck 2581 yy_pop_state(yyscanner);
310     if (yyextra->isPreprocessorConditionSet(yytext))
311     yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);
312     else
313     yy_push_state(PREPROC_PRE_BODY_EAT, yyscanner);
314     }
315     <PREPROC_IF_NOT>{ID} {
316 schoenebeck 2588 //printf("preproc use code if not '%s'\n", yytext);
317 schoenebeck 2581 yy_pop_state(yyscanner);
318     if (!yyextra->isPreprocessorConditionSet(yytext))
319     yy_push_state(PREPROC_PRE_BODY_USE, yyscanner);
320     else
321     yy_push_state(PREPROC_PRE_BODY_EAT, yyscanner);
322     }
323     <PREPROC_PRE_BODY_USE>[ \t]*")" {
324     yy_pop_state(yyscanner);
325     yy_push_state(PREPROC_BODY_USE, yyscanner);
326     }
327     <PREPROC_PRE_BODY_EAT>[ \t]*")" {
328 schoenebeck 3308 //printf("PREPROCESSOR EAT : {%s}\n", yytext);
329 schoenebeck 2581 yy_pop_state(yyscanner);
330     yy_push_state(PREPROC_BODY_EAT, yyscanner);
331     }
332 schoenebeck 3308 <PREPROC_BODY_EAT,PREPROC_BODY_USE>"END_USE_CODE" {
333 schoenebeck 2588 //printf("-->END_USE_CODE\n");
334 schoenebeck 2581 yy_pop_state(yyscanner);
335     }
336 schoenebeck 2888 <PREPROC_BODY_EAT>[ \t\r\n]* { /* eat up code block filtered out by preprocessor */
337 schoenebeck 3308 //printf("PREPROCESSOR EAT2 : {%s}\n", yytext);
338 schoenebeck 2888 processLocation();
339     }
340     <PREPROC_BODY_EAT>.* { /* eat up code block filtered out by preprocessor */
341 schoenebeck 3308 //printf("PREPROCESSOR EAT3 : {%s}\n", yytext);
342 schoenebeck 3285 yyextra->addPreprocessorComment(yylloc->first_line, yylloc->last_line,
343 schoenebeck 3729 yylloc->first_column+1, yylloc->last_column+1,
344     yylloc->first_byte, yylloc->length_bytes);
345 schoenebeck 2888 }
346 schoenebeck 2581
347    
348     /* Language keywords */
349    
350     "on" return ON;
351     "end" return END;
352     "note" return NOTE;
353     "init" return INIT;
354     "declare" return DECLARE;
355     "while" return WHILE;
356     "if" return IF;
357 schoenebeck 2935 ".or." return BITWISE_OR;
358 schoenebeck 2581 "or" return OR;
359     "release" return RELEASE;
360 schoenebeck 2935 ".and." return BITWISE_AND;
361 schoenebeck 2581 "and" return AND;
362 schoenebeck 2935 ".not." return BITWISE_NOT;
363 schoenebeck 2581 "not" return NOT;
364     "else" return ELSE;
365     "controller" return CONTROLLER;
366 schoenebeck 3690 "rpn" return RPN;
367     "nrpn" return NRPN;
368 schoenebeck 2581 "case" return CASE;
369     "select" return SELECT;
370     "to" return TO;
371     "<=" return LE;
372     ">=" return GE;
373 schoenebeck 2585 "const" return CONST_; // note: "CONST" is already defined for C/C++ compilers on Windows by default
374 schoenebeck 2581 "polyphonic" return POLYPHONIC;
375 schoenebeck 3733 "patch" return PATCH;
376 schoenebeck 2581 "mod" return MOD;
377 schoenebeck 2951 "function" return FUNCTION;
378     "call" return CALL;
379 schoenebeck 3260 "synchronized" return SYNCHRONIZED;
380 schoenebeck 2581
381 schoenebeck 3561 [&,!()[\]<>=*+#\/-] {
382 schoenebeck 2935 return *yytext;
383 schoenebeck 2581 }
384    
385 schoenebeck 3573 ("$"|"@"|"%"|"~"|"?"){ID} {
386 schoenebeck 2581 yylval->sValue = strdup(yytext);
387     return VARIABLE;
388     }
389    
390     {ID} {
391     yylval->sValue = strdup(yytext);
392     return IDENTIFIER;
393     }
394    
395     ":=" return ASSIGNMENT;
396    
397     \n+ {
398 schoenebeck 2888 yylineno += countNewLineChars(yytext);
399     yycolumn = 0;
400 schoenebeck 2581 //printf("lex: new line %d\n", yylineno, yytext);
401     //return LF;
402     }
403    
404 schoenebeck 2888 "{"[^}]*"}" { /* eat up comments */
405     processLocation();
406     }
407 schoenebeck 2581
408     [ \t\r]+ /* eat up whitespace */
409    
410 schoenebeck 3259 . {
411     printf( "Unrecognized character: '%s' (line %d, column %d)\n", yytext, yylineno, yycolumn);
412     return UNKNOWN_CHAR;
413     }
414 schoenebeck 2581
415     %%
416    
417     namespace LinuxSampler {
418    
419     void ParserContext::createScanner(std::istream* is) {
420     if (scanner) destroyScanner();
421     this->is = is;
422     yylex_init(&scanner);
423     yyset_extra(this, scanner);
424     }
425    
426     void ParserContext::destroyScanner() {
427     if (!scanner) return;
428     yylex_destroy(scanner);
429     scanner = NULL;
430     }
431    
432     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC