Пример #1
0
        // 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.");
            }

        }
Пример #2
0
 // 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);
 }
Пример #3
0
 // 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;
 }
Пример #4
0
 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;
 }
Пример #5
0
 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
     );
 }
Пример #6
0
 public override Boolean EqualType(ExprType other) => false;
Пример #7
0
 public override Boolean EqualType(ExprType other) =>
     other.kind == Kind.ARRAY && ((TArray)other).elem_type.EqualType(this.elem_type);
Пример #8
0
 public Assign(Expr lvalue, Expr rvalue, ExprType type)
     : base(type)
 {
     this.lvalue = lvalue;
     this.rvalue = rvalue;
 }
Пример #9
0
 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;
 }
Пример #10
0
 public AssignList(List<Expr> exprs, ExprType type)
     : base(type)
 {
     this.exprs = exprs;
 }
Пример #11
0
 public Attribute(Expr expr, String name, ExprType type)
     : base(type)
 {
     this.expr = expr;
     this.name = name;
 }
Пример #12
0
        /// <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();
            }
        }
Пример #13
0
 public static Boolean EqualType(ExprType t1, ExprType t2) {
     return t1.EqualType(t2);
 }
Пример #14
0
 public static Expr MakeCast(Expr expr, ExprType type) =>
     MakeCast(expr, type, expr.Env);
Пример #15
0
 public override Boolean EqualType(ExprType other) =>
     other.kind == Kind.POINTER && ((TPointer)other).ref_t.EqualType(ref_t);
Пример #16
0
 public Dereference(Expr expr, ExprType type)
     : base(type)
 {
     this.expr = expr;
 }
Пример #17
0
 public TIncompleteArray(ExprType elem_type, Boolean is_const = false, Boolean is_volatile = false)
     : base(is_const, is_volatile) {
     this.elem_type = elem_type;
 }
Пример #18
0
 protected Expr(ExprType type)
 {
     this.type = type;
 }
Пример #19
0
 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;
 }
Пример #20
0
 public Variable(ExprType type, String name, Env env)
     : base(type)
 {
     this.name = name;
     this.Env = env;
 }
Пример #21
0
 public override Boolean EqualType(ExprType other) =>
     other.kind == Kind.STRUCT_OR_UNION && ReferenceEquals(((TStructOrUnion)other)._layout, this._layout);
Пример #22
0
 public abstract Boolean EqualType(ExprType other);
Пример #23
0
        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(_ => _);
        }
Пример #24
0
 public override Boolean EqualType(ExprType other) => other.kind == Kind.VOID;
Пример #25
0
 // 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);
 }
Пример #26
0
 public override Boolean EqualType(ExprType other) => kind == other.kind;
Пример #27
0
 public Entry(EntryKind kind, ExprType type, Int32 offset)
 {
     this.kind = kind;
     this.type = type;
     this.offset = offset;
 }
Пример #28
0
 public TPointer(ExprType ref_t, Boolean is_const = false, Boolean is_volatile = false)
     : base(is_const, is_volatile) {
     this.ref_t = ref_t;
 }
Пример #29
0
 // 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;
 }
Пример #30
0
        /// <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.");
        }