/[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 3561 - (show annotations) (download)
Fri Aug 23 11:44:00 2019 UTC (4 years, 8 months ago) by schoenebeck
File size: 53275 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) 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 PARSE_DROP(loc) context->addPreprocessorComment(loc.first_line, loc.last_line, loc.first_column+1, loc.last_column+1);
27 #define yytnamerr(res,str) InstrScript_tnamerr(res, str)
28 %}
29
30 // generate reentrant safe parser
31 %pure-parser
32 %parse-param { LinuxSampler::ParserContext* context }
33 %lex-param { void* scanner }
34 // avoid symbol collision with other (i.e. future) auto generated (f)lex scanners
35 // (NOTE: "=" is deprecated here with Bison 3.x, however removing it would cause an error with Bison 2.x)
36 %name-prefix="InstrScript_"
37 %locations
38 %defines
39 %error-verbose
40
41 %token <iValue> INTEGER "integer literal"
42 %token <iUnitValue> INTEGER_UNIT "integer literal with unit"
43 %token <sValue> STRING "string literal"
44 %token <sValue> IDENTIFIER "function name"
45 %token <sValue> VARIABLE "variable name"
46 %token ON "keyword 'on'"
47 %token END "keyword 'end'"
48 %token INIT "keyword 'init'"
49 %token NOTE "keyword 'note'"
50 %token RELEASE "keyword 'release'"
51 %token CONTROLLER "keyword 'controller'"
52 %token DECLARE "keyword 'declare'"
53 %token ASSIGNMENT "operator ':='"
54 %token CONST_ "keyword 'const'"
55 %token POLYPHONIC "keyword 'polyphonic'"
56 %token WHILE "keyword 'while'"
57 %token SYNCHRONIZED "keyword 'synchronized'"
58 %token IF "keyword 'if'"
59 %token ELSE "keyword 'else'"
60 %token SELECT "keyword 'select'"
61 %token CASE "keyword 'case'"
62 %token TO "keyword 'to'"
63 %token OR "operator 'or'"
64 %token AND "operator 'and'"
65 %token NOT "operator 'not'"
66 %token BITWISE_OR "bitwise operator '.or.'"
67 %token BITWISE_AND "bitwise operator '.and.'"
68 %token BITWISE_NOT "bitwise operator '.not.'"
69 %token FUNCTION "keyword 'function'"
70 %token CALL "keyword 'call'"
71 %token MOD "operator 'mod'"
72 %token LE "operator '<='"
73 %token GE "operator '>='"
74 %token END_OF_FILE 0 "end of file"
75 %token UNKNOWN_CHAR "unknown character"
76
77 %type <nEventHandlers> script sections
78 %type <nEventHandler> section eventhandler
79 %type <nStatements> statements opt_statements userfunctioncall
80 %type <nStatement> statement assignment
81 %type <nFunctionCall> functioncall
82 %type <nArgs> args
83 %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
84 %type <nCaseBranch> caseclause
85 %type <nCaseBranches> caseclauses
86
87 %start script
88
89 %%
90
91 script:
92 sections {
93 $$ = context->handlers = $1;
94 }
95
96 sections:
97 section {
98 $$ = new EventHandlers();
99 if ($1) $$->add($1);
100 }
101 | sections section {
102 $$ = $1;
103 if ($2) $$->add($2);
104 }
105
106 section:
107 function_declaration {
108 $$ = EventHandlerRef();
109 }
110 | eventhandler {
111 $$ = $1;
112 }
113
114 eventhandler:
115 ON NOTE opt_statements END ON {
116 if (context->onNote)
117 PARSE_ERR(@2, "Redeclaration of 'note' event handler.");
118 context->onNote = new OnNote($3);
119 $$ = context->onNote;
120 }
121 | ON INIT opt_statements END ON {
122 if (context->onInit)
123 PARSE_ERR(@2, "Redeclaration of 'init' event handler.");
124 context->onInit = new OnInit($3);
125 $$ = context->onInit;
126 }
127 | ON RELEASE opt_statements END ON {
128 if (context->onRelease)
129 PARSE_ERR(@2, "Redeclaration of 'release' event handler.");
130 context->onRelease = new OnRelease($3);
131 $$ = context->onRelease;
132 }
133 | ON CONTROLLER opt_statements END ON {
134 if (context->onController)
135 PARSE_ERR(@2, "Redeclaration of 'controller' event handler.");
136 context->onController = new OnController($3);
137 $$ = context->onController;
138 }
139
140 function_declaration:
141 FUNCTION IDENTIFIER opt_statements END FUNCTION {
142 const char* name = $2;
143 if (context->functionProvider->functionByName(name)) {
144 PARSE_ERR(@2, (String("There is already a built-in function with name '") + name + "'.").c_str());
145 } else if (context->userFunctionByName(name)) {
146 PARSE_ERR(@2, (String("There is already a user defined function with name '") + name + "'.").c_str());
147 } else {
148 context->userFnTable[name] = $3;
149 }
150 }
151
152 opt_statements:
153 /* epsilon (empty argument) */ {
154 $$ = new Statements();
155 }
156 | statements {
157 $$ = $1;
158 }
159
160 statements:
161 statement {
162 $$ = new Statements();
163 if ($1) {
164 if (!isNoOperation($1)) $$->add($1); // filter out NoOperation statements
165 } else
166 PARSE_WRN(@1, "Not a statement.");
167 }
168 | statements statement {
169 $$ = $1;
170 if ($2) {
171 if (!isNoOperation($2)) $$->add($2); // filter out NoOperation statements
172 } else
173 PARSE_WRN(@2, "Not a statement.");
174 }
175
176 statement:
177 functioncall {
178 $$ = $1;
179 }
180 | userfunctioncall {
181 $$ = $1;
182 }
183 | DECLARE VARIABLE {
184 const char* name = $2;
185 //printf("declared var '%s'\n", name);
186 if (context->variableByName(name))
187 PARSE_ERR(@2, (String("Redeclaration of variable '") + name + "'.").c_str());
188 if (name[0] == '@') {
189 context->vartable[name] = new StringVariable(context);
190 $$ = new NoOperation;
191 } else {
192 context->vartable[name] = new IntVariable(context);
193 $$ = new NoOperation;
194 }
195 }
196 | DECLARE POLYPHONIC VARIABLE {
197 const char* name = $3;
198 //printf("declared polyphonic var '%s'\n", name);
199 if (context->variableByName(name))
200 PARSE_ERR(@3, (String("Redeclaration of variable '") + name + "'.").c_str());
201 if (name[0] != '$') {
202 PARSE_ERR(@3, "Polyphonic variables may only be declared as integers.");
203 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
204 } else {
205 context->vartable[name] = new PolyphonicIntVariable(context);
206 $$ = new NoOperation;
207 }
208 }
209 | DECLARE VARIABLE ASSIGNMENT expr {
210 const char* name = $2;
211 //printf("declared assign var '%s'\n", name);
212 if (context->variableByName(name))
213 PARSE_ERR(@2, (String("Redeclaration of variable '") + name + "'.").c_str());
214 if ($4->exprType() == STRING_EXPR) {
215 if (name[0] == '$')
216 PARSE_WRN(@2, (String("Variable '") + name + "' declared as integer, string expression assigned though.").c_str());
217 StringExprRef expr = $4;
218 if (expr->isConstExpr()) {
219 const String s = expr->evalStr();
220 StringVariableRef var = new StringVariable(context);
221 context->vartable[name] = var;
222 $$ = new Assignment(var, new StringLiteral(s));
223 } else {
224 StringVariableRef var = new StringVariable(context);
225 context->vartable[name] = var;
226 $$ = new Assignment(var, expr);
227 }
228 } else {
229 if (name[0] == '@')
230 PARSE_WRN(@2, (String("Variable '") + name + "' declared as string, integer expression assigned though.").c_str());
231 IntExprRef expr = $4;
232 IntVariableRef var = new IntVariable(context);
233 if (expr->isConstExpr()) {
234 const vmint i = expr->evalInt();
235 $$ = new Assignment(var, new IntLiteral(i));
236 } else {
237 $$ = new Assignment(var, expr);
238 }
239 var->copyUnitFrom(expr);
240 var->setFinal(expr->isFinal());
241 context->vartable[name] = var;
242 }
243 }
244 | DECLARE VARIABLE '[' expr ']' {
245 //printf("declare array without args\n");
246 const char* name = $2;
247 if (!$4->isConstExpr()) {
248 PARSE_ERR(@4, (String("Array variable '") + name + "' must be declared with constant array size.").c_str());
249 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
250 } else if ($4->exprType() != INT_EXPR) {
251 PARSE_ERR(@4, (String("Size of array variable '") + name + "' declared with non integer expression.").c_str());
252 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
253 } else if (context->variableByName(name)) {
254 PARSE_ERR(@2, (String("Redeclaration of variable '") + name + "'.").c_str());
255 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
256 } else {
257 IntExprRef expr = $4;
258 if (expr->unitType() || expr->unitPrefix(0)) {
259 PARSE_ERR(@4, "Units are not allowed as array size.");
260 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
261 } else {
262 if (expr->isFinal())
263 PARSE_WRN(@4, "Final operator '!' is meaningless here.");
264 vmint size = expr->evalInt();
265 if (size <= 0) {
266 PARSE_ERR(@4, (String("Array variable '") + name + "' declared with array size " + ToString(size) + ".").c_str());
267 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
268 } else {
269 context->vartable[name] = new IntArrayVariable(context, size);
270 $$ = new NoOperation;
271 }
272 }
273 }
274 }
275 | DECLARE VARIABLE '[' expr ']' ASSIGNMENT '(' args ')' {
276 const char* name = $2;
277 if (!$4->isConstExpr()) {
278 PARSE_ERR(@4, (String("Array variable '") + name + "' must be declared with constant array size.").c_str());
279 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
280 } else if ($4->exprType() != INT_EXPR) {
281 PARSE_ERR(@4, (String("Size of array variable '") + name + "' declared with non integer expression.").c_str());
282 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
283 } else if (context->variableByName(name)) {
284 PARSE_ERR(@2, (String("Redeclaration of variable '") + name + "'.").c_str());
285 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
286 } else {
287 IntExprRef sizeExpr = $4;
288 ArgsRef args = $8;
289 vmint size = sizeExpr->evalInt();
290 if (size <= 0) {
291 PARSE_ERR(@4, (String("Array variable '") + name + "' must be declared with positive array size.").c_str());
292 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
293 } else if (args->argsCount() > size) {
294 PARSE_ERR(@8, (String("Array variable '") + name +
295 "' was declared with size " + ToString(size) +
296 " but " + ToString(args->argsCount()) +
297 " values were assigned." ).c_str());
298 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
299 } else if (sizeExpr->unitType() || sizeExpr->unitPrefix(0)) {
300 PARSE_ERR(@4, "Units are not allowed as array size.");
301 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
302 } else {
303 if (sizeExpr->isFinal())
304 PARSE_WRN(@4, "Final operator '!' is meaningless here.");
305 bool argsOK = true;
306 for (vmint i = 0; i < args->argsCount(); ++i) {
307 if (args->arg(i)->exprType() != INT_EXPR) {
308 PARSE_ERR(
309 @8,
310 (String("Array variable '") + name +
311 "' declared with invalid assignment values. Assigned element " +
312 ToString(i+1) + " is not an integer expression.").c_str()
313 );
314 argsOK = false;
315 break;
316 } else if (args->arg(i)->asInt()->unitType() ||
317 args->arg(i)->asInt()->unitPrefix(0))
318 {
319 PARSE_ERR(
320 @8,
321 (String("Array variable '") + name +
322 "' declared with invalid assignment values. Assigned element " +
323 ToString(i+1) + " contains a unit.").c_str()
324 );
325 argsOK = false;
326 break;
327 }
328 }
329 if (argsOK) {
330 context->vartable[name] = new IntArrayVariable(context, size, args);
331 $$ = new NoOperation;
332 } else
333 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
334 }
335 }
336 }
337 | DECLARE CONST_ VARIABLE '[' expr ']' ASSIGNMENT '(' args ')' {
338 const char* name = $3;
339 if (!$5->isConstExpr()) {
340 PARSE_ERR(@5, (String("Array variable '") + name + "' must be declared with constant array size.").c_str());
341 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
342 } else if ($5->exprType() != INT_EXPR) {
343 PARSE_ERR(@5, (String("Size of array variable '") + name + "' declared with non integer expression.").c_str());
344 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
345 } else if (context->variableByName(name)) {
346 PARSE_ERR(@3, (String("Redeclaration of variable '") + name + "'.").c_str());
347 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
348 } else {
349 IntExprRef sizeExpr = $5;
350 ArgsRef args = $9;
351 vmint size = sizeExpr->evalInt();
352 if (size <= 0) {
353 PARSE_ERR(@5, (String("Array variable '") + name + "' must be declared with positive array size.").c_str());
354 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
355 } else if (args->argsCount() > size) {
356 PARSE_ERR(@9, (String("Array variable '") + name +
357 "' was declared with size " + ToString(size) +
358 " but " + ToString(args->argsCount()) +
359 " values were assigned." ).c_str());
360 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
361 } else if (sizeExpr->unitType() || sizeExpr->unitPrefix(0)) {
362 PARSE_ERR(@5, "Units are not allowed as array size.");
363 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
364 } else {
365 if (sizeExpr->isFinal())
366 PARSE_WRN(@5, "Final operator '!' is meaningless here.");
367 bool argsOK = true;
368 for (vmint i = 0; i < args->argsCount(); ++i) {
369 if (args->arg(i)->exprType() != INT_EXPR) {
370 PARSE_ERR(
371 @9,
372 (String("Array variable '") + name +
373 "' declared with invalid assignment values. Assigned element " +
374 ToString(i+1) + " is not an integer expression.").c_str()
375 );
376 argsOK = false;
377 break;
378 }
379 if (!args->arg(i)->isConstExpr()) {
380 PARSE_ERR(
381 @9,
382 (String("const array variable '") + name +
383 "' must be defined with const values. Assigned element " +
384 ToString(i+1) + " is not a const expression though.").c_str()
385 );
386 argsOK = false;
387 break;
388 } else if (args->arg(i)->asInt()->unitType() ||
389 args->arg(i)->asInt()->unitPrefix(0))
390 {
391 PARSE_ERR(
392 @9,
393 (String("const array variable '") + name +
394 "' declared with invalid assignment values. Assigned element " +
395 ToString(i+1) + " contains a unit.").c_str()
396 );
397 argsOK = false;
398 break;
399 }
400 }
401 if (argsOK) {
402 context->vartable[name] = new IntArrayVariable(context, size, args, true);
403 $$ = new NoOperation;
404 } else
405 $$ = new FunctionCall("nothing", new Args, NULL); // whatever
406 }
407 }
408 }
409 | DECLARE CONST_ VARIABLE ASSIGNMENT expr {
410 const char* name = $3;
411 if ($5->exprType() == STRING_EXPR) {
412 if (name[0] == '$')
413 PARSE_WRN(@5, "Variable declared as integer, string expression assigned though.");
414 String s;
415 StringExprRef expr = $5;
416 if (expr->isConstExpr())
417 s = expr->evalStr();
418 else
419 PARSE_ERR(@5, (String("Assignment to const string variable '") + name + "' requires const expression.").c_str());
420 ConstStringVariableRef var = new ConstStringVariable(context, s);
421 context->vartable[name] = var;
422 //$$ = new Assignment(var, new StringLiteral(s));
423 $$ = new NoOperation();
424 } else {
425 if (name[0] == '@')
426 PARSE_WRN(@5, "Variable declared as string, integer expression assigned though.");
427 vmint i = 0;
428 IntExprRef expr = $5;
429 if (expr->isConstExpr())
430 i = expr->evalInt();
431 else
432 PARSE_ERR(@5, (String("Assignment to const integer variable '") + name + "' requires const expression.").c_str());
433 ConstIntVariableRef var = new ConstIntVariable(i);
434 var->copyUnitFrom(expr);
435 var->setFinal(expr->isFinal());
436 context->vartable[name] = var;
437 //$$ = new Assignment(var, new IntLiteral(i));
438 $$ = new NoOperation();
439 }
440 }
441 | assignment {
442 $$ = $1;
443 }
444 | WHILE '(' expr ')' opt_statements END WHILE {
445 if ($3->exprType() == INT_EXPR) {
446 IntExprRef expr = $3;
447 if (expr->isFinal() && expr->isConstExpr())
448 PARSE_WRN(@3, "Final operator '!' is meaningless here.");
449 $$ = new While(expr, $5);
450 } else {
451 PARSE_ERR(@3, "Condition for 'while' loops must be integer expression.");
452 $$ = new While(new IntLiteral(0), $5);
453 }
454 }
455 | SYNCHRONIZED opt_statements END SYNCHRONIZED {
456 $$ = new SyncBlock($2);
457 }
458 | IF '(' expr ')' opt_statements ELSE opt_statements END IF {
459 if ($3->exprType() == INT_EXPR) {
460 IntExprRef expr = $3;
461 if (expr->isFinal() && expr->isConstExpr())
462 PARSE_WRN(@3, "Final operator '!' is meaningless here.");
463 $$ = new If($3, $5, $7);
464 } else {
465 PARSE_ERR(@3, "Condition for 'if' must be integer expression.");
466 $$ = new If(new IntLiteral(0), $5, $7);
467 }
468 }
469 | IF '(' expr ')' opt_statements END IF {
470 if ($3->exprType() == INT_EXPR) {
471 IntExprRef expr = $3;
472 if (expr->isFinal() && expr->isConstExpr())
473 PARSE_WRN(@3, "Final operator '!' is meaningless here.");
474 $$ = new If($3, $5);
475 } else {
476 PARSE_ERR(@3, "Condition for 'if' must be integer expression.");
477 $$ = new If(new IntLiteral(0), $5);
478 }
479 }
480 | SELECT expr caseclauses END SELECT {
481 if ($2->exprType() == INT_EXPR) {
482 IntExprRef expr = $2;
483 if (expr->unitType() || expr->unitPrefix(0)) {
484 PARSE_ERR(@2, "Units are not allowed here.");
485 } else {
486 if (expr->isFinal() && expr->isConstExpr())
487 PARSE_WRN(@2, "Final operator '!' is meaningless here.");
488 $$ = new SelectCase(expr, $3);
489 }
490 } else {
491 PARSE_ERR(@2, "Statement 'select' can only by applied to integer expressions.");
492 $$ = new SelectCase(new IntLiteral(0), $3);
493 }
494 }
495
496 caseclauses:
497 caseclause {
498 $$ = CaseBranches();
499 $$.push_back($1);
500 }
501 | caseclauses caseclause {
502 $$ = $1;
503 $$.push_back($2);
504 }
505
506 caseclause:
507 CASE INTEGER opt_statements {
508 $$ = CaseBranch();
509 $$.from = new IntLiteral($2);
510 $$.statements = $3;
511 }
512 | CASE INTEGER TO INTEGER opt_statements {
513 $$ = CaseBranch();
514 $$.from = new IntLiteral($2);
515 $$.to = new IntLiteral($4);
516 $$.statements = $5;
517 }
518
519 userfunctioncall:
520 CALL IDENTIFIER {
521 const char* name = $2;
522 StatementsRef fn = context->userFunctionByName(name);
523 if (context->functionProvider->functionByName(name)) {
524 PARSE_ERR(@1, (String("Keyword 'call' must only be used for user defined functions, not for any built-in function like '") + name + "'.").c_str());
525 $$ = StatementsRef();
526 } else if (!fn) {
527 PARSE_ERR(@2, (String("No user defined function with name '") + name + "'.").c_str());
528 $$ = StatementsRef();
529 } else {
530 $$ = fn;
531 }
532 }
533
534 functioncall:
535 IDENTIFIER '(' args ')' {
536 const char* name = $1;
537 //printf("function call of '%s' with args\n", name);
538 ArgsRef args = $3;
539 VMFunction* fn = context->functionProvider->functionByName(name);
540 if (context->userFunctionByName(name)) {
541 PARSE_ERR(@1, (String("Missing 'call' keyword before user defined function name '") + name + "'.").c_str());
542 $$ = new FunctionCall(name, args, NULL);
543 } else if (!fn) {
544 PARSE_ERR(@1, (String("No built-in function with name '") + name + "'.").c_str());
545 $$ = new FunctionCall(name, args, NULL);
546 } else if (context->functionProvider->isFunctionDisabled(fn,context)) {
547 PARSE_DROP(@$);
548 $$ = new NoFunctionCall;
549 } else if (args->argsCount() < fn->minRequiredArgs()) {
550 PARSE_ERR(@3, (String("Built-in function '") + name + "' requires at least " + ToString(fn->minRequiredArgs()) + " arguments.").c_str());
551 $$ = new FunctionCall(name, args, NULL);
552 } else if (args->argsCount() > fn->maxAllowedArgs()) {
553 PARSE_ERR(@3, (String("Built-in function '") + name + "' accepts max. " + ToString(fn->maxAllowedArgs()) + " arguments.").c_str());
554 $$ = new FunctionCall(name, args, NULL);
555 } else {
556 bool argsOK = true;
557 for (vmint i = 0; i < args->argsCount(); ++i) {
558 if (args->arg(i)->exprType() != fn->argType(i) && !fn->acceptsArgType(i, args->arg(i)->exprType())) {
559 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());
560 argsOK = false;
561 break;
562 } else if (fn->modifiesArg(i) && !args->arg(i)->isModifyable()) {
563 PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' expects an assignable variable.").c_str());
564 argsOK = false;
565 break;
566 } else if (args->arg(i)->exprType() == INT_EXPR && !fn->acceptsArgUnitType(i, args->arg(i)->asInt()->unitType())) {
567 if (args->arg(i)->asInt()->unitType())
568 PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' does not expect unit " + unitTypeStr(args->arg(i)->asInt()->unitType()) + ".").c_str());
569 else
570 PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' expects a unit.").c_str());
571 argsOK = false;
572 break;
573 } else if (!fn->acceptsArgUnitPrefix(i) && args->arg(i)->exprType() == INT_EXPR && args->arg(i)->asInt()->unitPrefix(0)) {
574 PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' does not expect a unit prefix.").c_str());
575 argsOK = false;
576 break;
577 } else if (!fn->acceptsArgFinal(i) && args->arg(i)->exprType() == INT_EXPR && args->arg(i)->asInt()->isFinal()) {
578 PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' does not expect a \"final\" value.").c_str());
579 argsOK = false;
580 break;
581 }
582 }
583 $$ = new FunctionCall(name, args, argsOK ? fn : NULL);
584 }
585 }
586 | IDENTIFIER '(' ')' {
587 const char* name = $1;
588 //printf("function call of '%s' (with empty args)\n", name);
589 ArgsRef args = new Args;
590 VMFunction* fn = context->functionProvider->functionByName(name);
591 if (context->userFunctionByName(name)) {
592 PARSE_ERR(@1, (String("Missing 'call' keyword before user defined function name '") + name + "'.").c_str());
593 $$ = new FunctionCall(name, args, NULL);
594 } else if (!fn) {
595 PARSE_ERR(@1, (String("No built-in function with name '") + name + "'.").c_str());
596 $$ = new FunctionCall(name, args, NULL);
597 } else if (context->functionProvider->isFunctionDisabled(fn,context)) {
598 PARSE_DROP(@$);
599 $$ = new NoFunctionCall;
600 } else if (fn->minRequiredArgs() > 0) {
601 PARSE_ERR(@3, (String("Built-in function '") + name + "' requires at least " + ToString(fn->minRequiredArgs()) + " arguments.").c_str());
602 $$ = new FunctionCall(name, args, NULL);
603 } else {
604 $$ = new FunctionCall(name, args, fn);
605 }
606 }
607 | IDENTIFIER {
608 const char* name = $1;
609 //printf("function call of '%s' (without args)\n", name);
610 ArgsRef args = new Args;
611 VMFunction* fn = context->functionProvider->functionByName(name);
612 if (context->userFunctionByName(name)) {
613 PARSE_ERR(@1, (String("Missing 'call' keyword before user defined function name '") + name + "'.").c_str());
614 $$ = new FunctionCall(name, args, NULL);
615 } else if (!fn) {
616 PARSE_ERR(@1, (String("No built-in function with name '") + name + "'.").c_str());
617 $$ = new FunctionCall(name, args, NULL);
618 } else if (context->functionProvider->isFunctionDisabled(fn,context)) {
619 PARSE_DROP(@$);
620 $$ = new NoFunctionCall;
621 } else if (fn->minRequiredArgs() > 0) {
622 PARSE_ERR(@1, (String("Built-in function '") + name + "' requires at least " + ToString(fn->minRequiredArgs()) + " arguments.").c_str());
623 $$ = new FunctionCall(name, args, NULL);
624 } else {
625 $$ = new FunctionCall(name, args, fn);
626 }
627 }
628
629 args:
630 arg {
631 $$ = new Args();
632 $$->add($1);
633 }
634 | args ',' arg {
635 $$ = $1;
636 $$->add($3);
637 }
638
639 arg:
640 expr
641
642 assignment:
643 VARIABLE ASSIGNMENT expr {
644 //printf("variable lookup with name '%s' as assignment expr\n", $1);
645 const char* name = $1;
646 VariableRef var = context->variableByName(name);
647 if (!var)
648 PARSE_ERR(@1, (String("Variable assignment: No variable declared with name '") + name + "'.").c_str());
649 else if (var->isConstExpr())
650 PARSE_ERR(@2, (String("Variable assignment: Cannot modify const variable '") + name + "'.").c_str());
651 else if (!var->isAssignable())
652 PARSE_ERR(@2, (String("Variable assignment: Variable '") + name + "' is not assignable.").c_str());
653 else if (var->exprType() != $3->exprType())
654 PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' is of type " + typeStr(var->exprType()) + ", assignment is of type " + typeStr($3->exprType()) + " though.").c_str());
655 else if (var->exprType() == INT_EXPR) {
656 IntVariableRef intVar = var;
657 IntExprRef expr = $3;
658 if (intVar->unitType() != expr->unitType())
659 PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' has unit type " + unitTypeStr(intVar->unitType()) + ", assignment has unit type " + unitTypeStr(expr->unitType()) + " though.").c_str());
660 else if (intVar->unitFactor() != expr->unitFactor())
661 PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' has a different unit prefix.").c_str());
662 else if (intVar->isFinal() != expr->isFinal())
663 PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' was declared as " + String(intVar->isFinal() ? "final" : "not final") + ", assignment is " + String(expr->isFinal() ? "final" : "not final") + " though.").c_str());
664 }
665 $$ = new Assignment(var, $3);
666 }
667 | VARIABLE '[' expr ']' ASSIGNMENT expr {
668 const char* name = $1;
669 VariableRef var = context->variableByName(name);
670 if (!var)
671 PARSE_ERR(@1, (String("No variable declared with name '") + name + "'.").c_str());
672 else if (var->exprType() != INT_ARR_EXPR)
673 PARSE_ERR(@2, (String("Variable '") + name + "' is not an array variable.").c_str());
674 else if (var->isConstExpr())
675 PARSE_ERR(@5, (String("Variable assignment: Cannot modify const array variable '") + name + "'.").c_str());
676 else if (!var->isAssignable())
677 PARSE_ERR(@5, (String("Variable assignment: Array variable '") + name + "' is not assignable.").c_str());
678 else if ($3->exprType() != INT_EXPR)
679 PARSE_ERR(@3, (String("Array variable '") + name + "' accessed with non integer expression.").c_str());
680 else if ($3->asInt()->unitType())
681 PARSE_ERR(@3, "Unit types are not allowed as array index.");
682 else if ($6->exprType() != INT_EXPR)
683 PARSE_ERR(@5, (String("Value assigned to array variable '") + name + "' must be an integer expression.").c_str());
684 else if ($6->asInt()->unitType())
685 PARSE_ERR(@6, "Unit types are not allowed for array variables.");
686 else if ($6->asInt()->isFinal())
687 PARSE_ERR(@6, "Final operator '!' not allowed for array variables.");
688 else if ($3->isConstExpr() && $3->asInt()->evalInt() >= ((IntArrayVariableRef)var)->arraySize())
689 PARSE_WRN(@3, (String("Index ") + ToString($3->asInt()->evalInt()) +
690 " exceeds size of array variable '" + name +
691 "' which was declared with size " +
692 ToString(((IntArrayVariableRef)var)->arraySize()) + ".").c_str());
693 else if ($3->asInt()->isFinal())
694 PARSE_WRN(@3, "Final operator '!' is meaningless here.");
695 IntArrayElementRef element = new IntArrayElement(var, $3);
696 $$ = new Assignment(element, $6);
697 }
698
699 unary_expr:
700 INTEGER {
701 $$ = new IntLiteral($1);
702 }
703 | INTEGER_UNIT {
704 IntLiteralRef literal = new IntLiteral($1.iValue);
705 literal->setUnit($1.prefix, $1.unit);
706 $$ = literal;
707 }
708 | STRING {
709 $$ = new StringLiteral($1);
710 }
711 | VARIABLE {
712 //printf("variable lookup with name '%s' as unary expr\n", $1);
713 VariableRef var = context->variableByName($1);
714 if (var)
715 $$ = var;
716 else {
717 PARSE_ERR(@1, (String("No variable declared with name '") + $1 + "'.").c_str());
718 $$ = new IntLiteral(0);
719 }
720 }
721 | VARIABLE '[' expr ']' {
722 const char* name = $1;
723 VariableRef var = context->variableByName(name);
724 if (!var) {
725 PARSE_ERR(@1, (String("No variable declared with name '") + name + "'.").c_str());
726 $$ = new IntLiteral(0);
727 } else if (var->exprType() != INT_ARR_EXPR) {
728 PARSE_ERR(@2, (String("Variable '") + name + "' is not an array variable.").c_str());
729 $$ = new IntLiteral(0);
730 } else if ($3->exprType() != INT_EXPR) {
731 PARSE_ERR(@3, (String("Array variable '") + name + "' accessed with non integer expression.").c_str());
732 $$ = new IntLiteral(0);
733 } else if ($3->asInt()->unitType() || $3->asInt()->unitPrefix(0)) {
734 PARSE_ERR(@3, "Units are not allowed as array index.");
735 $$ = new IntLiteral(0);
736 } else {
737 if ($3->isConstExpr() && $3->asInt()->evalInt() >= ((IntArrayVariableRef)var)->arraySize())
738 PARSE_WRN(@3, (String("Index ") + ToString($3->asInt()->evalInt()) +
739 " exceeds size of array variable '" + name +
740 "' which was declared with size " +
741 ToString(((IntArrayVariableRef)var)->arraySize()) + ".").c_str());
742 else if ($3->asInt()->isFinal())
743 PARSE_WRN(@3, "Final operator '!' is meaningless here.");
744 $$ = new IntArrayElement(var, $3);
745 }
746 }
747 | '(' expr ')' {
748 $$ = $2;
749 }
750 | functioncall {
751 $$ = $1;
752 }
753 | '-' unary_expr {
754 $$ = new Neg($2);
755 }
756 | BITWISE_NOT unary_expr {
757 if ($2->exprType() != INT_EXPR) {
758 PARSE_ERR(@2, (String("Right operand of bitwise operator '.not.' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str());
759 $$ = new IntLiteral(0);
760 } else if ($2->asInt()->unitType() || $2->asInt()->unitPrefix(0)) {
761 PARSE_ERR(@2, "Units are not allowed for operands of bitwise operations.");
762 $$ = new IntLiteral(0);
763 } else {
764 $$ = new BitwiseNot($2);
765 }
766 }
767 | NOT unary_expr {
768 if ($2->exprType() != INT_EXPR) {
769 PARSE_ERR(@2, (String("Right operand of operator 'not' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str());
770 $$ = new IntLiteral(0);
771 } else if ($2->asInt()->unitType() || $2->asInt()->unitPrefix(0)) {
772 PARSE_ERR(@2, "Units are not allowed for operands of logical operations.");
773 $$ = new IntLiteral(0);
774 } else {
775 $$ = new Not($2);
776 }
777 }
778 | '!' unary_expr {
779 if ($2->exprType() != INT_EXPR) {
780 PARSE_ERR(@2, (String("Right operand of \"final\" operator '!' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str());
781 $$ = new IntLiteral(0);
782 } else {
783 $$ = new Final($2);
784 }
785 }
786
787 expr:
788 concat_expr
789
790 concat_expr:
791 logical_or_expr
792 | concat_expr '&' logical_or_expr {
793 ExpressionRef lhs = $1;
794 ExpressionRef rhs = $3;
795 if (lhs->isConstExpr() && rhs->isConstExpr()) {
796 $$ = new StringLiteral(
797 lhs->evalCastToStr() + rhs->evalCastToStr()
798 );
799 } else {
800 $$ = new ConcatString(lhs, rhs);
801 }
802 }
803
804 logical_or_expr:
805 logical_and_expr
806 | logical_or_expr OR logical_and_expr {
807 ExpressionRef lhs = $1;
808 ExpressionRef rhs = $3;
809 if (lhs->exprType() != INT_EXPR) {
810 PARSE_ERR(@1, (String("Left operand of operator 'or' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
811 $$ = new IntLiteral(0);
812 } else if (rhs->exprType() != INT_EXPR) {
813 PARSE_ERR(@3, (String("Right operand of operator 'or' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
814 $$ = new IntLiteral(0);
815 } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) {
816 PARSE_ERR(@1, "Units are not allowed for operands of logical operations.");
817 $$ = new IntLiteral(0);
818 } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) {
819 PARSE_ERR(@3, "Units are not allowed for operands of logical operations.");
820 $$ = new IntLiteral(0);
821 } else {
822 $$ = new Or(lhs, rhs);
823 }
824 }
825
826 logical_and_expr:
827 bitwise_or_expr {
828 $$ = $1;
829 }
830 | logical_and_expr AND bitwise_or_expr {
831 ExpressionRef lhs = $1;
832 ExpressionRef rhs = $3;
833 if (lhs->exprType() != INT_EXPR) {
834 PARSE_ERR(@1, (String("Left operand of operator 'and' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
835 $$ = new IntLiteral(0);
836 } else if (rhs->exprType() != INT_EXPR) {
837 PARSE_ERR(@3, (String("Right operand of operator 'and' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
838 $$ = new IntLiteral(0);
839 } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) {
840 PARSE_ERR(@1, "Units are not allowed for operands of logical operations.");
841 $$ = new IntLiteral(0);
842 } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) {
843 PARSE_ERR(@3, "Units are not allowed for operands of logical operations.");
844 $$ = new IntLiteral(0);
845 } else {
846 $$ = new And(lhs, rhs);
847 }
848 }
849
850 bitwise_or_expr:
851 bitwise_and_expr
852 | bitwise_or_expr BITWISE_OR bitwise_and_expr {
853 ExpressionRef lhs = $1;
854 ExpressionRef rhs = $3;
855 if (lhs->exprType() != INT_EXPR) {
856 PARSE_ERR(@1, (String("Left operand of bitwise operator '.or.' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
857 $$ = new IntLiteral(0);
858 } else if (rhs->exprType() != INT_EXPR) {
859 PARSE_ERR(@3, (String("Right operand of bitwise operator '.or.' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
860 $$ = new IntLiteral(0);
861 } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) {
862 PARSE_ERR(@1, "Units are not allowed for operands of bitwise operations.");
863 $$ = new IntLiteral(0);
864 } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) {
865 PARSE_ERR(@3, "Units are not allowed for operands of bitwise operations.");
866 $$ = new IntLiteral(0);
867 } else {
868 $$ = new BitwiseOr(lhs, rhs);
869 }
870 }
871
872 bitwise_and_expr:
873 rel_expr {
874 $$ = $1;
875 }
876 | bitwise_and_expr BITWISE_AND rel_expr {
877 ExpressionRef lhs = $1;
878 ExpressionRef rhs = $3;
879 if (lhs->exprType() != INT_EXPR) {
880 PARSE_ERR(@1, (String("Left operand of bitwise operator '.and.' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
881 $$ = new IntLiteral(0);
882 } else if (rhs->exprType() != INT_EXPR) {
883 PARSE_ERR(@3, (String("Right operand of bitwise operator '.and.' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
884 $$ = new IntLiteral(0);
885 } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) {
886 PARSE_ERR(@1, "Units are not allowed for operands of bitwise operations.");
887 $$ = new IntLiteral(0);
888 } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) {
889 PARSE_ERR(@3, "Units are not allowed for operands of bitwise operations.");
890 $$ = new IntLiteral(0);
891 } else {
892 $$ = new BitwiseAnd(lhs, rhs);
893 }
894 }
895
896 rel_expr:
897 add_expr
898 | rel_expr '<' add_expr {
899 ExpressionRef lhs = $1;
900 ExpressionRef rhs = $3;
901 if (lhs->exprType() != INT_EXPR) {
902 PARSE_ERR(@1, (String("Left operand of operator '<' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
903 $$ = new IntLiteral(0);
904 } else if (rhs->exprType() != INT_EXPR) {
905 PARSE_ERR(@3, (String("Right operand of operator '<' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
906 $$ = new IntLiteral(0);
907 } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() ||
908 lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
909 {
910 PARSE_ERR(@2, "Operands of relative operations must have same unit.");
911 $$ = new IntLiteral(0);
912 } else {
913 $$ = new Relation(lhs, Relation::LESS_THAN, rhs);
914 }
915 }
916 | rel_expr '>' add_expr {
917 ExpressionRef lhs = $1;
918 ExpressionRef rhs = $3;
919 if (lhs->exprType() != INT_EXPR) {
920 PARSE_ERR(@1, (String("Left operand of operator '>' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
921 $$ = new IntLiteral(0);
922 } else if (rhs->exprType() != INT_EXPR) {
923 PARSE_ERR(@3, (String("Right operand of operator '>' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
924 $$ = new IntLiteral(0);
925 } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() ||
926 lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
927 {
928 PARSE_ERR(@2, "Operands of relative operations must have same unit.");
929 $$ = new IntLiteral(0);
930 } else {
931 $$ = new Relation(lhs, Relation::GREATER_THAN, rhs);
932 }
933 }
934 | rel_expr LE add_expr {
935 ExpressionRef lhs = $1;
936 ExpressionRef rhs = $3;
937 if (lhs->exprType() != INT_EXPR) {
938 PARSE_ERR(@1, (String("Left operand of operator '<=' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
939 $$ = new IntLiteral(0);
940 } else if (rhs->exprType() != INT_EXPR) {
941 PARSE_ERR(@3, (String("Right operand of operator '<=' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
942 $$ = new IntLiteral(0);
943 } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() ||
944 lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
945 {
946 PARSE_ERR(@2, "Operands of relative operations must have same unit.");
947 $$ = new IntLiteral(0);
948 } else {
949 $$ = new Relation(lhs, Relation::LESS_OR_EQUAL, rhs);
950 }
951 }
952 | rel_expr GE add_expr {
953 ExpressionRef lhs = $1;
954 ExpressionRef rhs = $3;
955 if (lhs->exprType() != INT_EXPR) {
956 PARSE_ERR(@1, (String("Left operand of operator '>=' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
957 $$ = new IntLiteral(0);
958 } else if (rhs->exprType() != INT_EXPR) {
959 PARSE_ERR(@3, (String("Right operand of operator '>=' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
960 $$ = new IntLiteral(0);
961 } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() ||
962 lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
963 {
964 PARSE_ERR(@2, "Operands of relative operations must have same unit.");
965 $$ = new IntLiteral(0);
966 } else {
967 $$ = new Relation(lhs, Relation::GREATER_OR_EQUAL, rhs);
968 }
969 }
970 | rel_expr '=' add_expr {
971 ExpressionRef lhs = $1;
972 ExpressionRef rhs = $3;
973 if (lhs->exprType() != INT_EXPR) {
974 PARSE_ERR(@1, (String("Left operand of operator '=' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
975 $$ = new IntLiteral(0);
976 } else if (rhs->exprType() != INT_EXPR) {
977 PARSE_ERR(@3, (String("Right operand of operator '=' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
978 $$ = new IntLiteral(0);
979 } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() ||
980 lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
981 {
982 PARSE_ERR(@2, "Operands of relative operations must have same unit.");
983 $$ = new IntLiteral(0);
984 } else {
985 $$ = new Relation(lhs, Relation::EQUAL, rhs);
986 }
987 }
988 | rel_expr '#' add_expr {
989 ExpressionRef lhs = $1;
990 ExpressionRef rhs = $3;
991 if (lhs->exprType() != INT_EXPR) {
992 PARSE_ERR(@1, (String("Left operand of operator '#' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
993 $$ = new IntLiteral(0);
994 } else if (rhs->exprType() != INT_EXPR) {
995 PARSE_ERR(@3, (String("Right operand of operator '#' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
996 $$ = new IntLiteral(0);
997 } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() ||
998 lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
999 {
1000 PARSE_ERR(@2, "Operands of relative operations must have same unit.");
1001 $$ = new IntLiteral(0);
1002 } else {
1003 $$ = new Relation(lhs, Relation::NOT_EQUAL, rhs);
1004 }
1005 }
1006
1007 add_expr:
1008 mul_expr
1009 | add_expr '+' mul_expr {
1010 ExpressionRef lhs = $1;
1011 ExpressionRef rhs = $3;
1012 if (lhs->exprType() != INT_EXPR) {
1013 PARSE_ERR(@1, (String("Left operand of operator '+' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1014 $$ = new IntLiteral(0);
1015 } else if (rhs->exprType() != INT_EXPR) {
1016 PARSE_ERR(@3, (String("Right operand of operator '+' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1017 $$ = new IntLiteral(0);
1018 } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() ||
1019 lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
1020 {
1021 PARSE_ERR(@2, "Operands of '+' operations must have same unit.");
1022 $$ = new IntLiteral(0);
1023 } else {
1024 $$ = new Add(lhs,rhs);
1025 }
1026 }
1027 | add_expr '-' mul_expr {
1028 ExpressionRef lhs = $1;
1029 ExpressionRef rhs = $3;
1030 if (lhs->exprType() != INT_EXPR) {
1031 PARSE_ERR(@1, (String("Left operand of operator '-' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1032 $$ = new IntLiteral(0);
1033 } else if (rhs->exprType() != INT_EXPR) {
1034 PARSE_ERR(@3, (String("Right operand of operator '-' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1035 $$ = new IntLiteral(0);
1036 } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() ||
1037 lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
1038 {
1039 PARSE_ERR(@2, "Operands of '-' operations must have same unit.");
1040 $$ = new IntLiteral(0);
1041 } else {
1042 $$ = new Sub(lhs,rhs);
1043 }
1044 }
1045
1046 mul_expr:
1047 unary_expr
1048 | mul_expr '*' unary_expr {
1049 ExpressionRef lhs = $1;
1050 ExpressionRef rhs = $3;
1051 if (lhs->exprType() != INT_EXPR) {
1052 PARSE_ERR(@1, (String("Left operand of operator '*' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1053 $$ = new IntLiteral(0);
1054 } else if (rhs->exprType() != INT_EXPR) {
1055 PARSE_ERR(@3, (String("Right operand of operator '*' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1056 $$ = new IntLiteral(0);
1057 } else if (lhs->asInt()->unitType() && rhs->asInt()->unitType()) {
1058 PARSE_ERR(@2, "Only one operand of operator '*' may have a unit type");
1059 $$ = new IntLiteral(0);
1060 } else if (lhs->asInt()->unitPrefix(0) && rhs->asInt()->unitPrefix(0)) {
1061 PARSE_ERR(@2, "Only one operand of operator '*' may have a unit prefix");
1062 $$ = new IntLiteral(0);
1063 } else {
1064 $$ = new Mul(lhs,rhs);
1065 }
1066 }
1067 | mul_expr '/' unary_expr {
1068 ExpressionRef lhs = $1;
1069 ExpressionRef rhs = $3;
1070 if (lhs->exprType() != INT_EXPR) {
1071 PARSE_ERR(@1, (String("Left operand of operator '/' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1072 $$ = new IntLiteral(0);
1073 } else if (rhs->exprType() != INT_EXPR) {
1074 PARSE_ERR(@3, (String("Right operand of operator '/' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1075 $$ = new IntLiteral(0);
1076 } else if (lhs->asInt()->unitType() && rhs->asInt()->unitType() &&
1077 lhs->asInt()->unitType() != rhs->asInt()->unitType())
1078 {
1079 PARSE_ERR(@2, "Operands of operator '/' with two different unit types.");
1080 $$ = new IntLiteral(0);
1081 } else if (!lhs->asInt()->unitType() && rhs->asInt()->unitType()) {
1082 PARSE_ERR(@3, ("Dividing left operand without any unit type by right operand with unit type " + typeStr(rhs->exprType()) + " is not possible.").c_str());
1083 $$ = new IntLiteral(0);
1084 } else if (lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor() &&
1085 lhs->asInt()->unitPrefix(0) && rhs->asInt()->unitPrefix(0))
1086 {
1087 PARSE_ERR(@2, "Dividing two operands with two different unit prefixes is not possible.");
1088 $$ = new IntLiteral(0);
1089 } else if (lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor() &&
1090 rhs->asInt()->unitPrefix(0))
1091 {
1092 PARSE_ERR(@3, "Dividing left operand without any unit prefix by right operand with unit prefix is not possible.");
1093 $$ = new IntLiteral(0);
1094 } else {
1095 $$ = new Div(lhs,rhs);
1096 }
1097 }
1098 | mul_expr MOD unary_expr {
1099 ExpressionRef lhs = $1;
1100 ExpressionRef rhs = $3;
1101 if (lhs->exprType() != INT_EXPR) {
1102 PARSE_ERR(@1, (String("Left operand of modulo operator must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
1103 $$ = new IntLiteral(0);
1104 } else if (rhs->exprType() != INT_EXPR) {
1105 PARSE_ERR(@3, (String("Right operand of modulo operator must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1106 $$ = new IntLiteral(0);
1107 } else {
1108 if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0))
1109 PARSE_ERR(@1, "Operands of modulo operator must not use any unit.");
1110 if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0))
1111 PARSE_ERR(@3, "Operands of modulo operator must not use any unit.");
1112 $$ = new Mod(lhs,rhs);
1113 }
1114 }
1115
1116 %%
1117
1118 void InstrScript_error(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* err) {
1119 //fprintf(stderr, "%d: %s\n", locp->first_line, err);
1120 context->addErr(locp->first_line, locp->last_line, locp->first_column+1, locp->last_column+1, err);
1121 }
1122
1123 void InstrScript_warning(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* txt) {
1124 //fprintf(stderr, "WRN %d: %s\n", locp->first_line, txt);
1125 context->addWrn(locp->first_line, locp->last_line, locp->first_column+1, locp->last_column+1, txt);
1126 }
1127
1128 /// Custom implementation of yytnamerr() to ensure quotation is always stripped from token names before printing them to error messages.
1129 int InstrScript_tnamerr(char* yyres, const char* yystr) {
1130 if (*yystr == '"') {
1131 int yyn = 0;
1132 char const *yyp = yystr;
1133 for (;;)
1134 switch (*++yyp)
1135 {
1136 /*
1137 case '\'':
1138 case ',':
1139 goto do_not_strip_quotes;
1140
1141 case '\\':
1142 if (*++yyp != '\\')
1143 goto do_not_strip_quotes;
1144 */
1145 /* Fall through. */
1146 default:
1147 if (yyres)
1148 yyres[yyn] = *yyp;
1149 yyn++;
1150 break;
1151
1152 case '"':
1153 if (yyres)
1154 yyres[yyn] = '\0';
1155 return yyn;
1156 }
1157 /*
1158 do_not_strip_quotes: ;
1159 */
1160 }
1161
1162 if (! yyres)
1163 return (int) yystrlen (yystr);
1164
1165 return int( yystpcpy (yyres, yystr) - yyres );
1166 }

  ViewVC Help
Powered by ViewVC