public virtual void CGenPush(Env env, CGenState state)
        {
            Reg ret = CGenValue(env, state);

            switch (type.kind) {
                case ExprType.Kind.CHAR:
                case ExprType.Kind.UCHAR:
                case ExprType.Kind.SHORT:
                case ExprType.Kind.USHORT:
                case ExprType.Kind.LONG:
                case ExprType.Kind.ULONG:
                    // Integral
                    if (ret != Reg.EAX) {
                        throw new InvalidProgramException("Integral values should be returned to %eax");
                    }
                    state.CGenPushLong(Reg.EAX);
                    break;

                case ExprType.Kind.FLOAT:
                    // Float
                    if (ret != Reg.ST0) {
                        throw new InvalidProgramException("Floats should be returned to %st(0)");
                    }
                    state.CGenExpandStackBy4Bytes();
                    state.FSTS(0, Reg.ESP);
                    break;

                case ExprType.Kind.DOUBLE:
                    // Double
                    if (ret != Reg.ST0) {
                        throw new InvalidProgramException("Doubles should be returned to %st(0)");
                    }
                    state.CGenExpandStackBy8Bytes();
                    state.FSTL(0, Reg.ESP);
                    break;

                case ExprType.Kind.ARRAY:
                case ExprType.Kind.FUNCTION:
                case ExprType.Kind.POINTER:
                    // Pointer
                    if (ret != Reg.EAX) {
                        throw new InvalidProgramException("Pointer values should be returned to %eax");
                    }
                    state.CGenPushLong(Reg.EAX);
                    break;

                case ExprType.Kind.INCOMPLETE_ARRAY:
                case ExprType.Kind.VOID:
                    throw new InvalidProgramException(type.kind.ToString() + " can't be pushed onto the stack");

                case ExprType.Kind.STRUCT_OR_UNION:
                    throw new NotImplementedException();
            }
        }