/[svn]/linuxsampler/trunk/src/scriptvm/parser.y
ViewVC logotype

Contents of /linuxsampler/trunk/src/scriptvm/parser.y

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3257 - (show annotations) (download)
Tue May 30 17:20:02 2017 UTC (6 years, 10 months ago) by schoenebeck
File size: 38230 byte(s)
* NKSP language: Added support for user declared const array variables.
* NKSP language: Raise parser warning if array variable is accessed with
  an index that exceeds the array's size.
* Bumped version (2.0.0.svn58).

1 /*
2 * Copyright (c) 2014-2017 Christian Schoenebeck and Andreas Persson
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 /* Parser for NKSP real-time instrument script language. */
11
12 %{
13 #define YYERROR_VERBOSE 1
14 #include "parser_shared.h"
15 #include <string>
16 #include <map>
17 using namespace LinuxSampler;
18
19 void InstrScript_error(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* err);
20 void InstrScript_warning(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* txt);
21 int InstrScript_tnamerr(char* yyres, const char* yystr);
22 int InstrScript_lex(YYSTYPE* lvalp, YYLTYPE* llocp, void* scanner);
23 #define scanner context->scanner
24 #define PARSE_ERR(loc,txt) yyerror(&loc, context, txt)
25 #define PARSE_WRN(loc,txt) InstrScript_warning(&loc, context, txt)
26 #define yytnamerr(res,str) InstrScript_tnamerr(res, str)
27 %}
28
29 // generate reentrant safe parser
30 %pure-parser
31 %parse-param { LinuxSampler::ParserContext* context }
32 %lex-param { void* scanner }
33 // avoid symbol collision with other (i.e. future) auto generated (f)lex scanners
34 // (NOTE: "=" is deprecated here with Bison 3.x, however removing it would cause an error with Bison 2.x)
35 %name-prefix="InstrScript_"
36 %locations
37 %defines
38 %error-verbose
39
40 %token <iValue> INTEGER "integer literal"
41 %token <sValue> STRING "string literal"
42 %token <sValue> IDENTIFIER "function name"
43 %token <sValue> VARIABLE "variable name"
44 %token ON "keyword 'on'"
45 %token END "keyword 'end'"
46 %token INIT "keyword 'init'"
47 %token NOTE "keyword 'note'"
48 %token RELEASE "keyword 'release'"
49 %token CONTROLLER "keyword 'controller'"
50 %token DECLARE "keyword 'declare'"
51 %token ASSIGNMENT "operator ':='"
52 %token CONST_ "keyword 'const'"
53 %token POLYPHONIC "keyword 'polyphonic'"
54 %token WHILE "keyword 'while'"
55 %token IF "keyword 'if'"
56 %token ELSE "keyword 'else'"
57 %token SELECT "keyword 'select'"
58 %token CASE "keyword 'case'"
59 %token TO "keyword 'to'"
60 %token OR "operator 'or'"
61 %token AND "operator 'and'"
62 %token NOT "operator 'not'"
63 %token BITWISE_OR "bitwise operator '.or.'"
64 %token BITWISE_AND "bitwise operator '.and.'"
65 %token BITWISE_NOT "bitwise operator '.not.'"
66 %token FUNCTION "keyword 'function'"
67 %token CALL "keyword 'call'"
68 %token MOD "operator 'mod'"
69 %token LE "operator '<='"
70 %token GE "operator '>='"
71 %token END_OF_FILE 0 "end of file"
72
73 %type <nEventHandlers> script sections
74 %type <nEventHandler> section eventhandler
75 %type <nStatements> statements opt_statements userfunctioncall
76 %type <nStatement> statement assignment
77 %type <nFunctionCall> functioncall
78 %type <nArgs> args
79 %type <nExpression> arg expr logical_or_expr logical_and_expr bitwise_or_expr bitwise_and_expr rel_expr add_expr mul_expr unary_expr concat_expr
80 %type <nCaseBranch> caseclause
81 %type <nCaseBranches> caseclauses
82
83 %start script
84
85 %%
86
87 script:
88 sections {
89 $$ = context->handlers = $1;
90 }
91
92 sections:
93 section {
94 $$ = new EventHandlers();
95 if ($1) $$->add($1);
96 }
97 | sections section {
98 $$ = $1;
99 if ($2) $$->add($2);
100 }
101
102 section:
103 function_declaration {
104 $$ = EventHandlerRef();
105 }
106 | eventhandler {
107 $$ = $1;
108 }
109
110 eventhandler:
111 ON NOTE opt_statements END ON {
112 if (context->onNote)
113 PARSE_ERR(@2, "Redeclaration of 'note' event handler.");
114 context->onNote = new OnNote($3);
115 $$ = context->onNote;
116 }
117 | ON INIT opt_statements END ON {
118 if (context->onInit)
119 PARSE_ERR(@2, "Redeclaration of 'init' event handler.");
120 context->onInit = new OnInit($3);
121 $$ = context->onInit;
122 }
123 | ON RELEASE opt_statements END ON {
124 if (context->onRelease)
125 PARSE_ERR(@2, "Redeclaration of 'release' event handler.");
126 context->onRelease = new OnRelease($3);
127 $$ = context->onRelease;
128 }
129 | ON CONTROLLER opt_statements END ON {
130 if (context->onController)
131 PARSE_ERR(@2, "Redeclaration of 'controller' event handler.");
132 context->onController = new OnController($3);
133 $$ = context->onController;
134 }
135
136 function_declaration:
137 FUNCTION IDENTIFIER opt_statements END FUNCTION {
138 const char* name = $2;
139 if (context->functionProvider->functionByName(name)) {
140 PARSE_ERR(@2, (String("There is already a built-in function with name '") + name + "'.").c_str());
141 } else if (context->userFunctionByName(name)) {
142 PARSE_ERR(@2, (String("There is already a user defined function with name '") + name + "'.").c_str());
143 } else {
144 context->userFnTable[name] = $3;
145 }
146 }
147
148 opt_statements:
149 /* epsilon (empty argument) */ {
150 $$ = new Statements();
151 }
152 | statements {
153 $$ = $1;
154 }
155
156 statements:
157 statement {
158 $$ = new Statements();
159 if ($1) {
160 if (!isNoOperation($1)) $$->add($1); // filter out NoOperation statements
161 } else
162 PARSE_WRN(@1, "Not a statement.");
163 }
164 | statements statement {
165 $$ = $1;
166 if ($2) {
167 if (!isNoOperation($2)) $$->add($2); // filter out NoOperation statements
168 } else
169 PARSE_WRN(@2, "Not a statement.");
170 }
171
172 statement:
173 functioncall {
174 $$ = $1;
175 }
176 | userfunctioncall {
177 $$ = $1;
178 }
179 | DECLARE VARIABLE {
180 const char* name = $2;
181 //printf("declared var '%s'\n", name);
182 if (context->variableByName(name))
183 PARSE_ERR(@2, (String("Redeclaration of variable '") + name + "'.").c_str());
184 if (name[0] == '@') {
185 context->vartable[name] = new StringVariable(context);
186 $$ = new NoOperation;
187 } else {
188 context->vartable[name] = new IntVariable(context);
189 $$ = new NoOperation;
190 }
191 }
192 | DECLARE POLYPHONIC VARIABLE {
193 const char* name = $3;
194 //printf("declared polyphonic var '%s'\n", name);
195 if (context->variableByName(name))
196 PARSE_ERR(@3, (String("Redeclaration of variable '") + name + "'.").c_str());
197 if (name[0] != '$') {
198 PARSE_ERR(@3, "Polyphonic variables may only be declared as integers.");
199 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
200 } else {
201 context->vartable[name] = new PolyphonicIntVariable(context);
202 $$ = new NoOperation;
203 }
204 }
205 | DECLARE VARIABLE ASSIGNMENT expr {
206 const char* name = $2;
207 //printf("declared assign var '%s'\n", name);
208 if (context->variableByName(name))
209 PARSE_ERR(@2, (String("Redeclaration of variable '") + name + "'.").c_str());
210 if ($4->exprType() == STRING_EXPR) {
211 if (name[0] == '$')
212 PARSE_WRN(@2, (String("Variable '") + name + "' declared as integer, string expression assigned though.").c_str());
213 StringExprRef expr = $4;
214 if (expr->isConstExpr()) {
215 const String s = expr->evalStr();
216 StringVariableRef var = new StringVariable(context);
217 context->vartable[name] = var;
218 $$ = new Assignment(var, new StringLiteral(s));
219 } else {
220 StringVariableRef var = new StringVariable(context);
221 context->vartable[name] = var;
222 $$ = new Assignment(var, expr);
223 }
224 } else {
225 if (name[0] == '@')
226 PARSE_WRN(@2, (String("Variable '") + name + "' declared as string, integer expression assigned though.").c_str());
227 IntExprRef expr = $4;
228 if (expr->isConstExpr()) {
229 const int i = expr->evalInt();
230 IntVariableRef var = new IntVariable(context);
231 context->vartable[name] = var;
232 $$ = new Assignment(var, new IntLiteral(i));
233 } else {
234 IntVariableRef var = new IntVariable(context);
235 context->vartable[name] = var;
236 $$ = new Assignment(var, expr);
237 }
238 }
239 }
240 | DECLARE VARIABLE '[' expr ']' {
241 //printf("declare array without args\n");
242 const char* name = $2;
243 if (!$4->isConstExpr()) {
244 PARSE_ERR(@4, (String("Array variable '") + name + "' must be declared with constant array size.").c_str());
245 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
246 } else if ($4->exprType() != INT_EXPR) {
247 PARSE_ERR(@4, (String("Size of array variable '") + name + "' declared with non integer expression.").c_str());
248 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
249 } else if (context->variableByName(name)) {
250 PARSE_ERR(@2, (String("Redeclaration of variable '") + name + "'.").c_str());
251 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
252 } else {
253 IntExprRef expr = $4;
254 int size = expr->evalInt();
255 if (size <= 0) {
256 PARSE_ERR(@4, (String("Array variable '") + name + "' declared with array size " + ToString(size) + ".").c_str());
257 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
258 } else {
259 context->vartable[name] = new IntArrayVariable(context, size);
260 $$ = new NoOperation;
261 }
262 }
263 }
264 | DECLARE VARIABLE '[' expr ']' ASSIGNMENT '(' args ')' {
265 const char* name = $2;
266 if (!$4->isConstExpr()) {
267 PARSE_ERR(@4, (String("Array variable '") + name + "' must be declared with constant array size.").c_str());
268 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
269 } else if ($4->exprType() != INT_EXPR) {
270 PARSE_ERR(@4, (String("Size of array variable '") + name + "' declared with non integer expression.").c_str());
271 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
272 } else if (context->variableByName(name)) {
273 PARSE_ERR(@2, (String("Redeclaration of variable '") + name + "'.").c_str());
274 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
275 } else {
276 IntExprRef sizeExpr = $4;
277 ArgsRef args = $8;
278 int size = sizeExpr->evalInt();
279 if (size <= 0) {
280 PARSE_ERR(@4, (String("Array variable '") + name + "' must be declared with positive array size.").c_str());
281 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
282 } else if (args->argsCount() > size) {
283 PARSE_ERR(@8, (String("Array variable '") + name +
284 "' was declared with size " + ToString(size) +
285 " but " + ToString(args->argsCount()) +
286 " values were assigned." ).c_str());
287 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
288 } else {
289 bool argsOK = true;
290 for (int i = 0; i < args->argsCount(); ++i) {
291 if (args->arg(i)->exprType() != INT_EXPR) {
292 PARSE_ERR(
293 @8,
294 (String("Array variable '") + name +
295 "' declared with invalid assignment values. Assigned element " +
296 ToString(i+1) + " is not an integer expression.").c_str()
297 );
298 argsOK = false;
299 break;
300 }
301 }
302 if (argsOK) {
303 context->vartable[name] = new IntArrayVariable(context, size, args);
304 $$ = new NoOperation;
305 } else
306 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
307 }
308 }
309 }
310 | DECLARE CONST_ VARIABLE '[' expr ']' ASSIGNMENT '(' args ')' {
311 const char* name = $3;
312 if (!$5->isConstExpr()) {
313 PARSE_ERR(@5, (String("Array variable '") + name + "' must be declared with constant array size.").c_str());
314 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
315 } else if ($5->exprType() != INT_EXPR) {
316 PARSE_ERR(@5, (String("Size of array variable '") + name + "' declared with non integer expression.").c_str());
317 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
318 } else if (context->variableByName(name)) {
319 PARSE_ERR(@3, (String("Redeclaration of variable '") + name + "'.").c_str());
320 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
321 } else {
322 IntExprRef sizeExpr = $5;
323 ArgsRef args = $9;
324 int size = sizeExpr->evalInt();
325 if (size <= 0) {
326 PARSE_ERR(@5, (String("Array variable '") + name + "' must be declared with positive array size.").c_str());
327 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
328 } else if (args->argsCount() > size) {
329 PARSE_ERR(@9, (String("Array variable '") + name +
330 "' was declared with size " + ToString(size) +
331 " but " + ToString(args->argsCount()) +
332 " values were assigned." ).c_str());
333 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
334 } else {
335 bool argsOK = true;
336 for (int i = 0; i < args->argsCount(); ++i) {
337 if (args->arg(i)->exprType() != INT_EXPR) {
338 PARSE_ERR(
339 @9,
340 (String("Array variable '") + name +
341 "' declared with invalid assignment values. Assigned element " +
342 ToString(i+1) + " is not an integer expression.").c_str()
343 );
344 argsOK = false;
345 break;
346 }
347 if (!args->arg(i)->isConstExpr()) {
348 PARSE_ERR(
349 @9,
350 (String("const array variable '") + name +
351 "' must be defined with const values. Assigned element " +
352 ToString(i+1) + " is not a const expression though.").c_str()
353 );
354 argsOK = false;
355 break;
356 }
357 }
358 if (argsOK) {
359 context->vartable[name] = new IntArrayVariable(context, size, args, true);
360 $$ = new NoOperation;
361 } else
362 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
363 }
364 }
365 }
366 | DECLARE CONST_ VARIABLE ASSIGNMENT expr {
367 const char* name = $3;
368 if ($5->exprType() == STRING_EXPR) {
369 if (name[0] == '$')
370 PARSE_WRN(@5, "Variable declared as integer, string expression assigned though.");
371 String s;
372 StringExprRef expr = $5;
373 if (expr->isConstExpr())
374 s = expr->evalStr();
375 else
376 PARSE_ERR(@5, (String("Assignment to const string variable '") + name + "' requires const expression.").c_str());
377 ConstStringVariableRef var = new ConstStringVariable(context, s);
378 context->vartable[name] = var;
379 //$$ = new Assignment(var, new StringLiteral(s));
380 $$ = new NoOperation();
381 } else {
382 if (name[0] == '@')
383 PARSE_WRN(@5, "Variable declared as string, integer expression assigned though.");
384 int i = 0;
385 IntExprRef expr = $5;
386 if (expr->isConstExpr())
387 i = expr->evalInt();
388 else
389 PARSE_ERR(@5, (String("Assignment to const integer variable '") + name + "' requires const expression.").c_str());
390 ConstIntVariableRef var = new ConstIntVariable(i);
391 context->vartable[name] = var;
392 //$$ = new Assignment(var, new IntLiteral(i));
393 $$ = new NoOperation();
394 }
395 }
396 | assignment {
397 $$ = $1;
398 }
399 | WHILE '(' expr ')' opt_statements END WHILE {
400 if ($3->exprType() == INT_EXPR) {
401 $$ = new While($3, $5);
402 } else {
403 PARSE_ERR(@3, "Condition for 'while' loops must be integer expression.");
404 $$ = new While(new IntLiteral(0), $5);
405 }
406 }
407 | IF '(' expr ')' opt_statements ELSE opt_statements END IF {
408 $$ = new If($3, $5, $7);
409 }
410 | IF '(' expr ')' opt_statements END IF {
411 $$ = new If($3, $5);
412 }
413 | SELECT expr caseclauses END SELECT {
414 if ($2->exprType() == INT_EXPR) {
415 $$ = new SelectCase($2, $3);
416 } else {
417 PARSE_ERR(@2, "Statement 'select' can only by applied to integer expressions.");
418 $$ = new SelectCase(new IntLiteral(0), $3);
419 }
420 }
421
422 caseclauses:
423 caseclause {
424 $$ = CaseBranches();
425 $$.push_back($1);
426 }
427 | caseclauses caseclause {
428 $$ = $1;
429 $$.push_back($2);
430 }
431
432 caseclause:
433 CASE INTEGER opt_statements {
434 $$ = CaseBranch();
435 $$.from = new IntLiteral($2);
436 $$.statements = $3;
437 }
438 | CASE INTEGER TO INTEGER opt_statements {
439 $$ = CaseBranch();
440 $$.from = new IntLiteral($2);
441 $$.to = new IntLiteral($4);
442 $$.statements = $5;
443 }
444
445 userfunctioncall:
446 CALL IDENTIFIER {
447 const char* name = $2;
448 StatementsRef fn = context->userFunctionByName(name);
449 if (context->functionProvider->functionByName(name)) {
450 PARSE_ERR(@1, (String("Keyword 'call' must only be used for user defined functions, not for any built-in function like '") + name + "'.").c_str());
451 $$ = StatementsRef();
452 } else if (!fn) {
453 PARSE_ERR(@2, (String("No user defined function with name '") + name + "'.").c_str());
454 $$ = StatementsRef();
455 } else {
456 $$ = fn;
457 }
458 }
459
460 functioncall:
461 IDENTIFIER '(' args ')' {
462 const char* name = $1;
463 //printf("function call of '%s' with args\n", name);
464 ArgsRef args = $3;
465 VMFunction* fn = context->functionProvider->functionByName(name);
466 if (context->userFunctionByName(name)) {
467 PARSE_ERR(@1, (String("Missing 'call' keyword before user defined function name '") + name + "'.").c_str());
468 $$ = new FunctionCall(name, args, NULL);
469 } else if (!fn) {
470 PARSE_ERR(@1, (String("No built-in function with name '") + name + "'.").c_str());
471 $$ = new FunctionCall(name, args, NULL);
472 } else if (args->argsCount() < fn->minRequiredArgs()) {
473 PARSE_ERR(@3, (String("Built-in function '") + name + "' requires at least " + ToString(fn->minRequiredArgs()) + " arguments.").c_str());
474 $$ = new FunctionCall(name, args, NULL);
475 } else if (args->argsCount() > fn->maxAllowedArgs()) {
476 PARSE_ERR(@3, (String("Built-in function '") + name + "' accepts max. " + ToString(fn->maxAllowedArgs()) + " arguments.").c_str());
477 $$ = new FunctionCall(name, args, NULL);
478 } else {
479 bool argsOK = true;
480 for (int i = 0; i < args->argsCount(); ++i) {
481 if (args->arg(i)->exprType() != fn->argType(i) && !fn->acceptsArgType(i, args->arg(i)->exprType())) {
482 PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' expects " + typeStr(fn->argType(i)) + " type, but type " + typeStr(args->arg(i)->exprType()) + " was given instead.").c_str());
483 argsOK = false;
484 break;
485 } else if (fn->modifiesArg(i) && !args->arg(i)->isModifyable()) {
486 PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' expects an assignable variable.").c_str());
487 argsOK = false;
488 break;
489 }
490 }
491 $$ = new FunctionCall(name, args, argsOK ? fn : NULL);
492 }
493 }
494 | IDENTIFIER '(' ')' {
495 const char* name = $1;
496 //printf("function call of '%s' (with empty args)\n", name);
497 ArgsRef args = new Args;
498 VMFunction* fn = context->functionProvider->functionByName(name);
499 if (context->userFunctionByName(name)) {
500 PARSE_ERR(@1, (String("Missing 'call' keyword before user defined function name '") + name + "'.").c_str());
501 $$ = new FunctionCall(name, args, NULL);
502 } else if (!fn) {
503 PARSE_ERR(@1, (String("No built-in function with name '") + name + "'.").c_str());
504 $$ = new FunctionCall(name, args, NULL);
505 } else if (fn->minRequiredArgs() > 0) {
506 PARSE_ERR(@3, (String("Built-in function '") + name + "' requires at least " + ToString(fn->minRequiredArgs()) + " arguments.").c_str());
507 $$ = new FunctionCall(name, args, NULL);
508 } else {
509 $$ = new FunctionCall(name, args, fn);
510 }
511 }
512 | IDENTIFIER {
513 const char* name = $1;
514 //printf("function call of '%s' (without args)\n", name);
515 ArgsRef args = new Args;
516 VMFunction* fn = context->functionProvider->functionByName(name);
517 if (context->userFunctionByName(name)) {
518 PARSE_ERR(@1, (String("Missing 'call' keyword before user defined function name '") + name + "'.").c_str());
519 $$ = new FunctionCall(name, args, NULL);
520 } else if (!fn) {
521 PARSE_ERR(@1, (String("No built-in function with name '") + name + "'.").c_str());
522 $$ = new FunctionCall(name, args, NULL);
523 } else if (fn->minRequiredArgs() > 0) {
524 PARSE_ERR(@1, (String("Built-in function '") + name + "' requires at least " + ToString(fn->minRequiredArgs()) + " arguments.").c_str());
525 $$ = new FunctionCall(name, args, NULL);
526 } else {
527 $$ = new FunctionCall(name, args, fn);
528 }
529 }
530
531 args:
532 arg {
533 $$ = new Args();
534 $$->add($1);
535 }
536 | args ',' arg {
537 $$ = $1;
538 $$->add($3);
539 }
540
541 arg:
542 expr
543
544 assignment:
545 VARIABLE ASSIGNMENT expr {
546 //printf("variable lookup with name '%s' as assignment expr\n", $1);
547 const char* name = $1;
548 VariableRef var = context->variableByName(name);
549 if (!var)
550 PARSE_ERR(@1, (String("Variable assignment: No variable declared with name '") + name + "'.").c_str());
551 else if (var->isConstExpr())
552 PARSE_ERR(@2, (String("Variable assignment: Cannot modify const variable '") + name + "'.").c_str());
553 else if (!var->isAssignable())
554 PARSE_ERR(@2, (String("Variable assignment: Variable '") + name + "' is not assignable.").c_str());
555 else if (var->exprType() != $3->exprType())
556 PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' is of type " + typeStr(var->exprType()) + ", assignment is of type " + typeStr($3->exprType()) + " though.").c_str());
557 $$ = new Assignment(var, $3);
558 }
559 | VARIABLE '[' expr ']' ASSIGNMENT expr {
560 const char* name = $1;
561 VariableRef var = context->variableByName(name);
562 if (!var)
563 PARSE_ERR(@1, (String("No variable declared with name '") + name + "'.").c_str());
564 else if (var->exprType() != INT_ARR_EXPR)
565 PARSE_ERR(@2, (String("Variable '") + name + "' is not an array variable.").c_str());
566 else if (var->isConstExpr())
567 PARSE_ERR(@5, (String("Variable assignment: Cannot modify const array variable '") + name + "'.").c_str());
568 else if (!var->isAssignable())
569 PARSE_ERR(@5, (String("Variable assignment: Array variable '") + name + "' is not assignable.").c_str());
570 else if ($3->exprType() != INT_EXPR)
571 PARSE_ERR(@3, (String("Array variable '") + name + "' accessed with non integer expression.").c_str());
572 else if ($6->exprType() != INT_EXPR)
573 PARSE_ERR(@5, (String("Value assigned to array variable '") + name + "' must be an integer expression.").c_str());
574 else if ($3->isConstExpr() && $3->asInt()->evalInt() >= ((IntArrayVariableRef)var)->arraySize())
575 PARSE_WRN(@3, (String("Index ") + ToString($3->asInt()->evalInt()) +
576 " exceeds size of array variable '" + name +
577 "' which was declared with size " +
578 ToString(((IntArrayVariableRef)var)->arraySize()) + ".").c_str());
579 IntArrayElementRef element = new IntArrayElement(var, $3);
580 $$ = new Assignment(element, $6);
581 }
582
583 unary_expr:
584 INTEGER {
585 $$ = new IntLiteral($1);
586 }
587 | STRING {
588 $$ = new StringLiteral($1);
589 }
590 | VARIABLE {
591 //printf("variable lookup with name '%s' as unary expr\n", $1);
592 VariableRef var = context->variableByName($1);
593 if (var)
594 $$ = var;
595 else {
596 PARSE_ERR(@1, (String("No variable declared with name '") + $1 + "'.").c_str());
597 $$ = new IntLiteral(0);
598 }
599 }
600 | VARIABLE '[' expr ']' {
601 const char* name = $1;
602 VariableRef var = context->variableByName(name);
603 if (!var) {
604 PARSE_ERR(@1, (String("No variable declared with name '") + name + "'.").c_str());
605 $$ = new IntLiteral(0);
606 } else if (var->exprType() != INT_ARR_EXPR) {
607 PARSE_ERR(@2, (String("Variable '") + name + "' is not an array variable.").c_str());
608 $$ = new IntLiteral(0);
609 } else if ($3->exprType() != INT_EXPR) {
610 PARSE_ERR(@3, (String("Array variable '") + name + "' accessed with non integer expression.").c_str());
611 $$ = new IntLiteral(0);
612 } else {
613 if ($3->isConstExpr() && $3->asInt()->evalInt() >= ((IntArrayVariableRef)var)->arraySize())
614 PARSE_WRN(@3, (String("Index ") + ToString($3->asInt()->evalInt()) +
615 " exceeds size of array variable '" + name +
616 "' which was declared with size " +
617 ToString(((IntArrayVariableRef)var)->arraySize()) + ".").c_str());
618 $$ = new IntArrayElement(var, $3);
619 }
620 }
621 | '(' expr ')' {
622 $$ = $2;
623 }
624 | functioncall {
625 $$ = $1;
626 }
627 | '-' unary_expr {
628 $$ = new Neg($2);
629 }
630 | BITWISE_NOT unary_expr {
631 if ($2->exprType() != INT_EXPR) {
632 PARSE_ERR(@2, (String("Right operand of bitwise operator '.not.' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str());
633 $$ = new IntLiteral(0);
634 } else {
635 $$ = new BitwiseNot($2);
636 }
637 }
638 | NOT unary_expr {
639 if ($2->exprType() != INT_EXPR) {
640 PARSE_ERR(@2, (String("Right operand of operator 'not' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str());
641 $$ = new IntLiteral(0);
642 } else {
643 $$ = new Not($2);
644 }
645 }
646
647 expr:
648 concat_expr
649
650 concat_expr:
651 logical_or_expr
652 | concat_expr '&' logical_or_expr {
653 ExpressionRef lhs = $1;
654 ExpressionRef rhs = $3;
655 if (lhs->isConstExpr() && rhs->isConstExpr()) {
656 $$ = new StringLiteral(
657 lhs->evalCastToStr() + rhs->evalCastToStr()
658 );
659 } else {
660 $$ = new ConcatString(lhs, rhs);
661 }
662 }
663
664 logical_or_expr:
665 logical_and_expr
666 | logical_or_expr OR logical_and_expr {
667 ExpressionRef lhs = $1;
668 ExpressionRef rhs = $3;
669 if (lhs->exprType() != INT_EXPR) {
670 PARSE_ERR(@1, (String("Left operand of operator 'or' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
671 $$ = new IntLiteral(0);
672 } else if (rhs->exprType() != INT_EXPR) {
673 PARSE_ERR(@3, (String("Right operand of operator 'or' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
674 $$ = new IntLiteral(0);
675 } else {
676 $$ = new Or(lhs, rhs);
677 }
678 }
679
680 logical_and_expr:
681 bitwise_or_expr {
682 $$ = $1;
683 }
684 | logical_and_expr AND bitwise_or_expr {
685 ExpressionRef lhs = $1;
686 ExpressionRef rhs = $3;
687 if (lhs->exprType() != INT_EXPR) {
688 PARSE_ERR(@1, (String("Left operand of operator 'and' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
689 $$ = new IntLiteral(0);
690 } else if (rhs->exprType() != INT_EXPR) {
691 PARSE_ERR(@3, (String("Right operand of operator 'and' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
692 $$ = new IntLiteral(0);
693 } else {
694 $$ = new And(lhs, rhs);
695 }
696 }
697
698 bitwise_or_expr:
699 bitwise_and_expr
700 | bitwise_or_expr BITWISE_OR bitwise_and_expr {
701 ExpressionRef lhs = $1;
702 ExpressionRef rhs = $3;
703 if (lhs->exprType() != INT_EXPR) {
704 PARSE_ERR(@1, (String("Left operand of bitwise operator '.or.' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
705 $$ = new IntLiteral(0);
706 } else if (rhs->exprType() != INT_EXPR) {
707 PARSE_ERR(@3, (String("Right operand of bitwise operator '.or.' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
708 $$ = new IntLiteral(0);
709 } else {
710 $$ = new BitwiseOr(lhs, rhs);
711 }
712 }
713
714 bitwise_and_expr:
715 rel_expr {
716 $$ = $1;
717 }
718 | bitwise_and_expr BITWISE_AND rel_expr {
719 ExpressionRef lhs = $1;
720 ExpressionRef rhs = $3;
721 if (lhs->exprType() != INT_EXPR) {
722 PARSE_ERR(@1, (String("Left operand of bitwise operator '.and.' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
723 $$ = new IntLiteral(0);
724 } else if (rhs->exprType() != INT_EXPR) {
725 PARSE_ERR(@3, (String("Right operand of bitwise operator '.and.' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
726 $$ = new IntLiteral(0);
727 } else {
728 $$ = new BitwiseAnd(lhs, rhs);
729 }
730 }
731
732 rel_expr:
733 add_expr
734 | rel_expr '<' add_expr {
735 ExpressionRef lhs = $1;
736 ExpressionRef rhs = $3;
737 if (lhs->exprType() != INT_EXPR) {
738 PARSE_ERR(@1, (String("Left operand of operator '<' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
739 $$ = new IntLiteral(0);
740 } else if (rhs->exprType() != INT_EXPR) {
741 PARSE_ERR(@3, (String("Right operand of operator '<' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
742 $$ = new IntLiteral(0);
743 } else {
744 $$ = new Relation(lhs, Relation::LESS_THAN, rhs);
745 }
746 }
747 | rel_expr '>' add_expr {
748 ExpressionRef lhs = $1;
749 ExpressionRef rhs = $3;
750 if (lhs->exprType() != INT_EXPR) {
751 PARSE_ERR(@1, (String("Left operand of operator '>' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
752 $$ = new IntLiteral(0);
753 } else if (rhs->exprType() != INT_EXPR) {
754 PARSE_ERR(@3, (String("Right operand of operator '>' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
755 $$ = new IntLiteral(0);
756 } else {
757 $$ = new Relation(lhs, Relation::GREATER_THAN, rhs);
758 }
759 }
760 | rel_expr LE add_expr {
761 ExpressionRef lhs = $1;
762 ExpressionRef rhs = $3;
763 if (lhs->exprType() != INT_EXPR) {
764 PARSE_ERR(@1, (String("Left operand of operator '<=' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
765 $$ = new IntLiteral(0);
766 } else if (rhs->exprType() != INT_EXPR) {
767 PARSE_ERR(@3, (String("Right operand of operator '<=' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
768 $$ = new IntLiteral(0);
769 } else {
770 $$ = new Relation(lhs, Relation::LESS_OR_EQUAL, rhs);
771 }
772 }
773 | rel_expr GE add_expr {
774 ExpressionRef lhs = $1;
775 ExpressionRef rhs = $3;
776 if (lhs->exprType() != INT_EXPR) {
777 PARSE_ERR(@1, (String("Left operand of operator '>=' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
778 $$ = new IntLiteral(0);
779 } else if (rhs->exprType() != INT_EXPR) {
780 PARSE_ERR(@3, (String("Right operand of operator '>=' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
781 $$ = new IntLiteral(0);
782 } else {
783 $$ = new Relation(lhs, Relation::GREATER_OR_EQUAL, rhs);
784 }
785 }
786 | rel_expr '=' add_expr {
787 $$ = new Relation($1, Relation::EQUAL, $3);
788 }
789 | rel_expr '#' add_expr {
790 $$ = new Relation($1, Relation::NOT_EQUAL, $3);
791 }
792
793 add_expr:
794 mul_expr
795 | add_expr '+' mul_expr {
796 ExpressionRef lhs = $1;
797 ExpressionRef rhs = $3;
798 if (lhs->exprType() != INT_EXPR) {
799 PARSE_ERR(@1, (String("Left operand of operator '+' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
800 $$ = new IntLiteral(0);
801 } else if (rhs->exprType() != INT_EXPR) {
802 PARSE_ERR(@3, (String("Right operand of operator '+' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
803 $$ = new IntLiteral(0);
804 } else {
805 $$ = new Add(lhs,rhs);
806 }
807 }
808 | add_expr '-' mul_expr {
809 ExpressionRef lhs = $1;
810 ExpressionRef rhs = $3;
811 if (lhs->exprType() != INT_EXPR) {
812 PARSE_ERR(@1, (String("Left operand of operator '-' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
813 $$ = new IntLiteral(0);
814 } else if (rhs->exprType() != INT_EXPR) {
815 PARSE_ERR(@3, (String("Right operand of operator '-' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
816 $$ = new IntLiteral(0);
817 } else {
818 $$ = new Sub(lhs,rhs);
819 }
820 }
821
822 mul_expr:
823 unary_expr
824 | mul_expr '*' unary_expr {
825 ExpressionRef lhs = $1;
826 ExpressionRef rhs = $3;
827 if (lhs->exprType() != INT_EXPR) {
828 PARSE_ERR(@1, (String("Left operand of operator '*' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
829 $$ = new IntLiteral(0);
830 } else if (rhs->exprType() != INT_EXPR) {
831 PARSE_ERR(@3, (String("Right operand of operator '*' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
832 $$ = new IntLiteral(0);
833 } else {
834 $$ = new Mul(lhs,rhs);
835 }
836 }
837 | mul_expr '/' unary_expr {
838 ExpressionRef lhs = $1;
839 ExpressionRef rhs = $3;
840 if (lhs->exprType() != INT_EXPR) {
841 PARSE_ERR(@1, (String("Left operand of operator '/' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
842 $$ = new IntLiteral(0);
843 } else if (rhs->exprType() != INT_EXPR) {
844 PARSE_ERR(@3, (String("Right operand of operator '/' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
845 $$ = new IntLiteral(0);
846 } else {
847 $$ = new Div(lhs,rhs);
848 }
849 }
850 | mul_expr MOD unary_expr {
851 ExpressionRef lhs = $1;
852 ExpressionRef rhs = $3;
853 if (lhs->exprType() != INT_EXPR) {
854 PARSE_ERR(@1, (String("Left operand of modulo operator must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
855 $$ = new IntLiteral(0);
856 } else if (rhs->exprType() != INT_EXPR) {
857 PARSE_ERR(@3, (String("Right operand of modulo operator must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
858 $$ = new IntLiteral(0);
859 } else {
860 $$ = new Mod(lhs,rhs);
861 }
862 }
863
864 %%
865
866 void InstrScript_error(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* err) {
867 //fprintf(stderr, "%d: %s\n", locp->first_line, err);
868 context->addErr(locp->first_line, locp->last_line, locp->first_column+1, locp->last_column+1, err);
869 }
870
871 void InstrScript_warning(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* txt) {
872 //fprintf(stderr, "WRN %d: %s\n", locp->first_line, txt);
873 context->addWrn(locp->first_line, locp->last_line, locp->first_column+1, locp->last_column+1, txt);
874 }
875
876 /// Custom implementation of yytnamerr() to ensure quotation is always stripped from token names before printing them to error messages.
877 int InstrScript_tnamerr(char* yyres, const char* yystr) {
878 if (*yystr == '"') {
879 int yyn = 0;
880 char const *yyp = yystr;
881 for (;;)
882 switch (*++yyp)
883 {
884 /*
885 case '\'':
886 case ',':
887 goto do_not_strip_quotes;
888
889 case '\\':
890 if (*++yyp != '\\')
891 goto do_not_strip_quotes;
892 */
893 /* Fall through. */
894 default:
895 if (yyres)
896 yyres[yyn] = *yyp;
897 yyn++;
898 break;
899
900 case '"':
901 if (yyres)
902 yyres[yyn] = '\0';
903 return yyn;
904 }
905 /*
906 do_not_strip_quotes: ;
907 */
908 }
909
910 if (! yyres)
911 return (int) yystrlen (yystr);
912
913 return int( yystpcpy (yyres, yystr) - yyres );
914 }

  ViewVC Help
Powered by ViewVC