protected BinaryOpSupportingArithmeticOperands(Expr left, Expr right) : base(left, right) { if (!(left.Type is LongType || left.Type is ULongType || left.Type is FloatType || left.Type is DoubleType)) { throw new InvalidOperationException("Only support long, ulong, float, double."); } }
protected BinaryOpSupportingOnlyIntegralOperands(Expr left, Expr right) : base(left, right) { if (!(left.Type is LongType || left.Type is ULongType)) { throw new InvalidOperationException("Only support long or ulong."); } this.Type = left.Type.GetQualifiedType(true, false); }
public Assign(Expr left, Expr right) { this.Left = left; this.Right = right; if (!this.Left.IsLValue) { throw new InvalidOperationException("Can only assign to lvalue."); } }
public Tuple <Env, String, Int32> GetEnumerator(Env env, Int32 idx) { if (this.Init.IsNone) { return(new Tuple <Env, String, Int32>(env, this.Name, idx)); } ABT.Expr init = this.Init.Value.GetExpr(env); init = ABT.TypeCast.MakeCast(init, new LongType()); if (!init.IsConstExpr) { throw new InvalidOperationException("Error: expected constant integer"); } Int32 initIdx = ((ConstLong)init).Value; return(new Tuple <Env, String, int>(env, this.Name, initIdx)); }
public Reference(Expr expr) { this.Expr = expr; this.Type = new PointerType(expr.Type); }
public Attribute(Expr expr, String name, ExprType type) { this.Expr = expr; this.Name = name; this.Type = type; }
public FuncCall(Expr func, FunctionType funcType, List<Expr> args) { this.Func = func; this.FuncType = funcType; this.Args = args; }
/// <summary> /// From: /// pointer /// To: /// pointer, integral /// </summary> public static Expr FromPointer(Expr expr, ExprType type, Env env) { ExprTypeKind from = expr.Type.Kind; ExprTypeKind to = type.Kind; if (from != ExprTypeKind.POINTER) { throw new InvalidOperationException("Expected a pointer."); } // if we are casting to another pointer, do a nop if (to == ExprTypeKind.POINTER) { if (expr.IsConstExpr) { return new ConstPtr(((ConstPtr)expr).Value, type, env); } return new TypeCast(TypeCastType.NOP, expr, type, env); } // if we are casting to an integral if (type.IsIntegral) { // pointer -> ulong -> whatever integral if (expr.IsConstExpr) { expr = new ConstULong(((ConstPtr)expr).Value, env); } else { expr = new TypeCast(TypeCastType.NOP, expr, new ULongType(type.IsConst, type.IsVolatile), env); } return MakeCast(expr, type, env); } throw new InvalidOperationException("Casting from a pointer to an unsupported Type."); }
public BitwiseNot(Expr expr) : base(expr) { if (!(expr.Type is LongType || expr.Type is ULongType)) { throw new InvalidOperationException("Invalid operand type."); } }
protected UnaryArithOp(Expr expr) { this.Expr = expr; }
// MakeCast // ======== // input: Expr, Type // output: TypeCast // converts Expr to Type // public static Expr MakeCast(Expr expr, ExprType type, Env env) { // if two types are equal, return Expr if (EqualType(expr.Type, type)) { return expr; } // from pointer if (expr.Type.Kind == ExprTypeKind.POINTER) { return FromPointer(expr, type, env); } // to pointer if (type.Kind == ExprTypeKind.POINTER) { return ToPointer(expr, type, env); } switch (expr.Type.Kind) { // from signed integral case ExprTypeKind.CHAR: case ExprTypeKind.SHORT: case ExprTypeKind.LONG: return SignedIntegralToArith(expr, type); // from unsigned integral case ExprTypeKind.UCHAR: case ExprTypeKind.USHORT: case ExprTypeKind.ULONG: return UnsignedIntegralToArith(expr, type); // from float case ExprTypeKind.FLOAT: case ExprTypeKind.DOUBLE: return FloatToArith(expr, type); case ExprTypeKind.VOID: case ExprTypeKind.POINTER: case ExprTypeKind.FUNCTION: case ExprTypeKind.ARRAY: case ExprTypeKind.INCOMPLETE_ARRAY: case ExprTypeKind.STRUCT_OR_UNION: default: throw new InvalidOperationException("Error: expression Type not supported for casting from."); } }
public LogicalNot(Expr expr) : base(expr) { if (!(expr.Type is LongType || expr.Type is ULongType || expr.Type is FloatType || expr.Type is DoubleType)) { throw new InvalidOperationException("Invalid operand type."); } }
public ConditionalExpr(Expr cond, Expr trueExpr, Expr falseExpr, ExprType type) { this.Cond = cond; this.TrueExpr = trueExpr; this.FalseExpr = falseExpr; this.Type = type; }
/// <summary> /// All integrals are converted to <see cref="LongType"/> or <see cref="ULongType"/>. /// </summary> /// <param name="expr"> /// The integral expression to be casted. /// </param> /// <returns> /// The casted expression and an <see cref="ExprTypeKind"/>. /// Possible return types: <see cref="LongType"/>, <see cref="ULongType"/>. /// </returns> public static Tuple<Expr, ExprTypeKind> IntegralPromotion(Expr expr) { if (!expr.Type.IsIntegral) { throw new InvalidProgramException(); } switch (expr.Type.Kind) { case ExprTypeKind.CHAR: case ExprTypeKind.SHORT: case ExprTypeKind.LONG: return Tuple.Create(MakeCast(expr, new LongType(expr.Type.IsConst, expr.Type.IsVolatile)), ExprTypeKind.LONG); case ExprTypeKind.UCHAR: case ExprTypeKind.USHORT: case ExprTypeKind.ULONG: return Tuple.Create(MakeCast(expr, new ULongType(expr.Type.IsConst, expr.Type.IsVolatile)), ExprTypeKind.ULONG); default: throw new InvalidProgramException(); } }
/// <summary> /// First, convert pointers to <see cref="ULongType"/>'s, then do <see cref="UsualArithmeticConversion"/>. /// </summary> /// <param name="e1"> /// The first expression to be casted. /// </param> /// <param name="e2"> /// The second expression to be casted. /// </param> /// <returns> /// The two converted expressions and an <see cref="ExprTypeKind"/>. /// Possible return types: <see cref="DoubleType"/>, <see cref="FloatType"/>, <see cref="ULongType"/>, <see cref="LongType"/>. /// </returns> public static Tuple<Expr, Expr, ExprTypeKind> UsualScalarConversion(Expr e1, Expr e2) { if (e1.Type.Kind == ExprTypeKind.POINTER) { e1 = FromPointer(e1, new ULongType(e1.Type.IsConst, e1.Type.IsVolatile), e2.Env); } if (e2.Type.Kind == ExprTypeKind.POINTER) { e2 = FromPointer(e2, new ULongType(e2.Type.IsConst, e2.Type.IsVolatile), e2.Env); } return UsualArithmeticConversion(e1, e2); }
/// <summary> /// From: /// char, short, long /// To: /// char, uchar, short, ushort, long, ulong, float double /// </summary> public static Expr SignedIntegralToArith(Expr expr, ExprType type) { ExprTypeKind from = expr.Type.Kind; ExprTypeKind to = type.Kind; Env env = expr.Env; switch (from) { case ExprTypeKind.CHAR: switch (to) { case ExprTypeKind.SHORT: case ExprTypeKind.USHORT: return new TypeCast(TypeCastType.INT8_TO_INT16, expr, type); case ExprTypeKind.LONG: case ExprTypeKind.ULONG: return new TypeCast(TypeCastType.INT8_TO_INT32, expr, type); case ExprTypeKind.UCHAR: return new TypeCast(TypeCastType.NOP, expr, type); case ExprTypeKind.FLOAT: // char -> long -> float return new TypeCast(TypeCastType.INT32_TO_FLOAT, new TypeCast(TypeCastType.INT8_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type); case ExprTypeKind.DOUBLE: // char -> long -> double return new TypeCast(TypeCastType.INT32_TO_DOUBLE, new TypeCast(TypeCastType.INT8_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type); case ExprTypeKind.VOID: case ExprTypeKind.POINTER: case ExprTypeKind.FUNCTION: case ExprTypeKind.ARRAY: case ExprTypeKind.INCOMPLETE_ARRAY: case ExprTypeKind.STRUCT_OR_UNION: case ExprTypeKind.CHAR: default: throw new InvalidProgramException($"Cannot cast from {from} to {to}"); } case ExprTypeKind.SHORT: switch (to) { case ExprTypeKind.CHAR: case ExprTypeKind.UCHAR: return new TypeCast(TypeCastType.PRESERVE_INT8, expr, type); case ExprTypeKind.USHORT: return new TypeCast(TypeCastType.NOP, expr, type); case ExprTypeKind.LONG: case ExprTypeKind.ULONG: return new TypeCast(TypeCastType.INT16_TO_INT32, expr, type); case ExprTypeKind.FLOAT: // short -> long -> float return new TypeCast(TypeCastType.INT32_TO_FLOAT, new TypeCast(TypeCastType.INT16_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type); case ExprTypeKind.DOUBLE: // short -> long -> double return new TypeCast(TypeCastType.INT32_TO_DOUBLE, new TypeCast(TypeCastType.INT16_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type); case ExprTypeKind.VOID: case ExprTypeKind.SHORT: case ExprTypeKind.POINTER: case ExprTypeKind.FUNCTION: case ExprTypeKind.ARRAY: case ExprTypeKind.INCOMPLETE_ARRAY: case ExprTypeKind.STRUCT_OR_UNION: default: throw new InvalidProgramException($"Cannot cast from {from} to {to}"); } case ExprTypeKind.LONG: switch (to) { case ExprTypeKind.CHAR: if (expr.IsConstExpr) { return new ConstChar((SByte)((ConstLong)expr).Value, env); } return new TypeCast(TypeCastType.PRESERVE_INT8, expr, type); case ExprTypeKind.UCHAR: if (expr.IsConstExpr) { return new ConstUChar((Byte)((ConstLong)expr).Value, env); } return new TypeCast(TypeCastType.PRESERVE_INT8, expr, type); case ExprTypeKind.SHORT: if (expr.IsConstExpr) { return new ConstShort((Int16)((ConstLong)expr).Value, env); } return new TypeCast(TypeCastType.PRESERVE_INT16, expr, type); case ExprTypeKind.USHORT: if (expr.IsConstExpr) { return new ConstUShort((UInt16)((ConstLong)expr).Value, env); } return new TypeCast(TypeCastType.PRESERVE_INT16, expr, type); case ExprTypeKind.ULONG: if (expr.IsConstExpr) { return new ConstULong((UInt32)((ConstLong)expr).Value, env); } return new TypeCast(TypeCastType.NOP, expr, type); case ExprTypeKind.FLOAT: if (expr.IsConstExpr) { return new ConstFloat(((ConstLong)expr).Value, env); } return new TypeCast(TypeCastType.INT32_TO_FLOAT, expr, type); case ExprTypeKind.DOUBLE: if (expr.IsConstExpr) { return new ConstDouble(((ConstLong)expr).Value, env); } return new TypeCast(TypeCastType.INT32_TO_DOUBLE, expr, type); case ExprTypeKind.VOID: case ExprTypeKind.LONG: case ExprTypeKind.POINTER: case ExprTypeKind.FUNCTION: case ExprTypeKind.ARRAY: case ExprTypeKind.INCOMPLETE_ARRAY: case ExprTypeKind.STRUCT_OR_UNION: default: throw new InvalidProgramException($"Cannot cast from {from} to {to}"); } default: throw new InvalidProgramException(); } }
/// <summary> /// <para>Perform the usual arithmetic conversion on two expressions.</para> /// <para>If either expression is <see cref="DoubleType"/>, then both are converted to <see cref="DoubleType"/>.</para> /// <para>Else, if either expression is <see cref="FloatType"/>, then both are converted to <see cref="FloatType"/>.</para> /// <para>Else, if either expression is <see cref="ULongType"/>, then both are converted to <see cref="ULongType"/>.</para> /// <para>Else, both are converted to <see cref="LongType"/>.</para> /// </summary> /// <param name="e1">The first expression to be casted. Must have <see cref="ArithmeticType"/>.</param> /// <param name="e2">The second expression to be casted. Must have <see cref="ArithmeticType"/>.</param> /// <returns> /// The two casted expressions, and an <see cref="ExprTypeKind"/>. /// </returns> public static Tuple<Expr, Expr, ExprTypeKind> UsualArithmeticConversion(Expr e1, Expr e2) { ExprType t1 = e1.Type; ExprType t2 = e2.Type; Boolean c1 = t1.IsConst; Boolean v1 = t1.IsVolatile; Boolean c2 = t2.IsConst; Boolean v2 = t2.IsVolatile; // 1. if either Expr is double: both are converted to double if (t1.Kind == ExprTypeKind.DOUBLE || t2.Kind == ExprTypeKind.DOUBLE) { return new Tuple<Expr, Expr, ExprTypeKind>(MakeCast(e1, new DoubleType(c1, v1)), MakeCast(e2, new DoubleType(c2, v2)), ExprTypeKind.DOUBLE); } // 2. if either Expr is float: both are converted to float if (t1.Kind == ExprTypeKind.FLOAT || t2.Kind == ExprTypeKind.FLOAT) { return new Tuple<Expr, Expr, ExprTypeKind>(MakeCast(e1, new FloatType(c1, v1)), MakeCast(e2, new FloatType(c2, v2)), ExprTypeKind.FLOAT); } // 3. if either Expr is unsigned long: both are converted to unsigned long if (t1.Kind == ExprTypeKind.ULONG || t2.Kind == ExprTypeKind.ULONG) { return new Tuple<Expr, Expr, ExprTypeKind>(MakeCast(e1, new ULongType(c1, v1)), MakeCast(e2, new ULongType(c2, v2)), ExprTypeKind.ULONG); } // 4. both are converted to long return new Tuple<Expr, Expr, ExprTypeKind>(MakeCast(e1, new LongType(c1, v1)), MakeCast(e2, new LongType(c2, v2)), ExprTypeKind.LONG); }
public static Expr MakeCast(Expr expr, ExprType type) => MakeCast(expr, type, expr.Env);
public Dereference(Expr expr, ExprType type) { this.Expr = expr; this.Type = type; }
public PreIncrement(Expr expr) : base(expr) { }
/// <summary> /// From: /// pointer, integral /// To: /// pointer /// </summary> public static Expr ToPointer(Expr expr, ExprType type, Env env) { ExprTypeKind from = expr.Type.Kind; ExprTypeKind to = type.Kind; if (to != ExprTypeKind.POINTER) { throw new InvalidOperationException("Error: expected casting to pointer."); } if (from == ExprTypeKind.POINTER) { if (expr.IsConstExpr) { return new ConstPtr(((ConstPtr)expr).Value, type, env); } return new TypeCast(TypeCastType.NOP, expr, type, env); } if (expr.Type.IsIntegral) { // if we are casting from an integral // whatever integral -> ulong switch (expr.Type.Kind) { case ExprTypeKind.CHAR: case ExprTypeKind.SHORT: case ExprTypeKind.LONG: expr = SignedIntegralToArith(expr, new ULongType(type.IsConst, type.IsVolatile)); break; case ExprTypeKind.UCHAR: case ExprTypeKind.USHORT: case ExprTypeKind.ULONG: expr = UnsignedIntegralToArith(expr, new ULongType(type.IsConst, type.IsVolatile)); break; default: break; } // ulong -> pointer if (expr.IsConstExpr) { return new ConstPtr(((ConstULong)expr).Value, type, env); } return new TypeCast(TypeCastType.NOP, expr, type, env); } if (expr.Type is FunctionType) { if (!expr.Type.EqualType(((PointerType)type).RefType)) { throw new InvalidOperationException("Casting from an incompatible function."); } // TODO: only allow compatible Type? return new TypeCast(TypeCastType.NOP, expr, type, env); } if (expr.Type is ArrayType) { // TODO: allow any pointer Type to cast to? return new TypeCast(TypeCastType.NOP, expr, type, env); } throw new InvalidOperationException("Error: casting from an unsupported Type to pointer."); }
protected IncDecExpr(Expr expr) { if (!(expr.Type is ScalarType)) { throw new InvalidOperationException("Only supports scalars."); } this.Expr = expr; }
public WhileStmt(Expr cond, Stmt body) { if (!cond.Type.IsScalar) { throw new InvalidProgramException(); } this.Cond = cond; this.Body = body; }
public PostDecrement(Expr expr) : base(expr) { }
public DoWhileStmt(Stmt body, Expr cond) { this.Body = body; this.Cond = cond; }
public PreDecrement(Expr expr) : base(expr) { }
public SwitchStmt(Expr expr, Stmt stmt) { this.Expr = expr; this.Stmt = stmt; }
public Negative(Expr expr) : base(expr) { }
public IfStmt(Expr cond, Stmt stmt) { this.Cond = cond; this.Stmt = stmt; }
public InitExpr(Expr expr) { this.expr = expr; }
public IfElseStmt(Expr cond, Stmt trueStmt, Stmt falseStmt) { this.Cond = cond; this.TrueStmt = trueStmt; this.FalseStmt = falseStmt; }