/[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 3728 - (show annotations) (download)
Wed Jan 29 13:58:33 2020 UTC (4 years, 2 months ago) by schoenebeck
File size: 68922 byte(s)
NKSP: Reduced code for parsing NKSP variable declarations:

* Use 2 generalized grammar rules with optional components (i.e. optional
  value assignment and optional variable qualifiers) instead of previous
  linear combinations of grammar rules, which also fixes some edge case.

* Bumped version (2.1.1.svn44).

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

  ViewVC Help
Powered by ViewVC