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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.2951  
changed lines
  Added in v.3728

  ViewVC Help
Powered by ViewVC