/[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 3729 - (show annotations) (download)
Fri Jan 31 10:57:53 2020 UTC (4 years, 2 months ago) by schoenebeck
File size: 69158 byte(s)
NKSP parser: track code locations also by raw byte position and length.

* NKSP VM API: Added member variables 'firstByte' and 'lengthBytes' to
  struct 'CodeBlock'.

* NKSP Editor API: Added methods firstByte() and lengthBytes() to
  class 'VMSourceToken'.

* NKSP VM language parser: track all positions also by raw byte offset
  and length (along to the already existing tracking by line/column).

* NKSP editor syntax highlighting scanner: track all positions also by
  raw byte offset and length (along to the already existing tracking by
  line/column).

* Bumped version (2.1.1.svn45).

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

  ViewVC Help
Powered by ViewVC