The cdecl calling convention: 1. arguments are passed on the stack, right to left. 2. int values and pointer values are returned in %eax. 3. floats are returned in %st(0). 4. when calling a function, %st(0) ~ %st(7) are all free. 5. functions are free to use %eax, %ecx, %edx, because caller needs to save them. 6. stack must be aligned to 4 bytes (before gcc 4.5, for gcc 4.5+, aligned to 16 bytes).
Example #1
0
 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.");
     }
 }
Example #2
0
 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);
 }
Example #3
0
        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));
        }
Example #5
0
 public Reference(Expr expr) {
     this.Expr = expr;
     this.Type = new PointerType(expr.Type);
 }
Example #6
0
 public Attribute(Expr expr, String name, ExprType type) {
     this.Expr = expr;
     this.Name = name;
     this.Type = type;
 }
Example #7
0
 public FuncCall(Expr func, FunctionType funcType, List<Expr> args) {
     this.Func = func;
     this.FuncType = funcType;
     this.Args = args;
 }
Example #8
0
        /// <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.");
        }
Example #9
0
 public BitwiseNot(Expr expr)
     : base(expr) {
     if (!(expr.Type is LongType || expr.Type is ULongType)) {
         throw new InvalidOperationException("Invalid operand type.");
     }
 }
Example #10
0
 protected UnaryArithOp(Expr expr) {
     this.Expr = expr;
 }
Example #11
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 == 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.");
            }

        }
Example #12
0
 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.");
     }
 }
Example #13
0
 public ConditionalExpr(Expr cond, Expr trueExpr, Expr falseExpr, ExprType type) {
     this.Cond = cond;
     this.TrueExpr = trueExpr;
     this.FalseExpr = falseExpr;
     this.Type = type;
 }
Example #14
0
        /// <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();
            }
        }
Example #15
0
 /// <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);
 }
Example #16
0
        /// <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();
            }
        }
Example #17
0
        /// <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);

        }
Example #18
0
 public static Expr MakeCast(Expr expr, ExprType type) =>
     MakeCast(expr, type, expr.Env);
Example #19
0
 public Dereference(Expr expr, ExprType type) {
     this.Expr = expr;
     this.Type = type;
 }
Example #20
0
 public PreIncrement(Expr expr)
     : base(expr) { }
Example #21
0
        /// <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.");
        }
Example #22
0
 protected IncDecExpr(Expr expr) {
     if (!(expr.Type is ScalarType)) {
         throw new InvalidOperationException("Only supports scalars.");
     }
     this.Expr = expr;
 }
Example #23
0
 public WhileStmt(Expr cond, Stmt body) {
     if (!cond.Type.IsScalar) {
         throw new InvalidProgramException();
     }
     this.Cond = cond;
     this.Body = body;
 }
Example #24
0
 public PostDecrement(Expr expr)
     : base(expr) { }
Example #25
0
 public DoWhileStmt(Stmt body, Expr cond) {
     this.Body = body;
     this.Cond = cond;
 }
Example #26
0
 public PreDecrement(Expr expr)
     : base(expr) { }
Example #27
0
 public SwitchStmt(Expr expr, Stmt stmt) {
     this.Expr = expr;
     this.Stmt = stmt;
 }
Example #28
0
 public Negative(Expr expr)
     : base(expr) { }
Example #29
0
 public IfStmt(Expr cond, Stmt stmt) {
     this.Cond = cond;
     this.Stmt = stmt;
 }
Example #30
0
 public InitExpr(Expr expr) {
     this.expr = expr;
 }
Example #31
0
 public IfElseStmt(Expr cond, Stmt trueStmt, Stmt falseStmt) {
     this.Cond = cond;
     this.TrueStmt = trueStmt;
     this.FalseStmt = falseStmt;
 }