--- linuxsampler/trunk/src/scriptvm/parser.y 2016/10/15 23:54:27 3013 +++ linuxsampler/trunk/src/scriptvm/parser.y 2019/08/24 09:18:57 3564 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016 Christian Schoenebeck and Andreas Persson + * Copyright (c) 2014-2017 Christian Schoenebeck and Andreas Persson * * http://www.linuxsampler.org * @@ -23,6 +23,7 @@ #define scanner context->scanner #define PARSE_ERR(loc,txt) yyerror(&loc, context, txt) #define PARSE_WRN(loc,txt) InstrScript_warning(&loc, context, txt) + #define PARSE_DROP(loc) context->addPreprocessorComment(loc.first_line, loc.last_line, loc.first_column+1, loc.last_column+1); #define yytnamerr(res,str) InstrScript_tnamerr(res, str) %} @@ -31,12 +32,14 @@ %parse-param { LinuxSampler::ParserContext* context } %lex-param { void* scanner } // avoid symbol collision with other (i.e. future) auto generated (f)lex scanners -%name-prefix "InstrScript_" +// (NOTE: "=" is deprecated here with Bison 3.x, however removing it would cause an error with Bison 2.x) +%name-prefix="InstrScript_" %locations %defines %error-verbose %token INTEGER "integer literal" +%token INTEGER_UNIT "integer literal with unit" %token STRING "string literal" %token IDENTIFIER "function name" %token VARIABLE "variable name" @@ -51,6 +54,7 @@ %token CONST_ "keyword 'const'" %token POLYPHONIC "keyword 'polyphonic'" %token WHILE "keyword 'while'" +%token SYNCHRONIZED "keyword 'synchronized'" %token IF "keyword 'if'" %token ELSE "keyword 'else'" %token SELECT "keyword 'select'" @@ -68,6 +72,7 @@ %token LE "operator '<='" %token GE "operator '>='" %token END_OF_FILE 0 "end of file" +%token UNKNOWN_CHAR "unknown character" %type script sections %type section eventhandler @@ -224,16 +229,16 @@ if (name[0] == '@') PARSE_WRN(@2, (String("Variable '") + name + "' declared as string, integer expression assigned though.").c_str()); IntExprRef expr = $4; + IntVariableRef var = new IntVariable(context); if (expr->isConstExpr()) { - const int i = expr->evalInt(); - IntVariableRef var = new IntVariable(context); - context->vartable[name] = var; + const vmint i = expr->evalInt(); $$ = new Assignment(var, new IntLiteral(i)); } else { - IntVariableRef var = new IntVariable(context); - context->vartable[name] = var; $$ = new Assignment(var, expr); } + var->copyUnitFrom(expr); + var->setFinal(expr->isFinal()); + context->vartable[name] = var; } } | DECLARE VARIABLE '[' expr ']' { @@ -250,13 +255,20 @@ $$ = 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()); + if (expr->unitType() || expr->unitPrefix(0)) { + PARSE_ERR(@4, "Units are not allowed as array size."); $$ = new FunctionCall("nothing", new Args, NULL); // whatever } else { - context->vartable[name] = new IntArrayVariable(context, size); - $$ = new NoOperation; + if (expr->isFinal()) + PARSE_WRN(@4, "Final operator '!' is meaningless here."); + vmint 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 + } else { + context->vartable[name] = new IntArrayVariable(context, size); + $$ = new NoOperation; + } } } } @@ -274,19 +286,24 @@ } else { IntExprRef sizeExpr = $4; ArgsRef args = $8; - int size = sizeExpr->evalInt(); + vmint size = sizeExpr->evalInt(); if (size <= 0) { PARSE_ERR(@4, (String("Array variable '") + name + "' must be declared with positive array size.").c_str()); $$ = new FunctionCall("nothing", new Args, NULL); // whatever } else if (args->argsCount() > size) { - PARSE_ERR(@8, (String("Variable '") + name + + PARSE_ERR(@8, (String("Array variable '") + name + "' was declared with size " + ToString(size) + " but " + ToString(args->argsCount()) + " values were assigned." ).c_str()); - $$ = new FunctionCall("nothing", new Args, NULL); // whatever + $$ = new FunctionCall("nothing", new Args, NULL); // whatever + } else if (sizeExpr->unitType() || sizeExpr->unitPrefix(0)) { + PARSE_ERR(@4, "Units are not allowed as array size."); + $$ = new FunctionCall("nothing", new Args, NULL); // whatever } else { + if (sizeExpr->isFinal()) + PARSE_WRN(@4, "Final operator '!' is meaningless here."); bool argsOK = true; - for (int i = 0; i < args->argsCount(); ++i) { + for (vmint i = 0; i < args->argsCount(); ++i) { if (args->arg(i)->exprType() != INT_EXPR) { PARSE_ERR( @8, @@ -296,6 +313,17 @@ ); argsOK = false; break; + } else if (args->arg(i)->asInt()->unitType() || + args->arg(i)->asInt()->unitPrefix(0)) + { + PARSE_ERR( + @8, + (String("Array variable '") + name + + "' declared with invalid assignment values. Assigned element " + + ToString(i+1) + " contains a unit.").c_str() + ); + argsOK = false; + break; } } if (argsOK) { @@ -306,6 +334,78 @@ } } } + | DECLARE CONST_ VARIABLE '[' expr ']' ASSIGNMENT '(' args ')' { + const char* name = $3; + if (!$5->isConstExpr()) { + PARSE_ERR(@5, (String("Array variable '") + name + "' must be declared with constant array size.").c_str()); + $$ = new FunctionCall("nothing", new Args, NULL); // whatever + } else if ($5->exprType() != INT_EXPR) { + PARSE_ERR(@5, (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(@3, (String("Redeclaration of variable '") + name + "'.").c_str()); + $$ = new FunctionCall("nothing", new Args, NULL); // whatever + } else { + IntExprRef sizeExpr = $5; + ArgsRef args = $9; + vmint size = sizeExpr->evalInt(); + if (size <= 0) { + PARSE_ERR(@5, (String("Array variable '") + name + "' must be declared with positive array size.").c_str()); + $$ = new FunctionCall("nothing", new Args, NULL); // whatever + } else if (args->argsCount() > size) { + PARSE_ERR(@9, (String("Array variable '") + name + + "' was declared with size " + ToString(size) + + " but " + ToString(args->argsCount()) + + " values were assigned." ).c_str()); + $$ = new FunctionCall("nothing", new Args, NULL); // whatever + } else if (sizeExpr->unitType() || sizeExpr->unitPrefix(0)) { + PARSE_ERR(@5, "Units are not allowed as array size."); + $$ = new FunctionCall("nothing", new Args, NULL); // whatever + } else { + if (sizeExpr->isFinal()) + PARSE_WRN(@5, "Final operator '!' is meaningless here."); + bool argsOK = true; + for (vmint i = 0; i < args->argsCount(); ++i) { + if (args->arg(i)->exprType() != INT_EXPR) { + PARSE_ERR( + @9, + (String("Array variable '") + name + + "' declared with invalid assignment values. Assigned element " + + ToString(i+1) + " is not an integer expression.").c_str() + ); + argsOK = false; + break; + } + if (!args->arg(i)->isConstExpr()) { + PARSE_ERR( + @9, + (String("const array variable '") + name + + "' must be defined with const values. Assigned element " + + ToString(i+1) + " is not a const expression though.").c_str() + ); + argsOK = false; + break; + } else if (args->arg(i)->asInt()->unitType() || + args->arg(i)->asInt()->unitPrefix(0)) + { + PARSE_ERR( + @9, + (String("const array variable '") + name + + "' declared with invalid assignment values. Assigned element " + + ToString(i+1) + " contains a unit.").c_str() + ); + argsOK = false; + break; + } + } + if (argsOK) { + context->vartable[name] = new IntArrayVariable(context, size, args, true); + $$ = new NoOperation; + } else + $$ = new FunctionCall("nothing", new Args, NULL); // whatever + } + } + } | DECLARE CONST_ VARIABLE ASSIGNMENT expr { const char* name = $3; if ($5->exprType() == STRING_EXPR) { @@ -324,13 +424,15 @@ } else { if (name[0] == '@') PARSE_WRN(@5, "Variable declared as string, integer expression assigned though."); - int i = 0; + vmint 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); + var->copyUnitFrom(expr); + var->setFinal(expr->isFinal()); context->vartable[name] = var; //$$ = new Assignment(var, new IntLiteral(i)); $$ = new NoOperation(); @@ -341,21 +443,50 @@ } | WHILE '(' expr ')' opt_statements END WHILE { if ($3->exprType() == INT_EXPR) { - $$ = new While($3, $5); + IntExprRef expr = $3; + if (expr->isFinal() && expr->isConstExpr()) + PARSE_WRN(@3, "Final operator '!' is meaningless here."); + $$ = new While(expr, $5); } else { PARSE_ERR(@3, "Condition for 'while' loops must be integer expression."); $$ = new While(new IntLiteral(0), $5); } } + | SYNCHRONIZED opt_statements END SYNCHRONIZED { + $$ = new SyncBlock($2); + } | IF '(' expr ')' opt_statements ELSE opt_statements END IF { - $$ = new If($3, $5, $7); + if ($3->exprType() == INT_EXPR) { + IntExprRef expr = $3; + if (expr->isFinal() && expr->isConstExpr()) + PARSE_WRN(@3, "Final operator '!' is meaningless here."); + $$ = new If($3, $5, $7); + } else { + PARSE_ERR(@3, "Condition for 'if' must be integer expression."); + $$ = new If(new IntLiteral(0), $5, $7); + } } | IF '(' expr ')' opt_statements END IF { - $$ = new If($3, $5); + if ($3->exprType() == INT_EXPR) { + IntExprRef expr = $3; + if (expr->isFinal() && expr->isConstExpr()) + PARSE_WRN(@3, "Final operator '!' is meaningless here."); + $$ = new If($3, $5); + } else { + PARSE_ERR(@3, "Condition for 'if' must be integer expression."); + $$ = new If(new IntLiteral(0), $5); + } } | SELECT expr caseclauses END SELECT { if ($2->exprType() == INT_EXPR) { - $$ = new SelectCase($2, $3); + IntExprRef expr = $2; + if (expr->unitType() || expr->unitPrefix(0)) { + PARSE_ERR(@2, "Units are not allowed here."); + } else { + if (expr->isFinal() && expr->isConstExpr()) + PARSE_WRN(@2, "Final operator '!' is meaningless here."); + $$ = new SelectCase(expr, $3); + } } else { PARSE_ERR(@2, "Statement 'select' can only by applied to integer expressions."); $$ = new SelectCase(new IntLiteral(0), $3); @@ -412,6 +543,9 @@ } else if (!fn) { PARSE_ERR(@1, (String("No built-in function with name '") + name + "'.").c_str()); $$ = new FunctionCall(name, args, NULL); + } else if (context->functionProvider->isFunctionDisabled(fn,context)) { + PARSE_DROP(@$); + $$ = new NoFunctionCall; } else if (args->argsCount() < fn->minRequiredArgs()) { PARSE_ERR(@3, (String("Built-in function '") + name + "' requires at least " + ToString(fn->minRequiredArgs()) + " arguments.").c_str()); $$ = new FunctionCall(name, args, NULL); @@ -420,7 +554,7 @@ $$ = new FunctionCall(name, args, NULL); } else { bool argsOK = true; - for (int i = 0; i < args->argsCount(); ++i) { + for (vmint i = 0; i < args->argsCount(); ++i) { if (args->arg(i)->exprType() != fn->argType(i) && !fn->acceptsArgType(i, args->arg(i)->exprType())) { 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()); argsOK = false; @@ -429,6 +563,24 @@ PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' expects an assignable variable.").c_str()); argsOK = false; break; + } else if (args->arg(i)->exprType() == INT_EXPR && !fn->acceptsArgUnitType(i, args->arg(i)->asInt()->unitType())) { + if (args->arg(i)->asInt()->unitType()) + 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()); + else + PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' expects a unit.").c_str()); + argsOK = false; + break; + } else if (args->arg(i)->exprType() == INT_EXPR && args->arg(i)->asInt()->unitPrefix(0) && !fn->acceptsArgUnitPrefix(i, args->arg(i)->asInt()->unitType())) { + if (args->arg(i)->asInt()->unitType()) + 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)->asInt()->unitType()) + ".").c_str()); + else + PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' does not expect a unit prefix.").c_str()); + argsOK = false; + break; + } else if (!fn->acceptsArgFinal(i) && args->arg(i)->exprType() == INT_EXPR && args->arg(i)->asInt()->isFinal()) { + PARSE_ERR(@3, (String("Argument ") + ToString(i+1) + " of built-in function '" + name + "' does not expect a \"final\" value.").c_str()); + argsOK = false; + break; } } $$ = new FunctionCall(name, args, argsOK ? fn : NULL); @@ -445,6 +597,9 @@ } else if (!fn) { PARSE_ERR(@1, (String("No built-in function with name '") + name + "'.").c_str()); $$ = new FunctionCall(name, args, NULL); + } else if (context->functionProvider->isFunctionDisabled(fn,context)) { + PARSE_DROP(@$); + $$ = new NoFunctionCall; } else if (fn->minRequiredArgs() > 0) { PARSE_ERR(@3, (String("Built-in function '") + name + "' requires at least " + ToString(fn->minRequiredArgs()) + " arguments.").c_str()); $$ = new FunctionCall(name, args, NULL); @@ -463,6 +618,9 @@ } else if (!fn) { PARSE_ERR(@1, (String("No built-in function with name '") + name + "'.").c_str()); $$ = new FunctionCall(name, args, NULL); + } else if (context->functionProvider->isFunctionDisabled(fn,context)) { + PARSE_DROP(@$); + $$ = new NoFunctionCall; } else if (fn->minRequiredArgs() > 0) { PARSE_ERR(@1, (String("Built-in function '") + name + "' requires at least " + ToString(fn->minRequiredArgs()) + " arguments.").c_str()); $$ = new FunctionCall(name, args, NULL); @@ -497,6 +655,16 @@ PARSE_ERR(@2, (String("Variable assignment: Variable '") + name + "' is not assignable.").c_str()); else if (var->exprType() != $3->exprType()) PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' is of type " + typeStr(var->exprType()) + ", assignment is of type " + typeStr($3->exprType()) + " though.").c_str()); + else if (var->exprType() == INT_EXPR) { + IntVariableRef intVar = var; + IntExprRef expr = $3; + if (intVar->unitType() != expr->unitType()) + PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' has unit type " + unitTypeStr(intVar->unitType()) + ", assignment has unit type " + unitTypeStr(expr->unitType()) + " though.").c_str()); + else if (intVar->unitFactor() != expr->unitFactor()) + PARSE_ERR(@3, (String("Variable assignment: Variable '") + name + "' has a different unit prefix.").c_str()); + else if (intVar->isFinal() != expr->isFinal()) + 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()); + } $$ = new Assignment(var, $3); } | VARIABLE '[' expr ']' ASSIGNMENT expr { @@ -506,10 +674,27 @@ PARSE_ERR(@1, (String("No variable declared with name '") + name + "'.").c_str()); else if (var->exprType() != INT_ARR_EXPR) PARSE_ERR(@2, (String("Variable '") + name + "' is not an array variable.").c_str()); + else if (var->isConstExpr()) + PARSE_ERR(@5, (String("Variable assignment: Cannot modify const array variable '") + name + "'.").c_str()); + else if (!var->isAssignable()) + PARSE_ERR(@5, (String("Variable assignment: Array variable '") + name + "' is not assignable.").c_str()); else if ($3->exprType() != INT_EXPR) PARSE_ERR(@3, (String("Array variable '") + name + "' accessed with non integer expression.").c_str()); + else if ($3->asInt()->unitType()) + PARSE_ERR(@3, "Unit types are not allowed as array index."); else if ($6->exprType() != INT_EXPR) PARSE_ERR(@5, (String("Value assigned to array variable '") + name + "' must be an integer expression.").c_str()); + else if ($6->asInt()->unitType()) + PARSE_ERR(@6, "Unit types are not allowed for array variables."); + else if ($6->asInt()->isFinal()) + PARSE_ERR(@6, "Final operator '!' not allowed for array variables."); + else if ($3->isConstExpr() && $3->asInt()->evalInt() >= ((IntArrayVariableRef)var)->arraySize()) + PARSE_WRN(@3, (String("Index ") + ToString($3->asInt()->evalInt()) + + " exceeds size of array variable '" + name + + "' which was declared with size " + + ToString(((IntArrayVariableRef)var)->arraySize()) + ".").c_str()); + else if ($3->asInt()->isFinal()) + PARSE_WRN(@3, "Final operator '!' is meaningless here."); IntArrayElementRef element = new IntArrayElement(var, $3); $$ = new Assignment(element, $6); } @@ -518,6 +703,11 @@ INTEGER { $$ = new IntLiteral($1); } + | INTEGER_UNIT { + IntLiteralRef literal = new IntLiteral($1.iValue); + literal->setUnit($1.prefix, $1.unit); + $$ = literal; + } | STRING { $$ = new StringLiteral($1); } @@ -543,7 +733,17 @@ } else if ($3->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Array variable '") + name + "' accessed with non integer expression.").c_str()); $$ = new IntLiteral(0); + } else if ($3->asInt()->unitType() || $3->asInt()->unitPrefix(0)) { + PARSE_ERR(@3, "Units are not allowed as array index."); + $$ = new IntLiteral(0); } else { + if ($3->isConstExpr() && $3->asInt()->evalInt() >= ((IntArrayVariableRef)var)->arraySize()) + PARSE_WRN(@3, (String("Index ") + ToString($3->asInt()->evalInt()) + + " exceeds size of array variable '" + name + + "' which was declared with size " + + ToString(((IntArrayVariableRef)var)->arraySize()) + ".").c_str()); + else if ($3->asInt()->isFinal()) + PARSE_WRN(@3, "Final operator '!' is meaningless here."); $$ = new IntArrayElement(var, $3); } } @@ -560,6 +760,9 @@ if ($2->exprType() != INT_EXPR) { PARSE_ERR(@2, (String("Right operand of bitwise operator '.not.' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if ($2->asInt()->unitType() || $2->asInt()->unitPrefix(0)) { + PARSE_ERR(@2, "Units are not allowed for operands of bitwise operations."); + $$ = new IntLiteral(0); } else { $$ = new BitwiseNot($2); } @@ -568,10 +771,21 @@ if ($2->exprType() != INT_EXPR) { PARSE_ERR(@2, (String("Right operand of operator 'not' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if ($2->asInt()->unitType() || $2->asInt()->unitPrefix(0)) { + PARSE_ERR(@2, "Units are not allowed for operands of logical operations."); + $$ = new IntLiteral(0); } else { $$ = new Not($2); } } + | '!' unary_expr { + if ($2->exprType() != INT_EXPR) { + PARSE_ERR(@2, (String("Right operand of \"final\" operator '!' must be an integer expression, is ") + typeStr($2->exprType()) + " though.").c_str()); + $$ = new IntLiteral(0); + } else { + $$ = new Final($2); + } + } expr: concat_expr @@ -601,6 +815,12 @@ } else if (rhs->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Right operand of operator 'or' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) { + PARSE_ERR(@1, "Units are not allowed for operands of logical operations."); + $$ = new IntLiteral(0); + } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) { + PARSE_ERR(@3, "Units are not allowed for operands of logical operations."); + $$ = new IntLiteral(0); } else { $$ = new Or(lhs, rhs); } @@ -619,6 +839,12 @@ } else if (rhs->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Right operand of operator 'and' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) { + PARSE_ERR(@1, "Units are not allowed for operands of logical operations."); + $$ = new IntLiteral(0); + } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) { + PARSE_ERR(@3, "Units are not allowed for operands of logical operations."); + $$ = new IntLiteral(0); } else { $$ = new And(lhs, rhs); } @@ -635,6 +861,12 @@ } else if (rhs->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Right operand of bitwise operator '.or.' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) { + PARSE_ERR(@1, "Units are not allowed for operands of bitwise operations."); + $$ = new IntLiteral(0); + } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) { + PARSE_ERR(@3, "Units are not allowed for operands of bitwise operations."); + $$ = new IntLiteral(0); } else { $$ = new BitwiseOr(lhs, rhs); } @@ -653,6 +885,12 @@ } else if (rhs->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Right operand of bitwise operator '.and.' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) { + PARSE_ERR(@1, "Units are not allowed for operands of bitwise operations."); + $$ = new IntLiteral(0); + } else if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) { + PARSE_ERR(@3, "Units are not allowed for operands of bitwise operations."); + $$ = new IntLiteral(0); } else { $$ = new BitwiseAnd(lhs, rhs); } @@ -669,6 +907,11 @@ } else if (rhs->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Right operand of operator '<' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() || + lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor()) + { + PARSE_ERR(@2, "Operands of relative operations must have same unit."); + $$ = new IntLiteral(0); } else { $$ = new Relation(lhs, Relation::LESS_THAN, rhs); } @@ -682,6 +925,11 @@ } else if (rhs->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Right operand of operator '>' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() || + lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor()) + { + PARSE_ERR(@2, "Operands of relative operations must have same unit."); + $$ = new IntLiteral(0); } else { $$ = new Relation(lhs, Relation::GREATER_THAN, rhs); } @@ -695,6 +943,11 @@ } else if (rhs->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Right operand of operator '<=' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() || + lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor()) + { + PARSE_ERR(@2, "Operands of relative operations must have same unit."); + $$ = new IntLiteral(0); } else { $$ = new Relation(lhs, Relation::LESS_OR_EQUAL, rhs); } @@ -708,15 +961,50 @@ } else if (rhs->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Right operand of operator '>=' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() || + lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor()) + { + PARSE_ERR(@2, "Operands of relative operations must have same unit."); + $$ = new IntLiteral(0); } else { $$ = new Relation(lhs, Relation::GREATER_OR_EQUAL, rhs); } } | rel_expr '=' add_expr { - $$ = new Relation($1, Relation::EQUAL, $3); + ExpressionRef lhs = $1; + ExpressionRef rhs = $3; + if (lhs->exprType() != INT_EXPR) { + PARSE_ERR(@1, (String("Left operand of operator '=' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str()); + $$ = new IntLiteral(0); + } else if (rhs->exprType() != INT_EXPR) { + PARSE_ERR(@3, (String("Right operand of operator '=' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); + $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() || + lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor()) + { + PARSE_ERR(@2, "Operands of relative operations must have same unit."); + $$ = new IntLiteral(0); + } else { + $$ = new Relation(lhs, Relation::EQUAL, rhs); + } } | rel_expr '#' add_expr { - $$ = new Relation($1, Relation::NOT_EQUAL, $3); + ExpressionRef lhs = $1; + ExpressionRef rhs = $3; + if (lhs->exprType() != INT_EXPR) { + PARSE_ERR(@1, (String("Left operand of operator '#' must be an integer expression, is ") + typeStr(lhs->exprType()) + " though.").c_str()); + $$ = new IntLiteral(0); + } else if (rhs->exprType() != INT_EXPR) { + PARSE_ERR(@3, (String("Right operand of operator '#' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); + $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() || + lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor()) + { + PARSE_ERR(@2, "Operands of relative operations must have same unit."); + $$ = new IntLiteral(0); + } else { + $$ = new Relation(lhs, Relation::NOT_EQUAL, rhs); + } } add_expr: @@ -730,6 +1018,11 @@ } else if (rhs->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Right operand of operator '+' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() || + lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor()) + { + PARSE_ERR(@2, "Operands of '+' operations must have same unit."); + $$ = new IntLiteral(0); } else { $$ = new Add(lhs,rhs); } @@ -743,6 +1036,11 @@ } else if (rhs->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Right operand of operator '-' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() != rhs->asInt()->unitType() || + lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor()) + { + PARSE_ERR(@2, "Operands of '-' operations must have same unit."); + $$ = new IntLiteral(0); } else { $$ = new Sub(lhs,rhs); } @@ -759,6 +1057,12 @@ } else if (rhs->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Right operand of operator '*' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() && rhs->asInt()->unitType()) { + PARSE_ERR(@2, "Only one operand of operator '*' may have a unit type"); + $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitPrefix(0) && rhs->asInt()->unitPrefix(0)) { + PARSE_ERR(@2, "Only one operand of operator '*' may have a unit prefix"); + $$ = new IntLiteral(0); } else { $$ = new Mul(lhs,rhs); } @@ -772,6 +1076,24 @@ } else if (rhs->exprType() != INT_EXPR) { PARSE_ERR(@3, (String("Right operand of operator '/' must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitType() && rhs->asInt()->unitType() && + lhs->asInt()->unitType() != rhs->asInt()->unitType()) + { + PARSE_ERR(@2, "Operands of operator '/' with two different unit types."); + $$ = new IntLiteral(0); + } else if (!lhs->asInt()->unitType() && rhs->asInt()->unitType()) { + PARSE_ERR(@3, ("Dividing left operand without any unit type by right operand with unit type " + typeStr(rhs->exprType()) + " is not possible.").c_str()); + $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor() && + lhs->asInt()->unitPrefix(0) && rhs->asInt()->unitPrefix(0)) + { + PARSE_ERR(@2, "Dividing two operands with two different unit prefixes is not possible."); + $$ = new IntLiteral(0); + } else if (lhs->asInt()->unitFactor() != rhs->asInt()->unitFactor() && + rhs->asInt()->unitPrefix(0)) + { + PARSE_ERR(@3, "Dividing left operand without any unit prefix by right operand with unit prefix is not possible."); + $$ = new IntLiteral(0); } else { $$ = new Div(lhs,rhs); } @@ -786,6 +1108,10 @@ PARSE_ERR(@3, (String("Right operand of modulo operator must be an integer expression, is ") + typeStr(rhs->exprType()) + " though.").c_str()); $$ = new IntLiteral(0); } else { + if (lhs->asInt()->unitType() || lhs->asInt()->unitPrefix(0)) + PARSE_ERR(@1, "Operands of modulo operator must not use any unit."); + if (rhs->asInt()->unitType() || rhs->asInt()->unitPrefix(0)) + PARSE_ERR(@3, "Operands of modulo operator must not use any unit."); $$ = new Mod(lhs,rhs); } } @@ -831,11 +1157,13 @@ yyres[yyn] = '\0'; return yyn; } +/* do_not_strip_quotes: ; +*/ } if (! yyres) - return yystrlen (yystr); + return (int) yystrlen (yystr); - return yystpcpy (yyres, yystr) - yyres; + return int( yystpcpy (yyres, yystr) - yyres ); }