/[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 3561 - (show 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 /*
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
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}|({METRIC}{0,2}{UNIT}?)) {
91 yyextra->token = NumberLiteralToken(yytext);
92 return yyextra->token.baseType;
93 }
94
95 /* there is currently no support for floating point numbers in NKSP yet */
96 /*{DIGIT}+"."{DIGIT}* {
97 yyextra->token = NumberLiteralToken(yytext);
98 return yyextra->token.baseType;
99 }*/
100
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 <PREPROC_END_NAME>[ \t]*{END_ID}? {
237 yy_pop_state(yyscanner);
238 yyextra->token = KeywordToken(yytext);
239 return yyextra->token.baseType;
240 }
241
242 ".or."|".and."|".not." {
243 yyextra->token = KeywordToken(yytext);
244 return yyextra->token.baseType;
245 }
246
247 declare|while|if|or|and|not|else|case|select|to|mod|const|polyphonic|function|call|synchronized {
248 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