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

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

  ViewVC Help
Powered by ViewVC