/[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 2945 by schoenebeck, Thu Jul 14 00:22:26 2016 UTC revision 3561 by schoenebeck, Fri Aug 23 11:44:00 2019 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (c) 2014-2016 Christian Schoenebeck and Andreas Persson   * Copyright (c) 2014-2017 Christian Schoenebeck and Andreas Persson
3   *   *
4   * http://www.linuxsampler.org   * http://www.linuxsampler.org
5   *   *
# Line 18  Line 18 
18    
19      void InstrScript_error(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* err);      void InstrScript_error(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* err);
20      void InstrScript_warning(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* txt);      void InstrScript_warning(YYLTYPE* locp, LinuxSampler::ParserContext* context, const char* txt);
21        int InstrScript_tnamerr(char* yyres, const char* yystr);
22      int InstrScript_lex(YYSTYPE* lvalp, YYLTYPE* llocp, void* scanner);      int InstrScript_lex(YYSTYPE* lvalp, YYLTYPE* llocp, void* scanner);
23      #define scanner context->scanner      #define scanner context->scanner
24      #define PARSE_ERR(loc,txt)  yyerror(&loc, context, txt)      #define PARSE_ERR(loc,txt)  yyerror(&loc, context, txt)
25      #define PARSE_WRN(loc,txt)  InstrScript_warning(&loc, context, txt)      #define PARSE_WRN(loc,txt)  InstrScript_warning(&loc, context, txt)
26        #define PARSE_DROP(loc)     context->addPreprocessorComment(loc.first_line, loc.last_line, loc.first_column+1, loc.last_column+1);
27        #define yytnamerr(res,str)  InstrScript_tnamerr(res, str)
28  %}  %}
29    
30  // generate reentrant safe parser  // generate reentrant safe parser
# Line 29  Line 32 
32  %parse-param { LinuxSampler::ParserContext* context }  %parse-param { LinuxSampler::ParserContext* context }
33  %lex-param { void* scanner }  %lex-param { void* scanner }
34  // avoid symbol collision with other (i.e. future) auto generated (f)lex scanners  // avoid symbol collision with other (i.e. future) auto generated (f)lex scanners
35  %name-prefix "InstrScript_"  // (NOTE: "=" is deprecated here with Bison 3.x, however removing it would cause an error with Bison 2.x)
36    %name-prefix="InstrScript_"
37  %locations  %locations
38  %defines  %defines
39  %error-verbose  %error-verbose
40    
41  %token <iValue> INTEGER  %token <iValue> INTEGER "integer literal"
42  %token <sValue> STRING  %token <iUnitValue> INTEGER_UNIT "integer literal with unit"
43  %token <sValue> IDENTIFIER  %token <sValue> STRING "string literal"
44  %token <sValue> VARIABLE  %token <sValue> IDENTIFIER "function name"
45  %token ON END INIT NOTE DECLARE ASSIGNMENT WHILE IF OR RELEASE AND ELSE  %token <sValue> VARIABLE "variable name"
46  %token BITWISE_OR BITWISE_AND BITWISE_NOT  %token ON "keyword 'on'"
47  %token CONTROLLER SELECT CASE TO NOT CONST_ POLYPHONIC MOD  %token END "keyword 'end'"
48  %token LE GE  %token INIT "keyword 'init'"
49    %token NOTE "keyword 'note'"
50  %type <nEventHandlers> script eventhandlers  %token RELEASE "keyword 'release'"
51  %type <nEventHandler> eventhandler  %token CONTROLLER "keyword 'controller'"
52  %type <nStatements> statements body  %token DECLARE "keyword 'declare'"
53    %token ASSIGNMENT "operator ':='"
54    %token CONST_ "keyword 'const'"
55    %token POLYPHONIC "keyword 'polyphonic'"
56    %token WHILE "keyword 'while'"
57    %token SYNCHRONIZED "keyword 'synchronized'"
58    %token IF "keyword 'if'"
59    %token ELSE "keyword 'else'"
60    %token SELECT "keyword 'select'"
61    %token CASE "keyword 'case'"
62    %token TO "keyword 'to'"
63    %token OR "operator 'or'"
64    %token AND "operator 'and'"
65    %token NOT "operator 'not'"
66    %token BITWISE_OR "bitwise operator '.or.'"
67    %token BITWISE_AND "bitwise operator '.and.'"
68    %token BITWISE_NOT "bitwise operator '.not.'"
69    %token FUNCTION "keyword 'function'"
70    %token CALL "keyword 'call'"
71    %token MOD "operator 'mod'"
72    %token LE "operator '<='"
73    %token GE "operator '>='"
74    %token END_OF_FILE 0 "end of file"
75    %token UNKNOWN_CHAR "unknown character"
76    
77    %type <nEventHandlers> script sections
78    %type <nEventHandler> section eventhandler
79    %type <nStatements> statements opt_statements userfunctioncall
80  %type <nStatement> statement assignment  %type <nStatement> statement assignment
81  %type <nFunctionCall> functioncall  %type <nFunctionCall> functioncall
82  %type <nArgs> args  %type <nArgs> args
# Line 58  Line 89 
89  %%  %%
90    
91  script:  script:
92      eventhandlers  {      sections  {
93          $$ = context->handlers = $1;          $$ = context->handlers = $1;
94      }      }
95    
96  eventhandlers:  sections:
97      eventhandler  {      section  {
98          $$ = new EventHandlers();          $$ = new EventHandlers();
99          $$->add($1);          if ($1) $$->add($1);
100        }
101        | sections section  {
102            $$ = $1;
103            if ($2) $$->add($2);
104        }
105    
106    section:
107        function_declaration  {
108            $$ = EventHandlerRef();
109      }      }
110      | eventhandlers eventhandler  {      | eventhandler  {
111          $$ = $1;          $$ = $1;
         $$->add($2);  
112      }      }
113    
114  eventhandler:  eventhandler:
115      ON NOTE body END ON  {      ON NOTE opt_statements END ON  {
116          if (context->onNote)          if (context->onNote)
117              PARSE_ERR(@2, "Redeclaration of 'note' event handler.");              PARSE_ERR(@2, "Redeclaration of 'note' event handler.");
118          context->onNote = new OnNote($3);          context->onNote = new OnNote($3);
119          $$ = context->onNote;          $$ = context->onNote;
120      }      }
121      | ON INIT body END ON  {      | ON INIT opt_statements END ON  {
122          if (context->onInit)          if (context->onInit)
123              PARSE_ERR(@2, "Redeclaration of 'init' event handler.");              PARSE_ERR(@2, "Redeclaration of 'init' event handler.");
124          context->onInit = new OnInit($3);          context->onInit = new OnInit($3);
125          $$ = context->onInit;          $$ = context->onInit;
126      }      }
127      | ON RELEASE body END ON  {      | ON RELEASE opt_statements END ON  {
128          if (context->onRelease)          if (context->onRelease)
129              PARSE_ERR(@2, "Redeclaration of 'release' event handler.");              PARSE_ERR(@2, "Redeclaration of 'release' event handler.");
130          context->onRelease = new OnRelease($3);          context->onRelease = new OnRelease($3);
131          $$ = context->onRelease;          $$ = context->onRelease;
132      }      }
133      | ON CONTROLLER body END ON  {      | ON CONTROLLER opt_statements END ON  {
134          if (context->onController)          if (context->onController)
135              PARSE_ERR(@2, "Redeclaration of 'controller' event handler.");              PARSE_ERR(@2, "Redeclaration of 'controller' event handler.");
136          context->onController = new OnController($3);          context->onController = new OnController($3);
137          $$ = context->onController;          $$ = context->onController;
138      }      }
139    
140  body:  function_declaration:
141        FUNCTION IDENTIFIER opt_statements END FUNCTION  {
142            const char* name = $2;
143            if (context->functionProvider->functionByName(name)) {
144                PARSE_ERR(@2, (String("There is already a built-in function with name '") + name + "'.").c_str());
145            } else if (context->userFunctionByName(name)) {
146                PARSE_ERR(@2, (String("There is already a user defined function with name '") + name + "'.").c_str());
147            } else {
148                context->userFnTable[name] = $3;
149            }
150        }
151    
152    opt_statements:
153      /* epsilon (empty argument) */  {      /* epsilon (empty argument) */  {
154          $$ = new Statements();          $$ = new Statements();
155      }      }
# Line 126  statement: Line 177  statement:
177      functioncall  {      functioncall  {
178          $$ = $1;          $$ = $1;
179      }      }
180        | userfunctioncall  {
181            $$ = $1;
182        }
183      | DECLARE VARIABLE  {      | DECLARE VARIABLE  {
184          const char* name = $2;          const char* name = $2;
185          //printf("declared var '%s'\n", name);          //printf("declared var '%s'\n", name);
# Line 175  statement: Line 229  statement:
229              if (name[0] == '@')              if (name[0] == '@')
230                  PARSE_WRN(@2, (String("Variable '") + name + "' declared as string, integer expression assigned though.").c_str());                  PARSE_WRN(@2, (String("Variable '") + name + "' declared as string, integer expression assigned though.").c_str());
231              IntExprRef expr = $4;              IntExprRef expr = $4;
232                IntVariableRef var = new IntVariable(context);
233              if (expr->isConstExpr()) {              if (expr->isConstExpr()) {
234                  const int i = expr->evalInt();                  const vmint i = expr->evalInt();
                 IntVariableRef var = new IntVariable(context);  
                 context->vartable[name] = var;  
235                  $$ = new Assignment(var, new IntLiteral(i));                  $$ = new Assignment(var, new IntLiteral(i));
236              } else {              } else {
                 IntVariableRef var = new IntVariable(context);  
                 context->vartable[name] = var;  
237                  $$ = new Assignment(var, expr);                  $$ = new Assignment(var, expr);
238              }              }
239                var->copyUnitFrom(expr);
240                var->setFinal(expr->isFinal());
241                context->vartable[name] = var;
242          }          }
243      }      }
244      | DECLARE VARIABLE '[' expr ']'  {      | DECLARE VARIABLE '[' expr ']'  {
# Line 201  statement: Line 255  statement:
255              $$ = new FunctionCall("nothing", new Args, NULL); // whatever              $$ = new FunctionCall("nothing", new Args, NULL); // whatever
256          } else {          } else {
257              IntExprRef expr = $4;              IntExprRef expr = $4;
258              int size = expr->evalInt();              if (expr->unitType() || expr->unitPrefix(0)) {
259              if (size <= 0) {                  PARSE_ERR(@4, "Units are not allowed as array size.");
                 PARSE_ERR(@4, (String("Array variable '") + name + "' declared with array size " + ToString(size) + ".").c_str());  
260                  $$ = new FunctionCall("nothing", new Args, NULL); // whatever                  $$ = new FunctionCall("nothing", new Args, NULL); // whatever
261              } else {              } else {
262                  context->vartable[name] = new IntArrayVariable(context, size);                  if (expr->isFinal())
263                  $$ = new NoOperation;                      PARSE_WRN(@4, "Final operator '!' is meaningless here.");
264                    vmint size = expr->evalInt();
265                    if (size <= 0) {
266                        PARSE_ERR(@4, (String("Array variable '") + name + "' declared with array size " + ToString(size) + ".").c_str());
267                        $$ = new FunctionCall("nothing", new Args, NULL); // whatever
268                    } else {
269                        context->vartable[name] = new IntArrayVariable(context, size);
270                        $$ = new NoOperation;
271                    }
272              }              }
273          }          }
274      }      }
# Line 225  statement: Line 286  statement:
286          } else {          } else {
287              IntExprRef sizeExpr = $4;              IntExprRef sizeExpr = $4;
288              ArgsRef args = $8;              ArgsRef args = $8;
289              int size = sizeExpr->evalInt();              vmint size = sizeExpr->evalInt();
290              if (size <= 0) {              if (size <= 0) {
291                  PARSE_ERR(@4, (String("Array variable '") + name + "' must be declared with positive array size.").c_str());                  PARSE_ERR(@4, (String("Array variable '") + name + "' must be declared with positive array size.").c_str());
292                  $$ = new FunctionCall("nothing", new Args, NULL); // whatever                  $$ = new FunctionCall("nothing", new Args, NULL); // whatever
293              } else if (args->argsCount() > size) {              } else if (args->argsCount() > size) {
294                  PARSE_ERR(@8, (String("Variable '") + name +                  PARSE_ERR(@8, (String("Array variable '") + name +
295                            "' was declared with size " + ToString(size) +                            "' was declared with size " + ToString(size) +
296                            " but " + ToString(args->argsCount()) +                            " but " + ToString(args->argsCount()) +
297                            " values were assigned." ).c_str());                            " values were assigned." ).c_str());
298                  $$ = new FunctionCall("nothing", new Args, NULL); // whatever                            $$ = new FunctionCall("nothing", new Args, NULL); // whatever
299                } else if (sizeExpr->unitType() || sizeExpr->unitPrefix(0)) {
300                    PARSE_ERR(@4, "Units are not allowed as array size.");
301                    $$ = new FunctionCall("nothing", new Args, NULL); // whatever
302              } else {              } else {
303                    if (sizeExpr->isFinal())
304                        PARSE_WRN(@4, "Final operator '!' is meaningless here.");
305                  bool argsOK = true;                  bool argsOK = true;
306                  for (int i = 0; i < args->argsCount(); ++i) {                  for (vmint i = 0; i < args->argsCount(); ++i) {
307                      if (args->arg(i)->exprType() != INT_EXPR) {                      if (args->arg(i)->exprType() != INT_EXPR) {
308                          PARSE_ERR(                          PARSE_ERR(
309                              @8,                              @8,
# Line 247  statement: Line 313  statement:
313                          );                          );
314                          argsOK = false;                          argsOK = false;
315                          break;                          break;
316                        } else if (args->arg(i)->asInt()->unitType() ||
317                                   args->arg(i)->asInt()->unitPrefix(0))
318                        {
319                            PARSE_ERR(
320                                @8,
321                                (String("Array variable '") + name +
322                                "' declared with invalid assignment values. Assigned element " +
323                                ToString(i+1) + " contains a unit.").c_str()
324                            );
325                            argsOK = false;
326                            break;
327                        }
328                    }
329                    if (argsOK) {
330                        context->vartable[name] = new IntArrayVariable(context, size, args);
331                        $$ = new NoOperation;
332                    } else
333                        $$ = new FunctionCall("nothing", new Args, NULL); // whatever
334                }
335            }
336        }
337        | DECLARE CONST_ VARIABLE '[' expr ']' ASSIGNMENT '(' args ')'  {
338            const char* name = $3;
339            if (!$5->isConstExpr()) {
340                PARSE_ERR(@5, (String("Array variable '") + name + "' must be declared with constant array size.").c_str());
341                $$ = new FunctionCall("nothing", new Args, NULL); // whatever
342            } else if ($5->exprType() != INT_EXPR) {
343                PARSE_ERR(@5, (String("Size of array variable '") + name + "' declared with non integer expression.").c_str());
344                $$ = new FunctionCall("nothing", new Args, NULL); // whatever
345            } else if (context->variableByName(name)) {
346                PARSE_ERR(@3, (String("Redeclaration of variable '") + name + "'.").c_str());
347                $$ = new FunctionCall("nothing", new Args, NULL); // whatever
348            } else {
349                IntExprRef sizeExpr = $5;
350                ArgsRef args = $9;
351                vmint size = sizeExpr->evalInt();
352                if (size <= 0) {
353                    PARSE_ERR(@5, (String("Array variable '") + name + "' must be declared with positive array size.").c_str());
354                    $$ = new FunctionCall("nothing", new Args, NULL); // whatever
355                } else if (args->argsCount() > size) {
356                    PARSE_ERR(@9, (String("Array variable '") + name +
357                              "' was declared with size " + ToString(size) +
358                              " but " + ToString(args->argsCount()) +
359                              " values were assigned." ).c_str());
360                    $$ = new FunctionCall("nothing", new Args, NULL); // whatever
361                } else if (sizeExpr->unitType() || sizeExpr->unitPrefix(0)) {
362                    PARSE_ERR(@5, "Units are not allowed as array size.");
363                    $$ = new FunctionCall("nothing", new Args, NULL); // whatever
364                } else {
365                    if (sizeExpr->isFinal())
366                        PARSE_WRN(@5, "Final operator '!' is meaningless here.");
367                    bool argsOK = true;
368                    for (vmint i = 0; i < args->argsCount(); ++i) {
369                        if (args->arg(i)->exprType() != INT_EXPR) {
370                            PARSE_ERR(
371                                @9,
372                                (String("Array variable '") + name +
373                                "' declared with invalid assignment values. Assigned element " +
374                                ToString(i+1) + " is not an integer expression.").c_str()
375                            );
376                            argsOK = false;
377                            break;
378                        }
379                        if (!args->arg(i)->isConstExpr()) {
380                            PARSE_ERR(
381                                @9,
382                                (String("const array variable '") + name +
383                                "' must be defined with const values. Assigned element " +
384                                ToString(i+1) + " is not a const expression though.").c_str()
385                            );
386                            argsOK = false;
387                            break;
388                        } else if (args->arg(i)->asInt()->unitType() ||
389                                   args->arg(i)->asInt()->unitPrefix(0))
390                        {
391                            PARSE_ERR(
392                                @9,
393                                (String("const array variable '") + name +
394                                "' declared with invalid assignment values. Assigned element " +
395                                ToString(i+1) + " contains a unit.").c_str()
396                            );
397                            argsOK = false;
398                            break;
399                      }                      }
400                  }                  }
401                  if (argsOK)                  if (argsOK) {
402                      $$ = context->vartable[name] = new IntArrayVariable(context, size, args);                      context->vartable[name] = new IntArrayVariable(context, size, args, true);
403                  else                      $$ = new NoOperation;
404                    } else
405                      $$ = new FunctionCall("nothing", new Args, NULL); // whatever                      $$ = new FunctionCall("nothing", new Args, NULL); // whatever
406              }              }
407          }          }
# Line 274  statement: Line 424  statement:
424          } else {          } else {
425              if (name[0] == '@')              if (name[0] == '@')
426                  PARSE_WRN(@5, "Variable declared as string, integer expression assigned though.");                  PARSE_WRN(@5, "Variable declared as string, integer expression assigned though.");
427              int i = 0;              vmint i = 0;
428              IntExprRef expr = $5;              IntExprRef expr = $5;
429              if (expr->isConstExpr())              if (expr->isConstExpr())
430                  i = expr->evalInt();                  i = expr->evalInt();
431              else              else
432                  PARSE_ERR(@5, (String("Assignment to const integer variable '") + name + "' requires const expression.").c_str());                  PARSE_ERR(@5, (String("Assignment to const integer variable '") + name + "' requires const expression.").c_str());
433              ConstIntVariableRef var = new ConstIntVariable(i);              ConstIntVariableRef var = new ConstIntVariable(i);
434                var->copyUnitFrom(expr);
435                var->setFinal(expr->isFinal());
436              context->vartable[name] = var;              context->vartable[name] = var;
437              //$$ = new Assignment(var, new IntLiteral(i));              //$$ = new Assignment(var, new IntLiteral(i));
438              $$ = new NoOperation();              $$ = new NoOperation();
# Line 289  statement: Line 441  statement:
441      | assignment  {      | assignment  {
442          $$ = $1;          $$ = $1;
443      }      }
444      | WHILE '(' expr ')' statements END WHILE  {      | WHILE '(' expr ')' opt_statements END WHILE  {
445          if ($3->exprType() == INT_EXPR) {          if ($3->exprType() == INT_EXPR) {
446              $$ = new While($3, $5);              IntExprRef expr = $3;
447                if (expr->isFinal() && expr->isConstExpr())
448                    PARSE_WRN(@3, "Final operator '!' is meaningless here.");
449                $$ = new While(expr, $5);
450          } else {          } else {
451              PARSE_ERR(@3, "Condition for 'while' loops must be integer expression.");              PARSE_ERR(@3, "Condition for 'while' loops must be integer expression.");
452              $$ = new While(new IntLiteral(0), $5);              $$ = new While(new IntLiteral(0), $5);
453          }          }
454      }      }
455      | IF '(' expr ')' statements ELSE statements END IF  {      | SYNCHRONIZED opt_statements END SYNCHRONIZED  {
456          $$ = new If($3, $5, $7);          $$ = new SyncBlock($2);
457      }      }
458      | IF '(' expr ')' statements END IF  {      | IF '(' expr ')' opt_statements ELSE opt_statements END IF  {
459          $$ = new If($3, $5);          if ($3->exprType() == INT_EXPR) {
460                IntExprRef expr = $3;
461                if (expr->isFinal() && expr->isConstExpr())
462                    PARSE_WRN(@3, "Final operator '!' is meaningless here.");
463                $$ = new If($3, $5, $7);
464            } else {
465                PARSE_ERR(@3, "Condition for 'if' must be integer expression.");
466                $$ = new If(new IntLiteral(0), $5, $7);
467            }
468        }
469        | IF '(' expr ')' opt_statements END IF  {
470            if ($3->exprType() == INT_EXPR) {
471                IntExprRef expr = $3;
472                if (expr->isFinal() && expr->isConstExpr())
473                    PARSE_WRN(@3, "Final operator '!' is meaningless here.");
474                $$ = new If($3, $5);
475            } else {
476                PARSE_ERR(@3, "Condition for 'if' must be integer expression.");
477                $$ = new If(new IntLiteral(0), $5);
478            }
479      }      }
480      | SELECT expr caseclauses END SELECT  {      | SELECT expr caseclauses END SELECT  {
481          if ($2->exprType() == INT_EXPR) {          if ($2->exprType() == INT_EXPR) {
482              $$ = new SelectCase($2, $3);              IntExprRef expr = $2;
483                if (expr->unitType() || expr->unitPrefix(0)) {
484                    PARSE_ERR(@2, "Units are not allowed here.");
485                } else {
486                    if (expr->isFinal() && expr->isConstExpr())
487                        PARSE_WRN(@2, "Final operator '!' is meaningless here.");
488                    $$ = new SelectCase(expr, $3);
489                }
490          } else {          } else {
491              PARSE_ERR(@2, "Statement 'select' can only by applied to integer expressions.");              PARSE_ERR(@2, "Statement 'select' can only by applied to integer expressions.");
492              $$ = new SelectCase(new IntLiteral(0), $3);              $$ = new SelectCase(new IntLiteral(0), $3);
# Line 323  caseclauses: Line 504  caseclauses:
504      }      }
505    
506  caseclause:  caseclause:
507      CASE INTEGER statements  {      CASE INTEGER opt_statements  {
508          $$ = CaseBranch();          $$ = CaseBranch();
509          $$.from = new IntLiteral($2);          $$.from = new IntLiteral($2);
510          $$.statements = $3;          $$.statements = $3;
511      }      }
512      | CASE INTEGER TO INTEGER statements  {      | CASE INTEGER TO INTEGER opt_statements  {
513          $$ = CaseBranch();          $$ = CaseBranch();
514          $$.from = new IntLiteral($2);          $$.from = new IntLiteral($2);
515          $$.to   = new IntLiteral($4);          $$.to   = new IntLiteral($4);
516          $$.statements = $5;          $$.statements = $5;
517      }      }
518    
519    userfunctioncall:
520        CALL IDENTIFIER  {
521            const char* name = $2;
522            StatementsRef fn = context->userFunctionByName(name);
523            if (context->functionProvider->functionByName(name)) {
524                PARSE_ERR(@1, (String("Keyword 'call' must only be used for user defined functions, not for any built-in function like '") + name + "'.").c_str());
525                $$ = StatementsRef();
526            } else if (!fn) {
527                PARSE_ERR(@2, (String("No user defined function with name '") + name + "'.").c_str());
528                $$ = StatementsRef();
529            } else {
530                $$ = fn;
531            }
532        }
533    
534  functioncall:  functioncall:
535      IDENTIFIER '(' args ')'  {      IDENTIFIER '(' args ')'  {
536          const char* name = $1;          const char* name = $1;
537          //printf("function call of '%s' with args\n", name);          //printf("function call of '%s' with args\n", name);
538          ArgsRef args = $3;          ArgsRef args = $3;
539          VMFunction* fn = context->functionProvider->functionByName(name);          VMFunction* fn = context->functionProvider->functionByName(name);
540          if (!fn) {          if (context->userFunctionByName(name)) {
541                PARSE_ERR(@1, (String("Missing 'call' keyword before user defined function name '") + name + "'.").c_str());
542                $$ = new FunctionCall(name, args, NULL);
543            } else if (!fn) {
544              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());
545              $$ = new FunctionCall(name, args, NULL);              $$ = new FunctionCall(name, args, NULL);
546            } else if (context->functionProvider->isFunctionDisabled(fn,context)) {
547                PARSE_DROP(@$);
548                $$ = new NoFunctionCall;
549          } else if (args->argsCount() < fn->minRequiredArgs()) {          } else if (args->argsCount() < fn->minRequiredArgs()) {
550              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());
551              $$ = new FunctionCall(name, args, NULL);              $$ = new FunctionCall(name, args, NULL);
# Line 352  functioncall: Line 554  functioncall:
554              $$ = new FunctionCall(name, args, NULL);              $$ = new FunctionCall(name, args, NULL);
555          } else {          } else {
556              bool argsOK = true;              bool argsOK = true;
557              for (int i = 0; i < args->argsCount(); ++i) {              for (vmint i = 0; i < args->argsCount(); ++i) {
558                  if (args->arg(i)->exprType() != fn->argType(i) && !fn->acceptsArgType(i, args->arg(i)->exprType())) {                  if (args->arg(i)->exprType() != fn->argType(i) && !fn->acceptsArgType(i, args->arg(i)->exprType())) {
559                      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 " + typeStr(fn->argType(i)) + " type, but type " + typeStr(args->arg(i)->exprType()) + " was given instead.").c_str());
560                      argsOK = false;                      argsOK = false;
# Line 361  functioncall: Line 563  functioncall:
563                      PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' expects an assignable variable.").c_str());                      PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' expects an assignable variable.").c_str());
564                      argsOK = false;                      argsOK = false;
565                      break;                      break;
566                    } else if (args->arg(i)->exprType() == INT_EXPR && !fn->acceptsArgUnitType(i, args->arg(i)->asInt()->unitType())) {
567                        if (args->arg(i)->asInt()->unitType())
568                            PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' does not expect unit " + unitTypeStr(args->arg(i)->asInt()->unitType()) +  ".").c_str());
569                        else
570                            PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' expects a unit.").c_str());
571                        argsOK = false;
572                        break;
573                    } else if (!fn->acceptsArgUnitPrefix(i) && args->arg(i)->exprType() == INT_EXPR && args->arg(i)->asInt()->unitPrefix(0)) {
574                        PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' does not expect a unit prefix.").c_str());
575                        argsOK = false;
576                        break;
577                    } else if (!fn->acceptsArgFinal(i) && args->arg(i)->exprType() == INT_EXPR && args->arg(i)->asInt()->isFinal()) {
578                        PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' does not expect a \"final\" value.").c_str());
579                        argsOK = false;
580                        break;
581                  }                  }
582              }              }
583              $$ = new FunctionCall(name, args, argsOK ? fn : NULL);              $$ = new FunctionCall(name, args, argsOK ? fn : NULL);
# Line 371  functioncall: Line 588  functioncall:
588          //printf("function call of '%s' (with empty args)\n", name);          //printf("function call of '%s' (with empty args)\n", name);
589          ArgsRef args = new Args;          ArgsRef args = new Args;
590          VMFunction* fn = context->functionProvider->functionByName(name);          VMFunction* fn = context->functionProvider->functionByName(name);
591          if (!fn) {          if (context->userFunctionByName(name)) {
592                PARSE_ERR(@1, (String("Missing 'call' keyword before user defined function name '") + name + "'.").c_str());
593                $$ = new FunctionCall(name, args, NULL);
594            } else if (!fn) {
595              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());
596              $$ = new FunctionCall(name, args, NULL);              $$ = new FunctionCall(name, args, NULL);
597            } else if (context->functionProvider->isFunctionDisabled(fn,context)) {
598                PARSE_DROP(@$);
599                $$ = new NoFunctionCall;
600          } else if (fn->minRequiredArgs() > 0) {          } else if (fn->minRequiredArgs() > 0) {
601              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());
602              $$ = new FunctionCall(name, args, NULL);              $$ = new FunctionCall(name, args, NULL);
# Line 386  functioncall: Line 609  functioncall:
609          //printf("function call of '%s' (without args)\n", name);          //printf("function call of '%s' (without args)\n", name);
610          ArgsRef args = new Args;          ArgsRef args = new Args;
611          VMFunction* fn = context->functionProvider->functionByName(name);          VMFunction* fn = context->functionProvider->functionByName(name);
612          if (!fn) {          if (context->userFunctionByName(name)) {
613                PARSE_ERR(@1, (String("Missing 'call' keyword before user defined function name '") + name + "'.").c_str());
614                $$ = new FunctionCall(name, args, NULL);
615            } else if (!fn) {
616              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());
617              $$ = new FunctionCall(name, args, NULL);              $$ = new FunctionCall(name, args, NULL);
618            } else if (context->functionProvider->isFunctionDisabled(fn,context)) {
619                PARSE_DROP(@$);
620                $$ = new NoFunctionCall;
621          } else if (fn->minRequiredArgs() > 0) {          } else if (fn->minRequiredArgs() > 0) {
622              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());
623              $$ = new FunctionCall(name, args, NULL);              $$ = new FunctionCall(name, args, NULL);
# Line 423  assignment: Line 652  assignment:
652              PARSE_ERR(@2, (String("Variable assignment: Variable '") + name + "' is not assignable.").c_str());              PARSE_ERR(@2, (String("Variable assignment: Variable '") + name + "' is not assignable.").c_str());
653          else if (var->exprType() != $3->exprType())          else if (var->exprType() != $3->exprType())
654              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());
655            else if (var->exprType() == INT_EXPR) {
656                IntVariableRef intVar = var;
657                IntExprRef expr = $3;
658                if (intVar->unitType() != expr->unitType())
659                    PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' has unit type " + unitTypeStr(intVar->unitType()) + ", assignment has unit type " + unitTypeStr(expr->unitType()) + " though.").c_str());
660                else if (intVar->unitFactor() != expr->unitFactor())
661                    PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' has a different unit prefix.").c_str());
662                else if (intVar->isFinal() != expr->isFinal())
663                    PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' was declared as " + String(intVar->isFinal() ? "final" : "not final") + ", assignment is " + String(expr->isFinal() ? "final" : "not final") + " though.").c_str());
664            }
665          $$ = new Assignment(var, $3);          $$ = new Assignment(var, $3);
666      }      }
667      | VARIABLE '[' expr ']' ASSIGNMENT expr  {      | VARIABLE '[' expr ']' ASSIGNMENT expr  {
# Line 432  assignment: Line 671  assignment:
671              PARSE_ERR(@1, (String("No variable declared with name '") + name + "'.").c_str());              PARSE_ERR(@1, (String("No variable declared with name '") + name + "'.").c_str());
672          else if (var->exprType() != INT_ARR_EXPR)          else if (var->exprType() != INT_ARR_EXPR)
673              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());
674            else if (var->isConstExpr())
675                PARSE_ERR(@5, (String("Variable assignment: Cannot modify const array variable '") + name + "'.").c_str());
676            else if (!var->isAssignable())
677                PARSE_ERR(@5, (String("Variable assignment: Array variable '") + name + "' is not assignable.").c_str());
678          else if ($3->exprType() != INT_EXPR)          else if ($3->exprType() != INT_EXPR)
679              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());
680            else if ($3->asInt()->unitType())
681                PARSE_ERR(@3, "Unit types are not allowed as array index.");
682          else if ($6->exprType() != INT_EXPR)          else if ($6->exprType() != INT_EXPR)
683              PARSE_ERR(@5, (String("Value assigned to array variable '") + name + "' must be an integer expression.").c_str());              PARSE_ERR(@5, (String("Value assigned to array variable '") + name + "' must be an integer expression.").c_str());
684            else if ($6->asInt()->unitType())
685                PARSE_ERR(@6, "Unit types are not allowed for array variables.");
686            else if ($6->asInt()->isFinal())
687                PARSE_ERR(@6, "Final operator '!' not allowed for array variables.");
688            else if ($3->isConstExpr() && $3->asInt()->evalInt() >= ((IntArrayVariableRef)var)->arraySize())
689                PARSE_WRN(@3, (String("Index ") + ToString($3->asInt()->evalInt()) +
690                              " exceeds size of array variable '" + name +
691                              "' which was declared with size " +
692                              ToString(((IntArrayVariableRef)var)->arraySize()) + ".").c_str());
693            else if ($3->asInt()->isFinal())
694                PARSE_WRN(@3, "Final operator '!' is meaningless here.");
695          IntArrayElementRef element = new IntArrayElement(var, $3);          IntArrayElementRef element = new IntArrayElement(var, $3);
696          $$ = new Assignment(element, $6);          $$ = new Assignment(element, $6);
697      }      }
# Line 444  unary_expr: Line 700  unary_expr:
700      INTEGER  {      INTEGER  {
701          $$ = new IntLiteral($1);          $$ = new IntLiteral($1);
702      }      }
703        | INTEGER_UNIT  {
704            IntLiteralRef literal = new IntLiteral($1.iValue);
705            literal->setUnit($1.prefix, $1.unit);
706            $$ = literal;
707        }
708      | STRING    {      | STRING    {
709          $$ = new StringLiteral($1);          $$ = new StringLiteral($1);
710      }      }
# Line 469  unary_expr: Line 730  unary_expr:
730          } else if ($3->exprType() != INT_EXPR) {          } else if ($3->exprType() != INT_EXPR) {
731              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());
732              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
733            } else if ($3->asInt()->unitType() || $3->asInt()->unitPrefix(0)) {
734                PARSE_ERR(@3, "Units are not allowed as array index.");
735                $$ = new IntLiteral(0);
736          } else {          } else {
737                if ($3->isConstExpr() && $3->asInt()->evalInt() >= ((IntArrayVariableRef)var)->arraySize())
738                    PARSE_WRN(@3, (String("Index ") + ToString($3->asInt()->evalInt()) +
739                                   " exceeds size of array variable '" + name +
740                                   "' which was declared with size " +
741                                   ToString(((IntArrayVariableRef)var)->arraySize()) + ".").c_str());
742                else if ($3->asInt()->isFinal())
743                    PARSE_WRN(@3, "Final operator '!' is meaningless here.");
744              $$ = new IntArrayElement(var, $3);              $$ = new IntArrayElement(var, $3);
745          }          }
746      }      }
# Line 486  unary_expr: Line 757  unary_expr:
757          if ($2->exprType() != INT_EXPR) {          if ($2->exprType() != INT_EXPR) {
758              PARSE_ERR(@2, (String("Right operand of bitwise operator '.not.' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str());              PARSE_ERR(@2, (String("Right operand of bitwise operator '.not.' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str());
759              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
760            } else if ($2->asInt()->unitType() || $2->asInt()->unitPrefix(0)) {
761                PARSE_ERR(@2, "Units are not allowed for operands of bitwise operations.");
762                $$ = new IntLiteral(0);
763          } else {          } else {
764              $$ = new BitwiseNot($2);              $$ = new BitwiseNot($2);
765          }          }
# Line 494  unary_expr: Line 768  unary_expr:
768          if ($2->exprType() != INT_EXPR) {          if ($2->exprType() != INT_EXPR) {
769              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());
770              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
771            } else if ($2->asInt()->unitType() || $2->asInt()->unitPrefix(0)) {
772                PARSE_ERR(@2, "Units are not allowed for operands of logical operations.");
773                $$ = new IntLiteral(0);
774          } else {          } else {
775              $$ = new Not($2);              $$ = new Not($2);
776          }          }
777      }      }
778        | '!' unary_expr  {
779            if ($2->exprType() != INT_EXPR) {
780                PARSE_ERR(@2, (String("Right operand of \"final\" operator '!' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str());
781                $$ = new IntLiteral(0);
782            } else {
783                $$ = new Final($2);
784            }
785        }
786    
787  expr:  expr:
788      concat_expr      concat_expr
# Line 527  logical_or_expr: Line 812  logical_or_expr:
812          } else if (rhs->exprType() != INT_EXPR) {          } else if (rhs->exprType() != INT_EXPR) {
813              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());
814              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
815            } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) {
816                PARSE_ERR(@1, "Units are not allowed for operands of logical operations.");
817                $$ = new IntLiteral(0);
818            } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) {
819                PARSE_ERR(@3, "Units are not allowed for operands of logical operations.");
820                $$ = new IntLiteral(0);
821          } else {          } else {
822              $$ = new Or(lhs, rhs);              $$ = new Or(lhs, rhs);
823          }          }
# Line 545  logical_and_expr: Line 836  logical_and_expr:
836          } else if (rhs->exprType() != INT_EXPR) {          } else if (rhs->exprType() != INT_EXPR) {
837              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());
838              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
839            } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) {
840                PARSE_ERR(@1, "Units are not allowed for operands of logical operations.");
841                $$ = new IntLiteral(0);
842            } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) {
843                PARSE_ERR(@3, "Units are not allowed for operands of logical operations.");
844                $$ = new IntLiteral(0);
845          } else {          } else {
846              $$ = new And(lhs, rhs);              $$ = new And(lhs, rhs);
847          }          }
# Line 561  bitwise_or_expr: Line 858  bitwise_or_expr:
858          } else if (rhs->exprType() != INT_EXPR) {          } else if (rhs->exprType() != INT_EXPR) {
859              PARSE_ERR(@3, (String("Right operand of bitwise operator '.or.' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());              PARSE_ERR(@3, (String("Right operand of bitwise operator '.or.' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
860              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
861            } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) {
862                PARSE_ERR(@1, "Units are not allowed for operands of bitwise operations.");
863                $$ = new IntLiteral(0);
864            } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) {
865                PARSE_ERR(@3, "Units are not allowed for operands of bitwise operations.");
866                $$ = new IntLiteral(0);
867          } else {          } else {
868              $$ = new BitwiseOr(lhs, rhs);              $$ = new BitwiseOr(lhs, rhs);
869          }          }
# Line 579  bitwise_and_expr: Line 882  bitwise_and_expr:
882          } else if (rhs->exprType() != INT_EXPR) {          } else if (rhs->exprType() != INT_EXPR) {
883              PARSE_ERR(@3, (String("Right operand of bitwise operator '.and.' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());              PARSE_ERR(@3, (String("Right operand of bitwise operator '.and.' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
884              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
885            } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) {
886                PARSE_ERR(@1, "Units are not allowed for operands of bitwise operations.");
887                $$ = new IntLiteral(0);
888            } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) {
889                PARSE_ERR(@3, "Units are not allowed for operands of bitwise operations.");
890                $$ = new IntLiteral(0);
891          } else {          } else {
892              $$ = new BitwiseAnd(lhs, rhs);              $$ = new BitwiseAnd(lhs, rhs);
893          }          }
# Line 595  rel_expr: Line 904  rel_expr:
904          } else if (rhs->exprType() != INT_EXPR) {          } else if (rhs->exprType() != INT_EXPR) {
905              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 an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
906              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
907            } else if (lhs->asInt()->unitType()   != rhs->asInt()->unitType() ||
908                       lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
909            {
910                PARSE_ERR(@2, "Operands of relative operations must have same unit.");
911                $$ = new IntLiteral(0);
912          } else {          } else {
913              $$ = new Relation(lhs, Relation::LESS_THAN, rhs);              $$ = new Relation(lhs, Relation::LESS_THAN, rhs);
914          }          }
# Line 608  rel_expr: Line 922  rel_expr:
922          } else if (rhs->exprType() != INT_EXPR) {          } else if (rhs->exprType() != INT_EXPR) {
923              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 an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
924              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
925            } else if (lhs->asInt()->unitType()   != rhs->asInt()->unitType() ||
926                       lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
927            {
928                PARSE_ERR(@2, "Operands of relative operations must have same unit.");
929                $$ = new IntLiteral(0);
930          } else {          } else {
931              $$ = new Relation(lhs, Relation::GREATER_THAN, rhs);              $$ = new Relation(lhs, Relation::GREATER_THAN, rhs);
932          }          }
# Line 621  rel_expr: Line 940  rel_expr:
940          } else if (rhs->exprType() != INT_EXPR) {          } else if (rhs->exprType() != INT_EXPR) {
941              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 an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
942              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
943            } else if (lhs->asInt()->unitType()   != rhs->asInt()->unitType() ||
944                       lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
945            {
946                PARSE_ERR(@2, "Operands of relative operations must have same unit.");
947                $$ = new IntLiteral(0);
948          } else {          } else {
949              $$ = new Relation(lhs, Relation::LESS_OR_EQUAL, rhs);              $$ = new Relation(lhs, Relation::LESS_OR_EQUAL, rhs);
950          }          }
# Line 634  rel_expr: Line 958  rel_expr:
958          } else if (rhs->exprType() != INT_EXPR) {          } else if (rhs->exprType() != INT_EXPR) {
959              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 an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
960              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
961            } else if (lhs->asInt()->unitType()   != rhs->asInt()->unitType() ||
962                       lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
963            {
964                PARSE_ERR(@2, "Operands of relative operations must have same unit.");
965                $$ = new IntLiteral(0);
966          } else {          } else {
967              $$ = new Relation(lhs, Relation::GREATER_OR_EQUAL, rhs);              $$ = new Relation(lhs, Relation::GREATER_OR_EQUAL, rhs);
968          }          }
969      }      }
970      | rel_expr '=' add_expr  {      | rel_expr '=' add_expr  {
971          $$ = new Relation($1, Relation::EQUAL, $3);          ExpressionRef lhs = $1;
972            ExpressionRef rhs = $3;
973            if (lhs->exprType() != INT_EXPR) {
974                PARSE_ERR(@1, (String("Left operand of operator '=' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
975                $$ = new IntLiteral(0);
976            } else if (rhs->exprType() != INT_EXPR) {
977                PARSE_ERR(@3, (String("Right operand of operator '=' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
978                $$ = new IntLiteral(0);
979            } else if (lhs->asInt()->unitType()   != rhs->asInt()->unitType() ||
980                       lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
981            {
982                PARSE_ERR(@2, "Operands of relative operations must have same unit.");
983                $$ = new IntLiteral(0);
984            } else {
985                $$ = new Relation(lhs, Relation::EQUAL, rhs);
986            }
987      }      }
988      | rel_expr '#' add_expr  {      | rel_expr '#' add_expr  {
989          $$ = new Relation($1, Relation::NOT_EQUAL, $3);          ExpressionRef lhs = $1;
990            ExpressionRef rhs = $3;
991            if (lhs->exprType() != INT_EXPR) {
992                PARSE_ERR(@1, (String("Left operand of operator '#' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str());
993                $$ = new IntLiteral(0);
994            } else if (rhs->exprType() != INT_EXPR) {
995                PARSE_ERR(@3, (String("Right operand of operator '#' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
996                $$ = new IntLiteral(0);
997            } else if (lhs->asInt()->unitType()   != rhs->asInt()->unitType() ||
998                       lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
999            {
1000                PARSE_ERR(@2, "Operands of relative operations must have same unit.");
1001                $$ = new IntLiteral(0);
1002            } else {
1003                $$ = new Relation(lhs, Relation::NOT_EQUAL, rhs);
1004            }
1005      }      }
1006    
1007  add_expr:  add_expr:
# Line 656  add_expr: Line 1015  add_expr:
1015          } else if (rhs->exprType() != INT_EXPR) {          } else if (rhs->exprType() != INT_EXPR) {
1016              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 an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1017              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
1018            } else if (lhs->asInt()->unitType()   != rhs->asInt()->unitType() ||
1019                       lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
1020            {
1021                PARSE_ERR(@2, "Operands of '+' operations must have same unit.");
1022                $$ = new IntLiteral(0);
1023          } else {          } else {
1024              $$ = new Add(lhs,rhs);              $$ = new Add(lhs,rhs);
1025          }          }
# Line 669  add_expr: Line 1033  add_expr:
1033          } else if (rhs->exprType() != INT_EXPR) {          } else if (rhs->exprType() != INT_EXPR) {
1034              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 an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1035              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
1036            } else if (lhs->asInt()->unitType()   != rhs->asInt()->unitType() ||
1037                       lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor())
1038            {
1039                PARSE_ERR(@2, "Operands of '-' operations must have same unit.");
1040                $$ = new IntLiteral(0);
1041          } else {          } else {
1042              $$ = new Sub(lhs,rhs);              $$ = new Sub(lhs,rhs);
1043          }          }
# Line 685  mul_expr: Line 1054  mul_expr:
1054          } else if (rhs->exprType() != INT_EXPR) {          } else if (rhs->exprType() != INT_EXPR) {
1055              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 an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1056              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
1057            } else if (lhs->asInt()->unitType() && rhs->asInt()->unitType()) {
1058                PARSE_ERR(@2, "Only one operand of operator '*' may have a unit type");
1059                $$ = new IntLiteral(0);
1060            } else if (lhs->asInt()->unitPrefix(0) && rhs->asInt()->unitPrefix(0)) {
1061                PARSE_ERR(@2, "Only one operand of operator '*' may have a unit prefix");
1062                $$ = new IntLiteral(0);
1063          } else {          } else {
1064              $$ = new Mul(lhs,rhs);              $$ = new Mul(lhs,rhs);
1065          }          }
# Line 698  mul_expr: Line 1073  mul_expr:
1073          } else if (rhs->exprType() != INT_EXPR) {          } else if (rhs->exprType() != INT_EXPR) {
1074              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 an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str());
1075              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
1076            } else if (lhs->asInt()->unitType() && rhs->asInt()->unitType() &&
1077                       lhs->asInt()->unitType() != rhs->asInt()->unitType())
1078            {
1079                PARSE_ERR(@2, "Operands of operator '/' with two different unit types.");
1080                $$ = new IntLiteral(0);
1081            } else if (!lhs->asInt()->unitType() && rhs->asInt()->unitType()) {
1082                PARSE_ERR(@3, ("Dividing left operand without any unit type by right operand with unit type " + typeStr(rhs->exprType()) + " is not possible.").c_str());
1083                $$ = new IntLiteral(0);
1084            } else if (lhs->asInt()->unitFactor()  != rhs->asInt()->unitFactor() &&
1085                       lhs->asInt()->unitPrefix(0) && rhs->asInt()->unitPrefix(0))
1086            {
1087                PARSE_ERR(@2, "Dividing two operands with two different unit prefixes is not possible.");
1088                $$ = new IntLiteral(0);
1089            } else if (lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor() &&
1090                       rhs->asInt()->unitPrefix(0))
1091            {
1092                PARSE_ERR(@3, "Dividing left operand without any unit prefix by right operand with unit prefix is not possible.");
1093                $$ = new IntLiteral(0);
1094          } else {          } else {
1095              $$ = new Div(lhs,rhs);              $$ = new Div(lhs,rhs);
1096          }          }
# Line 712  mul_expr: Line 1105  mul_expr:
1105              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());
1106              $$ = new IntLiteral(0);              $$ = new IntLiteral(0);
1107          } else {          } else {
1108                if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0))
1109                    PARSE_ERR(@1, "Operands of modulo operator must not use any unit.");
1110                if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0))
1111                    PARSE_ERR(@3, "Operands of modulo operator must not use any unit.");
1112              $$ = new Mod(lhs,rhs);              $$ = new Mod(lhs,rhs);
1113          }          }
1114      }      }
# Line 727  void InstrScript_warning(YYLTYPE* locp, Line 1124  void InstrScript_warning(YYLTYPE* locp,
1124      //fprintf(stderr, "WRN %d: %s\n", locp->first_line, txt);      //fprintf(stderr, "WRN %d: %s\n", locp->first_line, txt);
1125      context->addWrn(locp->first_line, locp->last_line, locp->first_column+1, locp->last_column+1, txt);      context->addWrn(locp->first_line, locp->last_line, locp->first_column+1, locp->last_column+1, txt);
1126  }  }
1127    
1128    /// Custom implementation of yytnamerr() to ensure quotation is always stripped from token names before printing them to error messages.
1129    int InstrScript_tnamerr(char* yyres, const char* yystr) {
1130      if (*yystr == '"') {
1131          int yyn = 0;
1132          char const *yyp = yystr;
1133          for (;;)
1134            switch (*++yyp)
1135              {
1136    /*
1137              case '\'':
1138              case ',':
1139                goto do_not_strip_quotes;
1140    
1141              case '\\':
1142                if (*++yyp != '\\')
1143                  goto do_not_strip_quotes;
1144    */
1145                /* Fall through.  */
1146              default:
1147                if (yyres)
1148                  yyres[yyn] = *yyp;
1149                yyn++;
1150                break;
1151    
1152              case '"':
1153                if (yyres)
1154                  yyres[yyn] = '\0';
1155                return yyn;
1156              }
1157    /*
1158        do_not_strip_quotes: ;
1159    */
1160        }
1161    
1162      if (! yyres)
1163        return (int) yystrlen (yystr);
1164    
1165      return int( yystpcpy (yyres, yystr) - yyres );
1166    }

Legend:
Removed from v.2945  
changed lines
  Added in v.3561

  ViewVC Help
Powered by ViewVC