void UnaryExpr(out Expression expr) { expr = null; switch (la.kind) { case 40: { Get(); expr = new UnaryExpression(UnaryOperator.UMinus); expr.t = t; UnaryExpr(out (expr as UnaryExpression).operand); break; } case 41: { Get(); expr = new UnaryExpression(UnaryOperator.Not); expr.t = t; UnaryExpr(out (expr as UnaryExpression).operand); break; } case 2: case 3: case 4: case 26: case 27: { ConstantExpression(out expr); break; } case 36: { Get(); Expect(21); expr = new CastExpression(PrimitiveType.INT); expr.t = t; Expect(43); UnaryExpr(out (expr as CastExpression).operand); break; } case 1: { Get(); expr = new VariableReferenceExpression(t.val); expr.t = t; while (la.kind == 32) { Get(); Expect(1); (expr as VariableReferenceExpression).name += "." + t.val; } if (la.kind == 38) { Get(); expr = new CallExpression((expr as VariableReferenceExpression).name, expr.t); Expression argument; if (StartOf(3)) { Expression(out argument); (expr as CallExpression).AddArgument(argument); while (la.kind == 31) { Get(); Expression(out argument); (expr as CallExpression).AddArgument(argument); } } Expect(45); } if (la.kind == 37) { Get(); expr = new IndexerExpression(expr); Expression indexer; Expression(out indexer); (expr as IndexerExpression).AddIndexer(indexer); while (la.kind == 31) { Get(); Expression(out indexer); (expr as IndexerExpression).AddIndexer(indexer); } Expect(44); } break; } case 38: { Get(); Expression(out expr); Expect(45); break; } default: SynErr(56); break; } }
/// <summary> /// Evaluates this node and all its children /// </summary> /// <param name="scope">The scope of this expression</param> /// <returns></returns> public override Expression Evaluate(Scope scope) { // Evaluate operands leftOperand = leftOperand.Evaluate(scope); rightOperand = rightOperand.Evaluate(scope); // Check if both operands are of the same type if (leftOperand.returnType.ToCLRType() != rightOperand.returnType.ToCLRType()) { // If not, check if left operand can be implicitely typecasted to right operand type if (leftOperand.returnType.IsCompatible(rightOperand.returnType)) { // Create implicit cast CastExpression implicitCast = new CastExpression(rightOperand.returnType); implicitCast.operand = leftOperand; // Evaluate typecast for folding this.leftOperand = implicitCast.Evaluate(scope); // Set return type this.returnType = rightOperand.returnType; } // If not, check if right operand can be implicitely typecasted to left operand type else if (rightOperand.returnType.IsCompatible(leftOperand.returnType)) { // Create implicit cast CastExpression implicitCast = new CastExpression(leftOperand.returnType); implicitCast.operand = rightOperand; // Evaluate for folding this.rightOperand = implicitCast.Evaluate(scope); // Set return type this.returnType = leftOperand.returnType; } else { // Types are incompatible - issue error Compiler.Compiler.errors.SemErr(t.line, t.col, "Incompatible types"); this.returnType = PrimitiveType.UNSUPPORTED; return this; } } // If operands are of the same type else { // Set return type this.returnType = leftOperand.returnType; } // If operand is not arithmetic, overwrite return type if ((int)op >= 6) { this.returnType = PrimitiveType.BOOL; } // Check if operator and operands are compatible switch (op) { // Addition is accepted for strings and numeric types case BinaryOperator.Add: // If type is not string, check if it is numerical if (!leftOperand.returnType.Equals(PrimitiveType.STRING)) { goto case BinaryOperator.Leq; } break; // Other arithmetic operators and comparisons (except equals and not equals) are accepted for numeric types case BinaryOperator.Sub: case BinaryOperator.Mul: case BinaryOperator.Div: case BinaryOperator.Gt: case BinaryOperator.Lt: case BinaryOperator.Geq: case BinaryOperator.Leq: // Check if type is not integer or double if (!leftOperand.returnType.Equals(PrimitiveType.INT) && !leftOperand.returnType.Equals(PrimitiveType.DOUBLE)) { // Issue error Compiler.Compiler.errors.SemErr(t.line, t.col, "Arithmetic operator can only be applied to numerical types"); } break; // Modulo operator is accepted only for integer type case BinaryOperator.Rem: // Check if type is not integer if (!leftOperand.returnType.Equals(PrimitiveType.INT)) { // Issue error Compiler.Compiler.errors.SemErr(t.line, t.col, "Reminder operator can only be applied to integer type"); } break; // Equality and non equality are accepted for all types case BinaryOperator.Eq: case BinaryOperator.Neq: break; // Default case stands for logical operators default: // Check if type is not boolean if (!leftOperand.returnType.Equals(PrimitiveType.BOOL)) { // Issue error Compiler.Compiler.errors.SemErr(t.line, t.col, "Logical operator can only be applied to boolean type"); } break; } // If both operands are constant expressions, perform constant folding if ((leftOperand is ConstantExpression) && (rightOperand is ConstantExpression)) { // Compile time evaluation of expressions is done based on type and operator // If type is boolean if (leftOperand.returnType.Equals(PrimitiveType.BOOL)) { switch (op) { // Compute equality case BinaryOperator.Eq: // Cast values to bool, compare and create new constant expression return new ConstantExpression(Primitive.Bool, (bool)(leftOperand as ConstantExpression).value == (bool)(rightOperand as ConstantExpression).value); // Compute non-equality case BinaryOperator.Neq: // Same as exclusive or for boolean values goto case BinaryOperator.Xor; // Compute logical and case BinaryOperator.And: // Cast values to bool, apply operation and create constant expression return new ConstantExpression(Primitive.Bool, (bool)(leftOperand as ConstantExpression).value && (bool)(rightOperand as ConstantExpression).value); // Compute logical or case BinaryOperator.Or: // Cast values to bool, apply operation and create constant expression return new ConstantExpression(Primitive.Bool, (bool)(leftOperand as ConstantExpression).value || (bool)(rightOperand as ConstantExpression).value); // Compute logical exclusive or case BinaryOperator.Xor: // Cast values to bool, apply operation and create constant expression (xor is equivalent to a // non-equality check) return new ConstantExpression(Primitive.Bool, (bool)(leftOperand as ConstantExpression).value != (bool)(rightOperand as ConstantExpression).value); } } // If type is double else if (leftOperand.returnType.Equals(PrimitiveType.DOUBLE)) { switch (op) { // Compute equality case BinaryOperator.Eq: // Cast values to double, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (double)(leftOperand as ConstantExpression).value == (double)(rightOperand as ConstantExpression).value); // Compute non-equality case BinaryOperator.Neq: // Cast values to double, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (double)(leftOperand as ConstantExpression).value != (double)(rightOperand as ConstantExpression).value); // Compute greater than case BinaryOperator.Gt: // Cast values to double, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (double)(leftOperand as ConstantExpression).value > (double)(rightOperand as ConstantExpression).value); // Compute greater than or equal to case BinaryOperator.Geq: // Cast values to double, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (double)(leftOperand as ConstantExpression).value >= (double)(rightOperand as ConstantExpression).value); // Compute less than case BinaryOperator.Lt: // Cast values to double, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (double)(leftOperand as ConstantExpression).value < (double)(rightOperand as ConstantExpression).value); // Compute less than or equal to case BinaryOperator.Leq: // Cast values to double, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (double)(leftOperand as ConstantExpression).value <= (double)(rightOperand as ConstantExpression).value); // Compute addition case BinaryOperator.Add: // Cast values to double, apply operation and create constant expression return new ConstantExpression(Primitive.Double, ((double)(leftOperand as ConstantExpression).value + (double)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo)); // Compute subtraction case BinaryOperator.Sub: // Cast values to double, apply operation and create constant expression return new ConstantExpression(Primitive.Double, ((double)(leftOperand as ConstantExpression).value - (double)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo)); // Compute multiplication case BinaryOperator.Mul: // Cast values to double, apply operation and create constant expression return new ConstantExpression(Primitive.Double, ((double)(leftOperand as ConstantExpression).value * (double)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo)); // Compute division case BinaryOperator.Div: // Cast values to double, apply operation and create constant expression return new ConstantExpression(Primitive.Double, ((double)(leftOperand as ConstantExpression).value / (double)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo)); } } // If type is integer else if (leftOperand.returnType.Equals(PrimitiveType.INT)) { switch (op) { // Compute equality case BinaryOperator.Eq: // Cast values to int, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (int)(leftOperand as ConstantExpression).value == (int)(rightOperand as ConstantExpression).value); // Compute non-equality case BinaryOperator.Neq: // Cast values to int, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (int)(leftOperand as ConstantExpression).value != (int)(rightOperand as ConstantExpression).value); // Compute greater than case BinaryOperator.Gt: // Cast values to int, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (int)(leftOperand as ConstantExpression).value > (int)(rightOperand as ConstantExpression).value); // Compute greater than or equal to case BinaryOperator.Geq: // Cast values to int, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (int)(leftOperand as ConstantExpression).value >= (int)(rightOperand as ConstantExpression).value); // Compute less than case BinaryOperator.Lt: // Cast values to int, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (int)(leftOperand as ConstantExpression).value < (int)(rightOperand as ConstantExpression).value); // Compute less than or equal to case BinaryOperator.Leq: // Cast values to int, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (int)(leftOperand as ConstantExpression).value <= (int)(rightOperand as ConstantExpression).value); // Compute addition case BinaryOperator.Add: // Cast values to int, apply operation and create constant expression return new ConstantExpression(Primitive.Int, ((int)(leftOperand as ConstantExpression).value + (int)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo)); // Compute subtraction case BinaryOperator.Sub: // Cast values to int, apply operation and create constant expression return new ConstantExpression(Primitive.Int, ((int)(leftOperand as ConstantExpression).value - (int)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo)); // Compute multiplication case BinaryOperator.Mul: // Cast values to int, apply operation and create constant expression return new ConstantExpression(Primitive.Int, ((int)(leftOperand as ConstantExpression).value * (int)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo)); // Compute division case BinaryOperator.Div: // Cast values to int, apply operation and create constant expression return new ConstantExpression(Primitive.Int, ((int)(leftOperand as ConstantExpression).value / (int)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo)); // Compute modulo case BinaryOperator.Rem: // Cast values to int, apply operation and create constant expression return new ConstantExpression(Primitive.Int, ((int)(leftOperand as ConstantExpression).value % (int)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo)); } } // If type is string else if (leftOperand.returnType.Equals(PrimitiveType.STRING)) { switch (op) { // Compute equality case BinaryOperator.Eq: // Convert values to string, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (leftOperand as ConstantExpression).value.ToString() == (rightOperand as ConstantExpression).value.ToString()); // Compute non-equality case BinaryOperator.Neq: // Convert values to string, apply operation and create constant (boolean) expression return new ConstantExpression(Primitive.Bool, (leftOperand as ConstantExpression).value.ToString() != (rightOperand as ConstantExpression).value.ToString()); // Compute addition case BinaryOperator.Add: // Convert values to string, apply operation and create constant expression return new ConstantExpression(Primitive.String, (leftOperand as ConstantExpression).value.ToString() + (rightOperand as ConstantExpression).value.ToString()); } } } return this; }
/// <summary> /// Evaluates this node and all its children /// </summary> /// <param name="scope">The scope of this expression</param> /// <returns></returns> public override Expression Evaluate(Scope scope) { // Evaluate all arguments for (int i = 0; i < arguments.Count; i++) { arguments[i] = arguments[i].Evaluate(scope); } // Get signature from symbol table Signature sig = scope.GetFunction(this); // If no function is retrieved if (sig == null) { // Unknown function error Compiler.Compiler.errors.SemErr(t.line, t.col, "Unknown function or ambiguos call to " + methodName); } else { // Set return type this.returnType = sig.returnType; // Step through each argument for (int i = 0; i < sig.arguments.Count; i++) { // If argument expression type is different than expected argument // Arguments are guaranteed to be compatible since a matching signature was found in the symbol table if (!arguments[i].returnType.Equals(sig.arguments[i])) { // Create implicit type cast to expected argument Expression expr = arguments[i]; arguments[i] = new CastExpression(sig.arguments[i]); (arguments[i] as CastExpression).operand = expr; } } } return this; }
/// <summary> /// Evaluates this node and all of its children /// </summary> /// <param name="scope">The scope of this statement</param> /// <returns></returns> public override Statement Evaluate(Scope scope) { LocalScope localScope = scope as LocalScope; // If expr is not null, we must match return value with function return type if (expr != null) { // Evaluate inner expression expr.Evaluate(scope); // If return type is different than function return type if (!expr.returnType.Equals(localScope.returnType)) { // Check if an implicit typecast exists if (expr.returnType.IsCompatible(localScope.returnType)) { // Create typecast CastExpression newExpr = new CastExpression(localScope.returnType); newExpr.operand = expr; this.expr = newExpr; } else { // Issue error Compiler.Compiler.errors.SemErr(t.line, t.col, "invalid return type"); } } } else { // If function returns void but we provide a different type if (localScope.returnType.ToCLRType() != Type.GetType("System.Void")) { // Issue error Compiler.Compiler.errors.SemErr(t.line, t.col, "function should return " + localScope.returnType); } } return this; }