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

Legend:
Removed from v.2889  
changed lines
  Added in v.3690

  ViewVC Help
Powered by ViewVC