IFPSTools.NET/LibIFPSCC/AST/BinaryOperators.cs
zc e16c00799d ifpscc: initial commit
libifpscc: initial commit
readme: document ifpscc/libifpscc
license: add credits for ifpscc/libifpscc (derived from code also MIT licensed)
libifps: make additional fields/types public for libifpscc
libifps: fix field documentation for some opcodes
libifps: fix loading functions that are not exported
libifps: allow saving a nonexistant primitive type if the same primitive type was added already
libifps: fix parsing Extended constants
libifps: fix ushort/short being mapped to the wrong types in one table
csproj: set Prefer32Bit=false for release builds
2023-03-28 17:24:19 +01:00

792 lines
40 KiB
C#

using System;
namespace AST {
using static SemanticAnalysis;
/// <summary>
/// Binary operator: Left op Right
/// </summary>
public abstract class BinaryOp : Expr {
protected BinaryOp(Expr left, Expr right) {
this.Left = left;
this.Right = right;
}
public Expr Left { get; }
public Expr Right { get; }
}
/// <summary>
/// Binary integral operator: takes in two integrals, returns an integer.
/// </summary>
public abstract class BinaryIntegralOp : BinaryOp {
protected BinaryIntegralOp(Expr left, Expr right)
: base(left, right) { }
public abstract Int32 OperateLong(Int32 left, Int32 right);
public abstract UInt32 OperateULong(UInt32 left, UInt32 right);
public abstract long OperateS64(long left, long right);
public abstract ulong OperateU64(ulong left, ulong right);
public virtual string OperateString(string left, string right)
{
throw new InvalidOperationException("Does not support string").Attach(Left);
}
public abstract ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type);
protected override ABT.Expr GetExprImpl(ABT.Env env, ILineInfo info)
{
// 1. semant operands
var left = SemantExpr(this.Left, ref env);
var right = SemantExpr(this.Right, ref env);
// 2. perform usual arithmetic conversion
Tuple<ABT.Expr, ABT.Expr, ABT.ExprTypeKind> castReturn = ABT.TypeCast.UsualArithmeticConversion(left, right);
left = castReturn.Item1;
right = castReturn.Item2;
var typeKind = castReturn.Item3;
var isConst = left.Type.IsConst || right.Type.IsConst;
var isVolatile = left.Type.IsVolatile || right.Type.IsVolatile;
// 3. if both operands are constants
if (left.IsConstExpr && right.IsConstExpr) {
switch (typeKind) {
case ABT.ExprTypeKind.ULONG:
return new ABT.ConstULong(OperateULong(((ABT.ConstULong)left).Value, ((ABT.ConstULong)right).Value), env);
case ABT.ExprTypeKind.LONG:
return new ABT.ConstLong(OperateLong(((ABT.ConstLong)left).Value, ((ABT.ConstLong)right).Value), env);
case ABT.ExprTypeKind.U64:
return new ABT.ConstU64(OperateU64(((ABT.ConstU64)left).Value, ((ABT.ConstU64)right).Value), env);
case ABT.ExprTypeKind.S64:
return new ABT.ConstS64(OperateS64(((ABT.ConstS64)left).Value, ((ABT.ConstS64)right).Value), env);
case ABT.ExprTypeKind.ANSI_STRING:
return new ABT.ConstStringLiteral(OperateString(((ABT.ConstStringLiteral)left).Value, ((ABT.ConstStringLiteral)right).Value), env);
case ABT.ExprTypeKind.UNICODE_STRING:
return new ABT.ConstUnicodeStringLiteral(OperateString(((ABT.ConstUnicodeStringLiteral)left).Value, ((ABT.ConstUnicodeStringLiteral)right).Value), env);
default:
throw new InvalidOperationException("Expected long or unsigned long.").Attach(Left);
}
}
// 4. if not both operands are constants
switch (typeKind) {
case ABT.ExprTypeKind.ULONG:
return ConstructExpr(left, right, new ABT.ULongType(isConst, isVolatile));
case ABT.ExprTypeKind.LONG:
return ConstructExpr(left, right, new ABT.LongType(isConst, isVolatile));
case ABT.ExprTypeKind.U64:
return ConstructExpr(left, right, new ABT.U64Type(isConst, isVolatile));
case ABT.ExprTypeKind.S64:
return ConstructExpr(left, right, new ABT.S64Type(isConst, isVolatile));
case ABT.ExprTypeKind.ANSI_STRING:
return ConstructExpr(left, right, new ABT.AnsiStringType(isConst, isVolatile));
case ABT.ExprTypeKind.UNICODE_STRING:
return ConstructExpr(left, right, new ABT.UnicodeStringType(isConst, isVolatile));
case ABT.ExprTypeKind.COM_VARIANT:
return ConstructExpr(left, right, new ABT.ComVariantType(isConst, isVolatile));
default:
throw new InvalidOperationException("Expected long or unsigned long.").Attach(Left);
}
}
}
/// <summary>
/// Binary integral operator: takes in two int/uint/float/double, returns an int/uint/float/double.
/// </summary>
public abstract class BinaryArithmeticOp : BinaryIntegralOp {
protected BinaryArithmeticOp(Expr left, Expr right)
: base(left, right) { }
public abstract Single OperateFloat(Single left, Single right);
public abstract Double OperateDouble(Double left, Double right);
protected override ABT.Expr GetExprImpl(ABT.Env env, ILineInfo info)
{
// 1. semant operands
var left = SemantExpr(this.Left, ref env);
var right = SemantExpr(this.Right, ref env);
// 2. perform usual arithmetic conversion
Tuple<ABT.Expr, ABT.Expr, ABT.ExprTypeKind> castReturn = ABT.TypeCast.UsualArithmeticConversion(left, right);
left = castReturn.Item1;
right = castReturn.Item2;
var typeKind = castReturn.Item3;
var isConst = left.Type.IsConst || right.Type.IsConst;
var isVolatile = left.Type.IsVolatile || right.Type.IsVolatile;
// 3. if both operands are constants
if (left.IsConstExpr && right.IsConstExpr) {
switch (typeKind) {
case ABT.ExprTypeKind.DOUBLE:
return new ABT.ConstDouble(OperateDouble(((ABT.ConstDouble)left).Value, ((ABT.ConstDouble)right).Value), env);
case ABT.ExprTypeKind.FLOAT:
return new ABT.ConstFloat(OperateFloat(((ABT.ConstFloat)left).Value, ((ABT.ConstFloat)right).Value), env);
case ABT.ExprTypeKind.ULONG:
return new ABT.ConstULong(OperateULong(((ABT.ConstULong)left).Value, ((ABT.ConstULong)right).Value), env);
case ABT.ExprTypeKind.LONG:
return new ABT.ConstLong(OperateLong(((ABT.ConstLong)left).Value, ((ABT.ConstLong)right).Value), env);
case ABT.ExprTypeKind.U64:
return new ABT.ConstU64(OperateU64(((ABT.ConstU64)left).Value, ((ABT.ConstU64)right).Value), env);
case ABT.ExprTypeKind.S64:
return new ABT.ConstS64(OperateS64(((ABT.ConstS64)left).Value, ((ABT.ConstS64)right).Value), env);
case ABT.ExprTypeKind.ANSI_STRING:
return new ABT.ConstStringLiteral(OperateString(((ABT.ConstStringLiteral)left).Value, ((ABT.ConstStringLiteral)right).Value), env);
case ABT.ExprTypeKind.UNICODE_STRING:
return new ABT.ConstUnicodeStringLiteral(OperateString(((ABT.ConstUnicodeStringLiteral)left).Value, ((ABT.ConstUnicodeStringLiteral)right).Value), env);
default:
throw new InvalidOperationException("Expected arithmetic Type.").Attach(Left);
}
}
// 4. if not both operands are constants
switch (typeKind) {
case ABT.ExprTypeKind.DOUBLE:
return ConstructExpr(left, right, new ABT.DoubleType(isConst, isVolatile));
case ABT.ExprTypeKind.FLOAT:
return ConstructExpr(left, right, new ABT.FloatType(isConst, isVolatile));
case ABT.ExprTypeKind.ULONG:
return ConstructExpr(left, right, new ABT.ULongType(isConst, isVolatile));
case ABT.ExprTypeKind.LONG:
return ConstructExpr(left, right, new ABT.LongType(isConst, isVolatile));
case ABT.ExprTypeKind.U64:
return ConstructExpr(left, right, new ABT.U64Type(isConst, isVolatile));
case ABT.ExprTypeKind.S64:
return ConstructExpr(left, right, new ABT.S64Type(isConst, isVolatile));
case ABT.ExprTypeKind.ANSI_STRING:
return ConstructExpr(left, right, new ABT.AnsiStringType(isConst, isVolatile));
case ABT.ExprTypeKind.UNICODE_STRING:
return ConstructExpr(left, right, new ABT.UnicodeStringType(isConst, isVolatile));
case ABT.ExprTypeKind.COM_VARIANT:
return ConstructExpr(left, right, new ABT.ComVariantType(isConst, isVolatile));
default:
throw new InvalidOperationException("Expected arithmetic Type.").Attach(Left);
}
}
}
/// <summary>
/// Binary logical operator: first turn pointers to ulongs, then always returns long.
/// </summary>
public abstract class BinaryLogicalOp : BinaryOp {
protected BinaryLogicalOp(Expr left, Expr right)
: base(left, right) { }
public abstract Int32 OperateLong(Int32 left, Int32 right);
public abstract Int32 OperateULong(UInt32 left, UInt32 right);
public abstract int OperateS64(long left, long right);
public abstract int OperateU64(ulong left, ulong right);
public abstract Int32 OperateFloat(Single left, Single right);
public abstract Int32 OperateDouble(Double left, Double right);
public abstract ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type);
protected override ABT.Expr GetExprImpl(ABT.Env env, ILineInfo info)
{
// 1. semant operands
var left = SemantExpr(this.Left, ref env);
var right = SemantExpr(this.Right, ref env);
// 2. perform usual scalar conversion
Tuple<ABT.Expr, ABT.Expr, ABT.ExprTypeKind> castReturn = ABT.TypeCast.UsualScalarConversion(left, right);
left = castReturn.Item1;
right = castReturn.Item2;
var typeKind = castReturn.Item3;
var isConst = left.Type.IsConst || right.Type.IsConst;
var isVolatile = left.Type.IsVolatile || right.Type.IsVolatile;
// 3. if both operands are constants
if (left.IsConstExpr && right.IsConstExpr) {
switch (typeKind) {
case ABT.ExprTypeKind.DOUBLE:
return new ABT.ConstLong(OperateDouble(((ABT.ConstDouble)left).Value, ((ABT.ConstDouble)right).Value), env);
case ABT.ExprTypeKind.FLOAT:
return new ABT.ConstLong(OperateFloat(((ABT.ConstFloat)left).Value, ((ABT.ConstFloat)right).Value), env);
case ABT.ExprTypeKind.ULONG:
return new ABT.ConstLong(OperateULong(((ABT.ConstULong)left).Value, ((ABT.ConstULong)right).Value), env);
case ABT.ExprTypeKind.LONG:
return new ABT.ConstLong(OperateLong(((ABT.ConstLong)left).Value, ((ABT.ConstLong)right).Value), env);
case ABT.ExprTypeKind.U64:
return new ABT.ConstLong(OperateU64(((ABT.ConstU64)left).Value, ((ABT.ConstU64)right).Value), env);
case ABT.ExprTypeKind.S64:
return new ABT.ConstLong(OperateS64(((ABT.ConstS64)left).Value, ((ABT.ConstS64)right).Value), env);
default:
throw new InvalidOperationException("Expected arithmetic Type.").Attach(Left);
}
}
// 4. if not both operands are constants
switch (typeKind) {
case ABT.ExprTypeKind.DOUBLE:
return ConstructExpr(left, right, new ABT.LongType(isConst, isVolatile));
case ABT.ExprTypeKind.FLOAT:
return ConstructExpr(left, right, new ABT.LongType(isConst, isVolatile));
case ABT.ExprTypeKind.ULONG:
return ConstructExpr(left, right, new ABT.LongType(isConst, isVolatile));
case ABT.ExprTypeKind.LONG:
return ConstructExpr(left, right, new ABT.LongType(isConst, isVolatile));
case ABT.ExprTypeKind.U64:
return ConstructExpr(left, right, new ABT.LongType(isConst, isVolatile));
case ABT.ExprTypeKind.S64:
return ConstructExpr(left, right, new ABT.LongType(isConst, isVolatile));
case ABT.ExprTypeKind.COM_VARIANT:
return ConstructExpr(left, right, new ABT.ComVariantType(isConst, isVolatile));
default:
throw new InvalidOperationException("Expected arithmetic Type.").Attach(Left);
}
}
}
/// <summary>
/// Multiplication: perform usual arithmetic conversion.
/// </summary>
public sealed class Multiply : BinaryArithmeticOp {
private Multiply(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new Multiply(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => left * right;
public override UInt32 OperateULong(UInt32 left, UInt32 right) => left * right;
public override long OperateS64(long left, long right) => left * right;
public override ulong OperateU64(ulong left, ulong right) => left * right;
public override Single OperateFloat(Single left, Single right) => left * right;
public override Double OperateDouble(Double left, Double right) => left * right;
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.Multiply(left, right);
}
/// <summary>
/// Division: perform usual arithmetic conversion.
/// </summary>
public sealed class Divide : BinaryArithmeticOp {
private Divide(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new Divide(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => left / right;
public override UInt32 OperateULong(UInt32 left, UInt32 right) => left / right;
public override long OperateS64(long left, long right) => left / right;
public override ulong OperateU64(ulong left, ulong right) => left / right;
public override Single OperateFloat(Single left, Single right) => left / right;
public override Double OperateDouble(Double left, Double right) => left / right;
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.Divide(left, right);
}
/// <summary>
/// Modulo: only accepts integrals.
/// </summary>
public sealed class Modulo : BinaryIntegralOp {
private Modulo(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new Modulo(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => left % right;
public override UInt32 OperateULong(UInt32 left, UInt32 right) => left % right;
public override long OperateS64(long left, long right) => left % right;
public override ulong OperateU64(ulong left, ulong right) => left % right;
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.Modulo(left, right);
}
/// <summary>
/// Addition
///
/// There are two kinds of addition:
/// 1. both operands are of arithmetic Type
/// 2. one operand is a pointer, and the other is an integral
/// 3. both operands are strings
///
/// </summary>
public sealed class Add : BinaryArithmeticOp {
private Add(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new Add(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => left + right;
public override UInt32 OperateULong(UInt32 left, UInt32 right) => left + right;
public override long OperateS64(long left, long right) => left + right;
public override ulong OperateU64(ulong left, ulong right) => left + right;
public override Single OperateFloat(Single left, Single right) => left + right;
public override Double OperateDouble(Double left, Double right) => left + right;
public override string OperateString(string left, string right) => left + right;
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.Add(left, right);
public ABT.Expr GetPointerAddition(ABT.Expr ptr, ABT.Expr offset, Boolean order = true) {
if (ptr.Type.Kind != ABT.ExprTypeKind.POINTER) {
throw new InvalidOperationException().Attach(ptr);
}
if (offset.Type.Kind != ABT.ExprTypeKind.LONG) {
throw new InvalidOperationException().Attach(offset);
}
var env = order ? ptr.Env : offset.Env;
if (ptr.IsConstExpr && offset.IsConstExpr) {
var baseValue = (Int32)((ABT.ConstPtr)ptr).Value;
Int32 scaleValue = ((ABT.PointerType)(ptr.Type)).RefType.SizeOf;
Int32 offsetValue = ((ABT.ConstLong)offset).Value;
return new ABT.ConstPtr((UInt32)(baseValue + scaleValue * offsetValue), ptr.Type, env);
}
var baseAddress = ABT.TypeCast.FromPointer(ptr, new ABT.LongType(ptr.Type.IsConst, ptr.Type.IsVolatile), ptr.Env);
var scaleFactor = new ABT.Multiply(
offset,
new ABT.ConstLong(((ABT.PointerType)(ptr.Type)).RefType.SizeOf, env)
);
var type = new ABT.LongType(offset.Type.IsConst, offset.Type.IsVolatile);
var add =
order
? new ABT.Add(baseAddress, scaleFactor)
: new ABT.Add(scaleFactor, baseAddress);
return ABT.TypeCast.ToPointer(add, ptr.Type, env);
}
protected override ABT.Expr GetExprImpl(ABT.Env env, ILineInfo info)
{
// 1. semant the operands
var left = SemantExpr(this.Left, ref env);
var right = SemantExpr(this.Right, ref env);
var leftKind = left.Type.Kind;
var rightKind = right.Type.Kind;
if (leftKind == ABT.ExprTypeKind.ARRAY || leftKind == ABT.ExprTypeKind.INCOMPLETE_ARRAY || rightKind == ABT.ExprTypeKind.ARRAY || rightKind == ABT.ExprTypeKind.INCOMPLETE_ARRAY)
{
if (leftKind == ABT.ExprTypeKind.ARRAY || rightKind == ABT.ExprTypeKind.ARRAY)
{
var arrLeft = left.Type as ABT.ArrayType;
var arrRight = right.Type as ABT.ArrayType;
if (arrLeft != null && right.IsConstExpr)
{
var offset = ABT.TypeCast.MakeCast(right, new ABT.LongType(right.Type.IsConst, right.Type.IsVolatile));
int offsetValue = ((ABT.ConstLong)offset).Value;
if (offsetValue >= arrLeft.NumElems)
{
Console.WriteLine("[Line {0}, column {1}] Potential buffer overflow, decaying to pointer.", Left.Line, Left.Column);
left = ABT.TypeCast.MakeCast(left, new ABT.PointerType(((ABT.ArrayType)left.Type).ElemType, left.Type.IsConst, left.Type.IsVolatile));
arrLeft = null;
leftKind = ABT.ExprTypeKind.POINTER;
}
}
if (arrRight != null && left.IsConstExpr)
{
var offset = ABT.TypeCast.MakeCast(left, new ABT.LongType(left.Type.IsConst, left.Type.IsVolatile));
int offsetValue = ((ABT.ConstLong)offset).Value;
if (offsetValue >= arrRight.NumElems)
{
Console.WriteLine("[Line {0}, column {1}] Potential buffer overflow, decaying to pointer.", Left.Line, Left.Column);
right = ABT.TypeCast.MakeCast(right, new ABT.PointerType(((ABT.ArrayType)right.Type).ElemType, right.Type.IsConst, right.Type.IsVolatile));
arrRight = null;
rightKind = ABT.ExprTypeKind.POINTER;
}
}
}
// if leftKind and rightKind are not pointer, then we can go ahead and set up the array-to-index addition :)
if (leftKind != ABT.ExprTypeKind.POINTER && rightKind != ABT.ExprTypeKind.POINTER)
{
if (leftKind == ABT.ExprTypeKind.ARRAY || leftKind == ABT.ExprTypeKind.INCOMPLETE_ARRAY)
{
if (!right.Type.IsIntegral)
{
throw new InvalidOperationException("Expected integral to be array index.").Attach(right);
}
right = ABT.TypeCast.MakeCast(right, new ABT.ULongType(right.Type.IsConst, right.Type.IsVolatile));
return new ABT.ArrayIndexDeref(left, right);
}
if (!left.Type.IsIntegral)
{
throw new InvalidOperationException("Expected integral to be array index.").Attach(left);
}
left = ABT.TypeCast.MakeCast(left, new ABT.ULongType(left.Type.IsConst, left.Type.IsVolatile));
return new ABT.ArrayIndexDeref(right, left);
}
}
// 2. ptr + int
if (left.Type.Kind == ABT.ExprTypeKind.POINTER) {
if (!right.Type.IsIntegral) {
throw new InvalidOperationException("Expected integral to be added to a pointer.").Attach(right);
}
right = ABT.TypeCast.MakeCast(right, new ABT.LongType(right.Type.IsConst, right.Type.IsVolatile));
return GetPointerAddition(left, right);
}
// 3. int + ptr
if (right.Type.Kind == ABT.ExprTypeKind.POINTER) {
if (!left.Type.IsIntegral) {
throw new InvalidOperationException("Expected integral to be added to a pointer.").Attach(left);
}
left = ABT.TypeCast.MakeCast(left, new ABT.LongType(left.Type.IsConst, left.Type.IsVolatile));
return GetPointerAddition(right, left, false);
}
// 4. usual arithmetic conversion
return base.GetExprImpl(env, info);
}
}
/// <summary>
/// Subtraction
///
/// There are three kinds of subtractions:
/// 1. arithmetic - arithmetic
/// 2. pointer - integral
/// 3. pointer - pointer
/// </summary>
public sealed class Sub : BinaryArithmeticOp {
private Sub(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new Sub(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => left - right;
public override UInt32 OperateULong(UInt32 left, UInt32 right) => left - right;
public override long OperateS64(long left, long right) => left - right;
public override ulong OperateU64(ulong left, ulong right) => left - right;
public override Single OperateFloat(Single left, Single right) => left - right;
public override Double OperateDouble(Double left, Double right) => left - right;
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.Sub(left, right);
public static ABT.Expr GetPointerSubtraction(ABT.Expr ptr, ABT.Expr offset) {
if (ptr.Type.Kind != ABT.ExprTypeKind.POINTER) {
throw new InvalidOperationException("Error: expect a pointer").Attach(ptr);
}
if (offset.Type.Kind != ABT.ExprTypeKind.LONG) {
throw new InvalidOperationException("Error: expect an integer").Attach(offset);
}
if (ptr.IsConstExpr && offset.IsConstExpr) {
Int32 baseAddressValue = (Int32)((ABT.ConstPtr)ptr).Value;
Int32 scaleFactorValue = ((ABT.PointerType)(ptr.Type)).RefType.SizeOf;
Int32 offsetValue = ((ABT.ConstLong)offset).Value;
return new ABT.ConstPtr((UInt32)(baseAddressValue - scaleFactorValue * offsetValue), ptr.Type, offset.Env);
}
return ABT.TypeCast.ToPointer(new ABT.Sub(
ABT.TypeCast.FromPointer(ptr, new ABT.LongType(ptr.Type.IsConst, ptr.Type.IsVolatile), ptr.Env),
new ABT.Multiply(
offset,
new ABT.ConstLong(((ABT.PointerType)(ptr.Type)).RefType.SizeOf, offset.Env)
)
), ptr.Type, offset.Env
);
}
protected override ABT.Expr GetExprImpl(ABT.Env env, ILineInfo info)
{
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.").Attach(left);
}
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.").Attach(right);
}
right = ABT.TypeCast.MakeCast(right, new ABT.LongType(right.Type.IsConst, right.Type.IsVolatile));
return GetPointerSubtraction(left, right);
}
// 3. arith - arith
return base.GetExprImpl(env, info);
}
}
/// <summary>
/// Left Shift: takes in two integrals, returns an integer.
/// </summary>
public sealed class LShift : BinaryIntegralOp {
private LShift(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new LShift(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => left << right;
public override UInt32 OperateULong(UInt32 left, UInt32 right) => (UInt32)((Int32)left << (Int32)right);
public override long OperateS64(long left, long right) => left << (int)right;
public override ulong OperateU64(ulong left, ulong right) => (ulong)((long)left << (int)right);
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.LShift(left, right);
}
/// <summary>
/// Right Shift: takes in two integrals, returns an integer;
/// </summary>
public sealed class RShift : BinaryIntegralOp {
private RShift(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new RShift(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => left >> right;
public override UInt32 OperateULong(UInt32 left, UInt32 right) => (UInt32)((Int32)left >> (Int32)right);
public override long OperateS64(long left, long right) => left >> (int)right;
public override ulong OperateU64(ulong left, ulong right) => (ulong)((long)left >> (int)right);
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.RShift(left, right);
}
/// <summary>
/// Less than
/// </summary>
public sealed class Less : BinaryLogicalOp {
private Less(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new Less(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => Convert.ToInt32(left < right);
public override Int32 OperateULong(UInt32 left, UInt32 right) => Convert.ToInt32(left < right);
public override int OperateS64(long left, long right) => Convert.ToInt32(left < right);
public override int OperateU64(ulong left, ulong right) => Convert.ToInt32(left < right);
public override Int32 OperateFloat(Single left, Single right) => Convert.ToInt32(left < right);
public override Int32 OperateDouble(Double left, Double right) => Convert.ToInt32(left < right);
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.Less(left, right);
}
/// <summary>
/// Less or Equal than
/// </summary>
public sealed class LEqual : BinaryLogicalOp {
private LEqual(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new LEqual(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => Convert.ToInt32(left <= right);
public override Int32 OperateULong(UInt32 left, UInt32 right) => Convert.ToInt32(left <= right);
public override int OperateS64(long left, long right) => Convert.ToInt32(left <= right);
public override int OperateU64(ulong left, ulong right) => Convert.ToInt32(left <= right);
public override Int32 OperateFloat(Single left, Single right) => Convert.ToInt32(left <= right);
public override Int32 OperateDouble(Double left, Double right) => Convert.ToInt32(left <= right);
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.LEqual(left, right);
}
/// <summary>
/// Greater than
/// </summary>
public sealed class Greater : BinaryLogicalOp {
private Greater(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new Greater(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => Convert.ToInt32(left > right);
public override Int32 OperateULong(UInt32 left, UInt32 right) => Convert.ToInt32(left > right);
public override int OperateS64(long left, long right) => Convert.ToInt32(left > right);
public override int OperateU64(ulong left, ulong right) => Convert.ToInt32(left > right);
public override Int32 OperateFloat(Single left, Single right) => Convert.ToInt32(left > right);
public override Int32 OperateDouble(Double left, Double right) => Convert.ToInt32(left > right);
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.Greater(left, right);
}
/// <summary>
/// Greater or Equal than
/// </summary>
public sealed class GEqual : BinaryLogicalOp {
private GEqual(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new GEqual(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => Convert.ToInt32(left >= right);
public override Int32 OperateULong(UInt32 left, UInt32 right) => Convert.ToInt32(left >= right);
public override int OperateS64(long left, long right) => Convert.ToInt32(left >= right);
public override int OperateU64(ulong left, ulong right) => Convert.ToInt32(left >= right);
public override Int32 OperateFloat(Single left, Single right) => Convert.ToInt32(left >= right);
public override Int32 OperateDouble(Double left, Double right) => Convert.ToInt32(left >= right);
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.GEqual(left, right);
}
/// <summary>
/// Equal
/// </summary>
public sealed class Equal : BinaryLogicalOp {
private Equal(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new Equal(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => Convert.ToInt32(left == right);
public override Int32 OperateULong(UInt32 left, UInt32 right) => Convert.ToInt32(left == right);
public override int OperateS64(long left, long right) => Convert.ToInt32(left == right);
public override int OperateU64(ulong left, ulong right) => Convert.ToInt32(left == right);
public override Int32 OperateFloat(Single left, Single right) => Convert.ToInt32(left == right);
public override Int32 OperateDouble(Double left, Double right) => Convert.ToInt32(left == right);
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.Equal(left, right);
}
/// <summary>
/// Not equal
/// </summary>
public sealed class NotEqual : BinaryLogicalOp {
private NotEqual(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new NotEqual(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => Convert.ToInt32(left != right);
public override Int32 OperateULong(UInt32 left, UInt32 right) => Convert.ToInt32(left != right);
public override int OperateS64(long left, long right) => Convert.ToInt32(left != right);
public override int OperateU64(ulong left, ulong right) => Convert.ToInt32(left != right);
public override Int32 OperateFloat(Single left, Single right) => Convert.ToInt32(left != right);
public override Int32 OperateDouble(Double left, Double right) => Convert.ToInt32(left != right);
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.NotEqual(left, right);
}
/// <summary>
/// Bitwise And: returns an integer.
/// </summary>
public sealed class BitwiseAnd : BinaryIntegralOp {
private BitwiseAnd(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new BitwiseAnd(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => left & right;
public override UInt32 OperateULong(UInt32 left, UInt32 right) => left & right;
public override long OperateS64(long left, long right) => left & right;
public override ulong OperateU64(ulong left, ulong right) => left & right;
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.BitwiseAnd(left, right);
}
/// <summary>
/// Xor: returns an integer.
/// </summary>
public sealed class Xor : BinaryIntegralOp {
private Xor(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new Xor(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => left ^ right;
public override UInt32 OperateULong(UInt32 left, UInt32 right) => left ^ right;
public override long OperateS64(long left, long right) => left ^ right;
public override ulong OperateU64(ulong left, ulong right) => left ^ right;
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.Xor(left, right);
}
/// <summary>
/// Bitwise Or: accepts two integrals, returns an integer.
/// </summary>
public sealed class BitwiseOr : BinaryIntegralOp {
private BitwiseOr(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new BitwiseOr(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => left | right;
public override UInt32 OperateULong(UInt32 left, UInt32 right) => left | right;
public override long OperateS64(long left, long right) => left | right;
public override ulong OperateU64(ulong left, ulong right) => left | right;
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.BitwiseOr(left, right);
}
/// <summary>
/// Logical and: both operands need to be non-zero.
/// </summary>
public sealed class LogicalAnd : BinaryLogicalOp {
private LogicalAnd(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) => new LogicalAnd(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => Convert.ToInt32(left != 0 && right != 0);
public override Int32 OperateULong(UInt32 left, UInt32 right) => Convert.ToInt32(left != 0 && right != 0);
public override int OperateS64(long left, long right) => Convert.ToInt32(left != 0 && right != 0);
public override int OperateU64(ulong left, ulong right) => Convert.ToInt32(left != 0 && right != 0);
public override Int32 OperateFloat(Single left, Single right) => Convert.ToInt32(left != 0 && right != 0);
public override Int32 OperateDouble(Double left, Double right) => Convert.ToInt32(left != 0 && right != 0);
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.LogicalAnd(left, right);
}
/// <summary>
/// Logical or: at least one of operands needs to be non-zero.
/// </summary>
public sealed class LogicalOr : BinaryLogicalOp {
private LogicalOr(Expr left, Expr right)
: base(left, right) { }
public static Expr Create(Expr left, Expr right) =>
new LogicalOr(left, right);
public override Int32 OperateLong(Int32 left, Int32 right) => Convert.ToInt32(left != 0 || right != 0);
public override Int32 OperateULong(UInt32 left, UInt32 right) => Convert.ToInt32(left != 0 || right != 0);
public override int OperateS64(long left, long right) => Convert.ToInt32(left != 0 || right != 0);
public override int OperateU64(ulong left, ulong right) => Convert.ToInt32(left != 0 || right != 0);
public override Int32 OperateFloat(Single left, Single right) => Convert.ToInt32(left != 0 || right != 0);
public override Int32 OperateDouble(Double left, Double right) => Convert.ToInt32(left != 0 || right != 0);
public override ABT.Expr ConstructExpr(ABT.Expr left, ABT.Expr right, ABT.ExprType type) =>
new ABT.LogicalOr(left, right);
}
}