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

Legend:
Removed from v.2888  
changed lines
  Added in v.3733

  ViewVC Help
Powered by ViewVC