// 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 == ExprType.Kind.POINTER) { return FromPointer(expr, type, env); } // to pointer if (type.kind == ExprType.Kind.POINTER) { return ToPointer(expr, type, env); } switch (expr.type.kind) { // from signed integral case ExprType.Kind.CHAR: case ExprType.Kind.SHORT: case ExprType.Kind.LONG: return SignedIntegralToArith(expr, type); // from unsigned integral case ExprType.Kind.UCHAR: case ExprType.Kind.USHORT: case ExprType.Kind.ULONG: return UnsignedIntegralToArith(expr, type); // from float case ExprType.Kind.FLOAT: case ExprType.Kind.DOUBLE: return FloatToArith(expr, type); case ExprType.Kind.VOID: case ExprType.Kind.POINTER: case ExprType.Kind.FUNCTION: case ExprType.Kind.ARRAY: case ExprType.Kind.INCOMPLETE_ARRAY: case ExprType.Kind.STRUCT_OR_UNION: default: throw new InvalidOperationException("Error: expression type not supported for casting from."); } }
// PushEnum // ======== // input: name, type // output: Environment // return a new environment which adds a enum value // public Env PushEnum(String name, ExprType type, Int32 value) { Stack<Scope> scopes = new Stack<Scope>(new Stack<Scope>(env_scopes)); Scope top = scopes.Pop().PushEnum(name, type, value); scopes.Push(top); return new Env(scopes); }
// PushEntry // ========= // input: loc, name, type // output: Scope // returns a new scope with everything the same as this, excpet for a new entry // public Scope PushEntry(EntryKind loc, String name, ExprType type) { Scope scope = new Scope(this); switch (loc) { case EntryKind.STACK: scope.esp_pos -= Utils.RoundUp(type.SizeOf, 4); scope.locals.Add(new Utils.StoreEntry(name, type, scope.esp_pos)); break; case EntryKind.GLOBAL: scope.globals.Add(new Utils.StoreEntry(name, type, 0)); break; case EntryKind.TYPEDEF: scope.typedefs.Add(new Utils.StoreEntry(name, type, 0)); break; default: return null; } return scope; }
protected TFunction(ExprType ret_t, List<Utils.StoreEntry> args, Boolean is_varargs) : base(is_const: true, is_volatile: false) { this.args = args; this.ret_t = ret_t; this.is_varargs = is_varargs; }
public static TFunction Create(ExprType ret_type, List<Tuple<String, ExprType>> args, Boolean is_varargs) { Tuple<Int32, IReadOnlyList<Int32>> r_pack = Utils.PackArguments(args.ConvertAll(_ => _.Item2)); IReadOnlyList<Int32> offsets = r_pack.Item2; if (ret_type is TStructOrUnion) { offsets = offsets.Select(_ => _ + 3 * SIZEOF_POINTER).ToList(); } else { offsets = offsets.Select(_ => _ + 2 * SIZEOF_POINTER).ToList(); } return new TFunction( ret_type, Enumerable.Zip( args, offsets, (name_type, offset) => new Utils.StoreEntry(name_type.Item1, name_type.Item2, offset) ).ToList(), is_varargs ); }
public override Boolean EqualType(ExprType other) => false;
public override Boolean EqualType(ExprType other) => other.kind == Kind.ARRAY && ((TArray)other).elem_type.EqualType(this.elem_type);
public Assign(Expr lvalue, Expr rvalue, ExprType type) : base(type) { this.lvalue = lvalue; this.rvalue = rvalue; }
public ConditionalExpr(Expr cond, Expr true_expr, Expr false_expr, ExprType type) : base(type) { this.cond = cond; this.true_expr = true_expr; this.false_expr = false_expr; }
public AssignList(List<Expr> exprs, ExprType type) : base(type) { this.exprs = exprs; }
public Attribute(Expr expr, String name, ExprType type) : base(type) { this.expr = expr; this.name = name; }
/// <summary> /// From: /// char, short, long /// To: /// char, uchar, short, ushort, long, ulong, float double /// </summary> public static Expr SignedIntegralToArith(Expr expr, ExprType type) { ExprType.Kind from = expr.type.kind; ExprType.Kind to = type.kind; Env env = expr.Env; switch (from) { case ExprType.Kind.CHAR: switch (to) { case ExprType.Kind.SHORT: case ExprType.Kind.USHORT: return new TypeCast(Kind.INT8_TO_INT16, expr, type); case ExprType.Kind.LONG: case ExprType.Kind.ULONG: return new TypeCast(Kind.INT8_TO_INT32, expr, type); case ExprType.Kind.UCHAR: return new TypeCast(Kind.NOP, expr, type); case ExprType.Kind.FLOAT: // char -> long -> float return new TypeCast(Kind.INT32_TO_FLOAT, new TypeCast(Kind.INT8_TO_INT32, expr, new TLong(type.is_const, type.is_volatile)), type); case ExprType.Kind.DOUBLE: // char -> long -> double return new TypeCast(Kind.INT32_TO_DOUBLE, new TypeCast(Kind.INT8_TO_INT32, expr, new TLong(type.is_const, type.is_volatile)), type); case ExprType.Kind.VOID: case ExprType.Kind.POINTER: case ExprType.Kind.FUNCTION: case ExprType.Kind.ARRAY: case ExprType.Kind.INCOMPLETE_ARRAY: case ExprType.Kind.STRUCT_OR_UNION: case ExprType.Kind.CHAR: default: throw new InvalidProgramException($"Cannot cast from {from} to {to}"); } case ExprType.Kind.SHORT: switch (to) { case ExprType.Kind.CHAR: case ExprType.Kind.UCHAR: return new TypeCast(Kind.PRESERVE_INT8, expr, type); case ExprType.Kind.USHORT: return new TypeCast(Kind.NOP, expr, type); case ExprType.Kind.LONG: case ExprType.Kind.ULONG: return new TypeCast(Kind.INT16_TO_INT32, expr, type); case ExprType.Kind.FLOAT: // short -> long -> float return new TypeCast(Kind.INT32_TO_FLOAT, new TypeCast(Kind.INT16_TO_INT32, expr, new TLong(type.is_const, type.is_volatile)), type); case ExprType.Kind.DOUBLE: // short -> long -> double return new TypeCast(Kind.INT32_TO_DOUBLE, new TypeCast(Kind.INT16_TO_INT32, expr, new TLong(type.is_const, type.is_volatile)), type); case ExprType.Kind.VOID: case ExprType.Kind.SHORT: case ExprType.Kind.POINTER: case ExprType.Kind.FUNCTION: case ExprType.Kind.ARRAY: case ExprType.Kind.INCOMPLETE_ARRAY: case ExprType.Kind.STRUCT_OR_UNION: default: throw new InvalidProgramException($"Cannot cast from {from} to {to}"); } case ExprType.Kind.LONG: switch (to) { case ExprType.Kind.CHAR: if (expr.IsConstExpr) { return new ConstLong((Int32)(SByte)((ConstLong)expr).value, env); } else { return new TypeCast(Kind.PRESERVE_INT8, expr, type); } case ExprType.Kind.UCHAR: if (expr.IsConstExpr) { return new ConstULong((UInt32)(Byte)((ConstLong)expr).value, env); } else { return new TypeCast(Kind.PRESERVE_INT8, expr, type); } case ExprType.Kind.SHORT: if (expr.IsConstExpr) { return new ConstLong((Int32)(Int16)((ConstLong)expr).value, env); } else { return new TypeCast(Kind.PRESERVE_INT16, expr, type); } case ExprType.Kind.USHORT: if (expr.IsConstExpr) { return new ConstULong((UInt32)(UInt16)((ConstLong)expr).value, env); } else { return new TypeCast(Kind.PRESERVE_INT16, expr, type); } case ExprType.Kind.ULONG: if (expr.IsConstExpr) { return new ConstULong((UInt32)((ConstLong)expr).value, env); } else { return new TypeCast(Kind.NOP, expr, type); } case ExprType.Kind.FLOAT: if (expr.IsConstExpr) { return new ConstFloat((Single)((ConstLong)expr).value, env); } else { return new TypeCast(Kind.INT32_TO_FLOAT, expr, type); } case ExprType.Kind.DOUBLE: if (expr.IsConstExpr) { return new ConstDouble((Double)((ConstLong)expr).value, env); } else { return new TypeCast(Kind.INT32_TO_DOUBLE, expr, type); } case ExprType.Kind.VOID: case ExprType.Kind.LONG: case ExprType.Kind.POINTER: case ExprType.Kind.FUNCTION: case ExprType.Kind.ARRAY: case ExprType.Kind.INCOMPLETE_ARRAY: case ExprType.Kind.STRUCT_OR_UNION: default: throw new InvalidProgramException($"Cannot cast from {from} to {to}"); } default: throw new InvalidProgramException(); } }
public static Boolean EqualType(ExprType t1, ExprType t2) { return t1.EqualType(t2); }
public static Expr MakeCast(Expr expr, ExprType type) => MakeCast(expr, type, expr.Env);
public override Boolean EqualType(ExprType other) => other.kind == Kind.POINTER && ((TPointer)other).ref_t.EqualType(ref_t);
public Dereference(Expr expr, ExprType type) : base(type) { this.expr = expr; }
public TIncompleteArray(ExprType elem_type, Boolean is_const = false, Boolean is_volatile = false) : base(is_const, is_volatile) { this.elem_type = elem_type; }
protected Expr(ExprType type) { this.type = type; }
public TArray(ExprType elem_type, Int32 num_elems, Boolean is_const = false, Boolean is_volatile = false) : base(is_const, is_volatile) { this.elem_type = elem_type; this.num_elems = num_elems; }
public Variable(ExprType type, String name, Env env) : base(type) { this.name = name; this.Env = env; }
public override Boolean EqualType(ExprType other) => other.kind == Kind.STRUCT_OR_UNION && ReferenceEquals(((TStructOrUnion)other)._layout, this._layout);
public abstract Boolean EqualType(ExprType other);
public override Boolean EqualType(ExprType other) { return (other is TFunction) && (other as TFunction).is_varargs == this.is_varargs // same return type && (other as TFunction).ret_t.EqualType(this.ret_t) // same number of arguments && (other as TFunction).args.Count == this.args.Count // same argument types && (other as TFunction).args.Zip(this.args, (entry1, entry2) => entry1.type.EqualType(entry2.type)).All(_ => _); }
public override Boolean EqualType(ExprType other) => other.kind == Kind.VOID;
// PushEntry // ========= // input: loc, name, type // ouput: Environment // return a new environment which adds a symbol entry // public Env PushEntry(EntryKind loc, String name, ExprType type) { // note the nested copy constructor. this is because the constructor would reverse the elements. Stack<Scope> scopes = new Stack<Scope>(new Stack<Scope>(env_scopes)); Scope top = scopes.Pop().PushEntry(loc, name, type); scopes.Push(top); return new Env(scopes); }
public override Boolean EqualType(ExprType other) => kind == other.kind;
public Entry(EntryKind kind, ExprType type, Int32 offset) { this.kind = kind; this.type = type; this.offset = offset; }
public TPointer(ExprType ref_t, Boolean is_const = false, Boolean is_volatile = false) : base(is_const, is_volatile) { this.ref_t = ref_t; }
// PushEnum // ======== // input: name, type // output: Environment // return a new environment which adds a enum value // public Scope PushEnum(String name, ExprType type, Int32 value) { Scope scope = new Scope(this); scope.enums.Add(new Utils.StoreEntry(name, type, value)); return scope; }
/// <summary> /// From: /// pointer, integral /// To: /// pointer /// </summary> public static Expr ToPointer(Expr expr, ExprType type, Env env) { ExprType.Kind from = expr.type.kind; ExprType.Kind to = type.kind; if (to != ExprType.Kind.POINTER) { throw new InvalidOperationException("Error: expected casting to pointer."); } if (from == ExprType.Kind.POINTER) { if (expr.IsConstExpr) { return new ConstPtr(((ConstPtr)expr).value, type, env); } else { return new TypeCast(Kind.NOP, expr, type, env); } } if (expr.type.IsIntegral) { // if we are casting from an integral // whatever integral -> ulong switch (expr.type.kind) { case ExprType.Kind.CHAR: case ExprType.Kind.SHORT: case ExprType.Kind.LONG: expr = SignedIntegralToArith(expr, new TULong(type.is_const, type.is_volatile)); break; case ExprType.Kind.UCHAR: case ExprType.Kind.USHORT: case ExprType.Kind.ULONG: expr = UnsignedIntegralToArith(expr, new TULong(type.is_const, type.is_volatile)); break; default: break; } // ulong -> pointer if (expr.IsConstExpr) { return new ConstPtr(((ConstULong)expr).value, type, env); } else { return new TypeCast(Kind.NOP, expr, type, env); } } else if (expr.type is TFunction) { if (!expr.type.EqualType((type as TPointer).ref_t)) { throw new InvalidOperationException("Casting from an incompatible function."); } // TODO: only allow compatible type? return new TypeCast(Kind.NOP, expr, type, env); } else if (expr.type is TArray) { // TODO: allow any pointer type to cast to? return new TypeCast(Kind.NOP, expr, type, env); } throw new InvalidOperationException("Error: casting from an unsupported type to pointer."); }