/[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 3581 - (show annotations) (download)
Fri Aug 30 11:40:25 2019 UTC (4 years, 7 months ago) by schoenebeck
File size: 72220 byte(s)
NKSP: Allow more wider support of standard measuring units & 'final'ness.

* Raised compiler requirement to be C++14 compliant (due to severe
  restrictions regarding C-style aggregate initializer lists in C++11
  which are now massively used throughout the code base).

* NKSP VM API: Allow units and 'final'ness to be returned as result from
  built-in functions (added methods VMFunction::returnUnitType() and
  VMFunction::returnsFinal() for that purpose which must be implemented by
  built-in function implementations).

* NKSP language: Allow metric unit prefixes of numeric scalar and array
  variables to be changed freely at runtime (unlike unit types like Hz etc.
  which are still sticky parse-time features of variables which cannot be
  changed at runtime for the intentional sake of determinism).

* NKSP language: 'final' values are prohibited for array variables for now
  (attempt causes a parsers error).

* NKSP language: expressions with unit types (e.g. Hz) are prohibited for
  conditions of runtime control structures like if(), while(), select()
  (attempt causes a parser error).

* NKSP VM API: Allow built-in functions to perform their own, individual
  parse time checks of arguments going to be passed to the function at
  runtime (added method VMFunction::checkArgs() for that purpose).

* NKSP language: raise parser warning if only one operand of binary
  operators (like logical 'or' comparison) contain a 'final' value (because
  it would always yield in a 'final' result in such cases).

* NKSP language: Allow comparison (=, #, <, >, <=, >=) of values with
  different metric unit prefixes, which will behave as expected (e.g.
  result of expression '1000us < 2ms' is true).

* NKSP language: Allow adding values with different metric unit prefixes
  (e.g. result of expression '100Hz + 5kHz' is '5100Hz').

* NKSP language: Allow subtracting values with different metric unit
  prefixes (e.g. result of expression '1ms - 20us' is '980us').

* NKSP language: Allow multiplying with any metric unit prefixes
  (e.g. result of expression '2k * 3ms' is '6s'), however multiplications
  with unit types on both sides (e.g. '2s * 2s') is still prohibited since
  we don't have any considerable practical use for a term like '4s^2'
  (hence any attempt multiplying two unit types still causes parser error).

* NKSP language: Allow dividing by any metric unit prefixes and allow
  division of same unit type on both sides (e.g. expression '8kHz / 1000Hz'
  yields in unit free result '8'). So this is now a way to cast units away
  e.g. for passing the result to other expressions, certain function calls
  or variables which are not accepting any units (or that specific unit).

* NKSP language: integer arrays and real number arrays can now be converted
  to strings (e.g. for dumping their content with message() calls for
  script debugging purposes).

* NKSP language: expressions and variables with units are now correctly
  casted to strings (e.g. with message() calls).

* NKSP language: comparing real numbers for equalness (e.g. '~foo = 3.1') or
  unequalness (e.g. '~foo # 3.1') is now less strict and takes the expected
  floating point tolerances into account.

* NKSP VM API: Added methods VMScalarNumberExpr::evalCastInt() and
  VMScalarNumberExpr::evalCastReal().

* NKSP VM API: Added base class 'VMNumberArrayExpr' for classes
  'VMIntArrayExpr' and 'VMRealArrayExpr'.

* NKSP VM API: replaced all unitPrefix() (parse time) methods by
  unitFactor() (runtime) methods.

* Built-in function "exit()" supports now returning units and 'final'ness
  exclusively for test cases.

* The following built-in functions support now units as well: "abs()",
  "random()", "inc()", "dec()", "in_range()", "min()", "max()",
  "real_to_int()", "int()", "int_to_real()" and "real()".

* Built-in functions "array_equal()", "search()" and "sort()" support now
  real number arrays (correctly) as well.

* Added individual parse time checks of arguments to be passed to built-in
  functions "random()", "inc()", "dec()", "in_range()", "min()", "max()",
  "array_equal()" and "search()" specific for their individual purposes.

* Test cases: Added massive amount of NKSP test cases for standard
  measuring units and 'final' operator usage cases.

* Test cases: Added NKSP test cases for (floating point tolerance aware)
  real number equalness / unequalness comparison.

* Bumped version (2.1.1.svn8).

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

  ViewVC Help
Powered by ViewVC