public override ABT.Expr GetExpr(ABT.Env env) {
var left = SemantExpr(this.Left, ref env);
var right = SemantExpr(this.Right, ref env);
if (left.Type is ABT.ArrayType) {
left = ABT.TypeCast.MakeCast(left, new ABT.PointerType((left.Type as ABT.ArrayType).ElemType, left.Type.IsConst, left.Type.IsVolatile));
}
if (right.Type is ABT.ArrayType) {
right = ABT.TypeCast.MakeCast(right, new ABT.PointerType((right.Type as ABT.ArrayType).ElemType, right.Type.IsConst, right.Type.IsVolatile));
}
var isConst = left.Type.IsConst || right.Type.IsConst;
var isVolatile = left.Type.IsVolatile || right.Type.IsVolatile;
if (left.Type.Kind == ABT.ExprTypeKind.POINTER) {
// 1. ptr - ptr
if (right.Type.Kind == ABT.ExprTypeKind.POINTER) {
ABT.PointerType leftType = (ABT.PointerType)(left.Type);
ABT.PointerType rightType = (ABT.PointerType)(right.Type);
if (!leftType.RefType.EqualType(rightType.RefType)) {
throw new InvalidOperationException("The 2 pointers don't match.");
}
Int32 scale = leftType.RefType.SizeOf;
if (left.IsConstExpr && right.IsConstExpr) {
return new ABT.ConstLong((Int32)(((ABT.ConstPtr)left).Value - ((ABT.ConstPtr)right).Value) / scale, env);
}
return new ABT.Divide(
new ABT.Sub(
ABT.TypeCast.MakeCast(left, new ABT.LongType(isConst, isVolatile)),
ABT.TypeCast.MakeCast(right, new ABT.LongType(isConst, isVolatile))
),
new ABT.ConstLong(scale, env)
);
}
// 2. ptr - integral
if (!right.Type.IsIntegral) {
throw new InvalidOperationException("Expected an integral.");
}
right = ABT.TypeCast.MakeCast(right, new ABT.LongType(right.Type.IsConst, right.Type.IsVolatile));
return GetPointerSubtraction(left, right);
}
// 3. arith - arith
return base.GetExpr(env);
}
}