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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3561 - (hide annotations) (download)
Fri Aug 23 11:44:00 2019 UTC (4 years, 8 months ago) by schoenebeck
File size: 8587 byte(s)
NKSP: Added standard units support for numbers and final "!" operator:

* NKSP strictness: Variable names, function names and preprocessor condition
  names must start with a regular character (a-z or A-Z); starting them with
  a digit or underscore is no longer allowed.

* NKSP parser fix: equal comparison operator "=" and not equal comparison
  operator "#" must only accept integer operands.

* NKSP language: Implemented support for standard units like Hertz, seconds,
  Bel including support for metric unit prefixes; so one can now e.g.
  conveniently use numbers in scripts like "5us" meaning "5 microseconds",
  or e.g. "12kHz" meaning "12 kilo Hertz", or e.g. "-14mdB" meaning
  "minus 14 Millidecibel", or e.g. "28c" meaning "28 cents" (for tuning).

* NKSP language: Introduced "final" operator "!" which is specifically
  intended for synthesis parameter values to denote that the synthesis
  parameter value is intended to be the "final" value for that synthesis
  parameter that should explicitly be used by the engine and thus causing
  the sampler engine to ignore all other modulation sources for the same
  synthesis parameter (like e.g. LFO, EG); by simply prefixing a value,
  variable or formula with this new "!" operator the expression is marked as
  being "final".

* Bumped version (2.1.1.svn4).

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

  ViewVC Help
Powered by ViewVC