Add support for doubles to Ruamoko

Only as scalars, I still need to think about what to do for vectors and
quaternions due to param size issues. Also, doubles are not yet
guaranteed to be correctly aligned.
This commit is contained in:
Bill Currie 2020-02-14 16:38:37 +09:00
parent 13b608f40c
commit df7c08a010
22 changed files with 958 additions and 86 deletions

View file

@ -44,6 +44,7 @@ typedef enum {
ev_integer,
ev_uinteger,
ev_short, // value is embedded in the opcode
ev_double,
ev_invalid, // invalid type. used for instruction checking
ev_type_count // not a type, gives number of types
@ -305,6 +306,7 @@ typedef enum {
OP_PUSH_P,
OP_PUSH_Q,
OP_PUSH_I,
OP_PUSH_D,
OP_PUSHB_S,
OP_PUSHB_F,
@ -315,6 +317,7 @@ typedef enum {
OP_PUSHB_P,
OP_PUSHB_Q,
OP_PUSHB_I,
OP_PUSHB_D,
OP_PUSHBI_S,
OP_PUSHBI_F,
@ -325,6 +328,7 @@ typedef enum {
OP_PUSHBI_P,
OP_PUSHBI_Q,
OP_PUSHBI_I,
OP_PUSHBI_D,
OP_POP_S,
OP_POP_F,
@ -335,6 +339,7 @@ typedef enum {
OP_POP_P,
OP_POP_Q,
OP_POP_I,
OP_POP_D,
OP_POPB_S,
OP_POPB_F,
@ -345,6 +350,7 @@ typedef enum {
OP_POPB_P,
OP_POPB_Q,
OP_POPB_I,
OP_POPB_D,
OP_POPBI_S,
OP_POPBI_F,
@ -355,6 +361,36 @@ typedef enum {
OP_POPBI_P,
OP_POPBI_Q,
OP_POPBI_I,
OP_POPBI_D,
OP_ADD_D,
OP_SUB_D,
OP_MUL_D,
OP_MUL_QD,
OP_MUL_DQ,
OP_MUL_VD,
OP_MUL_DV,
OP_DIV_D,
OP_MOD_D,
OP_GE_D,
OP_LE_D,
OP_GT_D,
OP_LT_D,
OP_NOT_D,
OP_EQ_D,
OP_NE_D,
OP_CONV_FD,
OP_CONV_DF,
OP_CONV_ID,
OP_CONV_DI,
OP_STORE_D,
OP_STOREB_D,
OP_STOREBI_D,
OP_STOREP_D,
OP_LOAD_D,
OP_LOADB_D,
OP_LOADBI_D,
OP_ADDRESS_D,
} pr_opcode_e;
typedef struct opcode_s {
@ -423,7 +459,7 @@ typedef struct pr_va_list_s {
|(((0x##b) & 0xfff) << 12) \
|(((0x##c) & 0xfff) << 0) )
#define PROG_ID_VERSION 6
#define PROG_VERSION PROG_VERSION_ENCODE(0,fff,009)
#define PROG_VERSION PROG_VERSION_ENCODE(0,fff,00a)
typedef struct dprograms_s {
pr_uint_t version;

View file

@ -320,6 +320,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_
*/
#define G_FLOAT(p,o) G_var (p, o, float)
/** Access a double global. Can be assigned to.
\par QC type:
\c double
\param p pointer to ::progs_t VM struct
\param o offset into global data space
\return double lvalue
\hideinitializer
*/
#define G_DOUBLE(p,o) (*(double *) ((p)->pr_globals + o))
/** Access an integer global. Can be assigned to.
\par QC type:
@ -510,6 +522,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_
*/
#define P_FLOAT(p,n) P_var (p, n, float)
/** Access a double parameter. Can be assigned to.
\par QC type:
\c double
\param p pointer to ::progs_t VM struct
\param n parameter number (0-7)
\return double lvalue
\hideinitializer
*/
#define P_DOUBLE(p,n) (*(double *) ((p)->pr_params[n]))
/** Access an integer parameter. Can be assigned to.
\par QC type:
@ -702,6 +726,17 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_
*/
#define R_FLOAT(p) R_var (p, float)
/** Access the VM function return value as a \c double
\par QC type:
\c double
\param p pointer to ::progs_t VM struct
\return double lvalue
\hideinitializer
*/
#define R_DOUBLE(p) (*(double *) ((p)->pr_return))
/** Access the VM function return value as a \c ::pr_int_t (AKA int32_t)
\par QC type:
@ -868,6 +903,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_
*/
#define E_FLOAT(e,o) E_var (e, o, float)
/** Access a double entity field. Can be assigned to.
\par QC type:
\c double
\param e pointer to the entity
\param o field offset into entity data space
\return double lvalue
\hideinitializer
*/
#define E_DOUBLE(e,o) (*(double *) ((e)->v + o))
/** Access an integer entity field. Can be assigned to.
\par QC type:
@ -1560,6 +1607,7 @@ struct progs_s {
struct hashtab_s *strref_hash;
int num_strings;
strref_t *pr_xtstr;
int float_promoted; ///< for PR_Sprintf
//@}
/// \name memory map

View file

@ -280,12 +280,15 @@ PR_BoundsCheck (progs_t *pr, int addr, etype_t type)
#define OPB (*op_b)
#define OPC (*op_c)
#define OPA_double_var (*((double *) (op_a)))
#define OPB_double_var (*((double *) (op_b)))
#define OPC_double_var (*((double *) (op_c)))
/*
This gets around the problem of needing to test for -0.0 but denormals
causing exceptions (or wrong results for what we need) on the alpha.
*/
#define FNZ(x) ((x).uinteger_var && (x).uinteger_var != 0x80000000u)
#define FNZ(x) ((x).uinteger_var & ~0x80000000u)
static int
signal_hook (int sig, void *data)
@ -421,6 +424,9 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
PR_PrintStatement (pr, st, 1);
switch (st->op) {
case OP_ADD_D:
OPC_double_var = OPA_double_var + OPB_double_var;
break;
case OP_ADD_F:
OPC.float_var = OPA.float_var + OPB.float_var;
break;
@ -437,6 +443,9 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
PR_GetString (pr,
OPB.string_var));
break;
case OP_SUB_D:
OPC_double_var = OPA_double_var - OPB_double_var;
break;
case OP_SUB_F:
OPC.float_var = OPA.float_var - OPB.float_var;
break;
@ -446,12 +455,31 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
case OP_SUB_Q:
QuatSubtract (OPA.quat_var, OPB.quat_var, OPC.quat_var);
break;
case OP_MUL_D:
OPC_double_var = OPA_double_var * OPB_double_var;
break;
case OP_MUL_F:
OPC.float_var = OPA.float_var * OPB.float_var;
break;
case OP_MUL_V:
OPC.float_var = DotProduct (OPA.vector_var, OPB.vector_var);
break;
case OP_MUL_DV:
{
// avoid issues with the likes of x = x.x * x;
// makes for faster code, too
double scale = OPA_double_var;
VectorScale (OPB.vector_var, scale, OPC.vector_var);
}
break;
case OP_MUL_VD:
{
// avoid issues with the likes of x = x * x.x;
// makes for faster code, too
double scale = OPB_double_var;
VectorScale (OPA.vector_var, scale, OPC.vector_var);
}
break;
case OP_MUL_FV:
{
// avoid issues with the likes of x = x.x * x;
@ -474,6 +502,22 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
case OP_MUL_QV:
QuatMultVec (OPA.quat_var, OPB.vector_var, OPC.vector_var);
break;
case OP_MUL_DQ:
{
// avoid issues with the likes of x = x.s * x;
// makes for faster code, too
double scale = OPA_double_var;
QuatScale (OPB.quat_var, scale, OPC.quat_var);
}
break;
case OP_MUL_QD:
{
// avoid issues with the likes of x = x * x.s;
// makes for faster code, too
double scale = OPB_double_var;
QuatScale (OPA.quat_var, scale, OPC.quat_var);
}
break;
case OP_MUL_FQ:
{
// avoid issues with the likes of x = x.s * x;
@ -493,6 +537,9 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
case OP_CONJ_Q:
QuatConj (OPA.quat_var, OPC.quat_var);
break;
case OP_DIV_D:
OPC_double_var = OPA_double_var / OPB_double_var;
break;
case OP_DIV_F:
OPC.float_var = OPA.float_var / OPB.float_var;
break;
@ -630,6 +677,9 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
case OP_STORE_Q:
QuatCopy (OPA.quat_var, OPB.quat_var);
break;
case OP_STORE_D:
OPB_double_var = OPA_double_var;
break;
case OP_STOREP_F:
case OP_STOREP_ENT:
@ -661,6 +711,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
ptr = pr->pr_globals + pointer;
QuatCopy (OPA.quat_var, ptr->quat_var);
break;
case OP_STOREP_D:
pointer = OPB.integer_var;
if (pr_boundscheck->int_val) {
PR_BoundsCheck (pr, pointer, ev_double);
}
ptr = pr->pr_globals + pointer;
*(double *) ptr = OPA_double_var;
break;
case OP_ADDRESS:
if (pr_boundscheck->int_val) {
@ -687,6 +745,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
case OP_ADDRESS_FN:
case OP_ADDRESS_I:
case OP_ADDRESS_P:
case OP_ADDRESS_D:
OPC.integer_var = st->a;
break;
@ -735,6 +794,19 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
ed = PROG_TO_EDICT (pr, OPA.entity_var);
memcpy (&OPC, &ed->v[OPB.integer_var], 4 * sizeof (OPC));
break;
case OP_LOAD_D:
if (pr_boundscheck->int_val) {
if (OPA.entity_var < 0
|| OPA.entity_var >= pr->pr_edictareasize)
PR_RunError (pr, "Progs attempted to read an out of "
"bounds edict number");
if (OPB.uinteger_var + 1 >= pr->progs->entityfields)
PR_RunError (pr, "Progs attempted to read an invalid "
"field in an edict");
}
ed = PROG_TO_EDICT (pr, OPA.entity_var);
OPC_double_var = *(double *) (ed->v + OPB.integer_var);
break;
case OP_LOADB_F:
case OP_LOADB_S:
@ -766,6 +838,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
ptr = pr->pr_globals + pointer;
QuatCopy (ptr->quat_var, OPC.quat_var);
break;
case OP_LOADB_D:
pointer = OPA.integer_var + OPB.integer_var;
if (pr_boundscheck->int_val) {
PR_BoundsCheck (pr, pointer, ev_double);
}
ptr = pr->pr_globals + pointer;
OPC_double_var = *(double *) ptr;
break;
case OP_LOADBI_F:
case OP_LOADBI_S:
@ -797,6 +877,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
ptr = pr->pr_globals + pointer;
QuatCopy (ptr->quat_var, OPC.quat_var);
break;
case OP_LOADBI_D:
pointer = OPA.integer_var + (short) st->b;
if (pr_boundscheck->int_val) {
PR_BoundsCheck (pr, pointer, ev_quat);
}
ptr = pr->pr_globals + pointer;
OPC_double_var = *(double *) ptr;
break;
case OP_LEA:
pointer = OPA.integer_var + OPB.integer_var;
@ -838,6 +926,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
ptr = pr->pr_globals + pointer;
QuatCopy (OPA.quat_var, ptr->quat_var);
break;
case OP_STOREB_D:
pointer = OPB.integer_var + OPC.integer_var;
if (pr_boundscheck->int_val) {
PR_BoundsCheck (pr, pointer, ev_quat);
}
ptr = pr->pr_globals + pointer;
*(double *) ptr = OPA_double_var;
break;
case OP_STOREBI_F:
case OP_STOREBI_S:
@ -869,6 +965,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
ptr = pr->pr_globals + pointer;
QuatCopy (OPA.quat_var, ptr->quat_var);
break;
case OP_STOREBI_D:
pointer = OPB.integer_var + (short) st->c;
if (pr_boundscheck->int_val) {
PR_BoundsCheck (pr, pointer, ev_quat);
}
ptr = pr->pr_globals + pointer;
*(double *) ptr = OPA_double_var;
break;
case OP_PUSH_F:
case OP_PUSH_FLD:
@ -1322,20 +1426,19 @@ op_call:
case OP_MUL_I:
OPC.integer_var = OPA.integer_var * OPB.integer_var;
break;
/*
case OP_DIV_VF:
{
float temp = 1.0f / OPB.float_var;
VectorScale (OPA.vector_var, temp, OPC.vector_var);
}
break;
*/
case OP_DIV_I:
OPC.integer_var = OPA.integer_var / OPB.integer_var;
break;
case OP_MOD_I:
OPC.integer_var = OPA.integer_var % OPB.integer_var;
break;
case OP_MOD_D:
{
double a = OPA_double_var;
double b = OPB_double_var;
OPC_double_var = a - b * trunc (a / b);
}
break;
case OP_MOD_F:
{
float a = OPA.float_var;
@ -1432,6 +1535,41 @@ op_call:
st->b * 4);
break;
case OP_GE_D:
OPC.float_var = OPA_double_var >= OPB_double_var;
break;
case OP_LE_D:
OPC.float_var = OPA_double_var <= OPB_double_var;
break;
case OP_GT_D:
OPC.float_var = OPA_double_var > OPB_double_var;
break;
case OP_LT_D:
OPC.float_var = OPA_double_var < OPB_double_var;
break;
case OP_NOT_D:
OPC.integer_var = (op_a[0].integer_var
|| (op_a[1].integer_var & ~0x80000000u));
break;
case OP_EQ_D:
OPC.integer_var = OPA_double_var == OPB_double_var;
break;
case OP_NE_D:
OPC.integer_var = OPA_double_var != OPB_double_var;
break;
case OP_CONV_ID:
OPC_double_var = OPA.integer_var;
break;
case OP_CONV_DI:
OPC.integer_var = OPA_double_var;
break;
case OP_CONV_FD:
OPC_double_var = OPA.float_var;
break;
case OP_CONV_DF:
OPC.float_var = OPA_double_var;
break;
// LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized
/*
case OP_BOUNDCHECK:

View file

@ -61,6 +61,7 @@ VISIBLE int pr_type_size[ev_type_count] = {
1, // ev_integer
1, // ev_uinteger
0, // ev_short value in opcode
2, // ev_double
};
VISIBLE const char *pr_type_name[ev_type_count] = {
@ -102,6 +103,10 @@ VISIBLE opcode_t pr_opcodes[] = {
"%Va",
},
{"*", "mul.d", OP_MUL_D, false,
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"*", "mul.f", OP_MUL_F, false,
ev_float, ev_float, ev_float,
PROG_ID_VERSION,
@ -118,6 +123,14 @@ VISIBLE opcode_t pr_opcodes[] = {
ev_vector, ev_float, ev_vector,
PROG_ID_VERSION,
},
{"*", "mul.dv", OP_MUL_DV, false,
ev_double, ev_vector, ev_vector,
PROG_ID_VERSION,
},
{"*", "mul.vd", OP_MUL_VD, false,
ev_vector, ev_double, ev_vector,
PROG_ID_VERSION,
},
{"*", "mul.q", OP_MUL_Q, false,
ev_quat, ev_quat, ev_quat,
PROG_VERSION,
@ -130,6 +143,14 @@ VISIBLE opcode_t pr_opcodes[] = {
ev_quat, ev_float, ev_quat,
PROG_VERSION,
},
{"*", "mul.dq", OP_MUL_DQ, false,
ev_double, ev_quat, ev_quat,
PROG_VERSION,
},
{"*", "mul.qd", OP_MUL_QD, false,
ev_quat, ev_double, ev_quat,
PROG_VERSION,
},
{"*", "mul.qv", OP_MUL_QV, false,
ev_quat, ev_vector, ev_vector,
PROG_VERSION,
@ -145,7 +166,19 @@ VISIBLE opcode_t pr_opcodes[] = {
ev_float, ev_float, ev_float,
PROG_ID_VERSION,
},
{"/", "div.d", OP_DIV_D, false,
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"%", "mod.d", OP_MOD_D, false,
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"+", "add.d", OP_ADD_D, false,
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"+", "add.f", OP_ADD_F, false,
ev_float, ev_float, ev_float,
PROG_ID_VERSION,
@ -163,6 +196,10 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_VERSION,
},
{"-", "sub.d", OP_SUB_D, false,
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"-", "sub.f", OP_SUB_F, false,
ev_float, ev_float, ev_float,
PROG_ID_VERSION,
@ -176,6 +213,10 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_VERSION,
},
{"==", "eq.d", OP_EQ_D, false,
ev_double, ev_double, ev_integer,
PROG_VERSION,
},
{"==", "eq.f", OP_EQ_F, false,
ev_float, ev_float, ev_integer,
PROG_ID_VERSION,
@ -201,6 +242,10 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_ID_VERSION,
},
{"!=", "ne.d", OP_NE_D, false,
ev_double, ev_double, ev_integer,
PROG_VERSION,
},
{"!=", "ne.f", OP_NE_F, false,
ev_float, ev_float, ev_integer,
PROG_ID_VERSION,
@ -226,10 +271,18 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_ID_VERSION,
},
{"<=", "le.d", OP_LE_D, false,
ev_double, ev_double, ev_integer,
PROG_VERSION,
},
{"<=", "le.f", OP_LE_F, false,
ev_float, ev_float, ev_integer,
PROG_ID_VERSION,
},
{">=", "ge.d", OP_GE_D, false,
ev_double, ev_double, ev_integer,
PROG_VERSION,
},
{">=", "ge.f", OP_GE_F, false,
ev_float, ev_float, ev_integer,
PROG_ID_VERSION,
@ -242,10 +295,18 @@ VISIBLE opcode_t pr_opcodes[] = {
ev_string, ev_string, ev_integer,
PROG_VERSION,
},
{"<", "lt.d", OP_LT_D, false,
ev_double, ev_double, ev_integer,
PROG_VERSION,
},
{"<", "lt.f", OP_LT_F, false,
ev_float, ev_float, ev_integer,
PROG_ID_VERSION,
},
{">", "gt.d", OP_GT_D, false,
ev_double, ev_double, ev_integer,
PROG_VERSION,
},
{">", "gt.f", OP_GT_F, false,
ev_float, ev_float, ev_integer,
PROG_ID_VERSION,
@ -264,6 +325,11 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_ID_VERSION,
"%Ga.%Gb(%Ec), %gc",//FIXME %E more flexible?
},
{".", "load.d", OP_LOAD_D, false,
ev_entity, ev_field, ev_double,
PROG_VERSION,
"%Ga.%Gb(%Ec), %gc",
},
{".", "load.v", OP_LOAD_V, false,
ev_entity, ev_field, ev_vector,
PROG_ID_VERSION,
@ -305,6 +371,11 @@ VISIBLE opcode_t pr_opcodes[] = {
"%Ga.%Gb(%Ec), %gc",
},
{".", "loadb.d", OP_LOADB_D, false,
ev_pointer, ev_integer, ev_double,
PROG_VERSION,
"*(%Ga + %Gb), %gc",
},
{".", "loadb.f", OP_LOADB_F, false,
ev_pointer, ev_integer, ev_float,
PROG_VERSION,
@ -351,6 +422,11 @@ VISIBLE opcode_t pr_opcodes[] = {
"*(%Ga + %Gb), %gc",
},
{".", "loadbi.d", OP_LOADBI_D, false,
ev_pointer, ev_short, ev_double,
PROG_VERSION,
"*(%Ga + %sb), %gc",
},
{".", "loadbi.f", OP_LOADBI_F, false,
ev_pointer, ev_short, ev_float,
PROG_VERSION,
@ -408,6 +484,11 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_VERSION,
"%Ga, %gc",
},
{"&", "address.d", OP_ADDRESS_D, false,
ev_double, ev_invalid, ev_pointer,
PROG_VERSION,
"%Ga, %gc",
},
{"&", "address.f", OP_ADDRESS_F, false,
ev_float, ev_invalid, ev_pointer,
PROG_VERSION,
@ -475,7 +556,32 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_VERSION,
"%Ga, %gc",
},
{"<CONV>", "conv.id", OP_CONV_ID, false,
ev_integer, ev_invalid, ev_double,
PROG_VERSION,
"%Ga, %gc",
},
{"<CONV>", "conv.di", OP_CONV_DI, false,
ev_double, ev_invalid, ev_integer,
PROG_VERSION,
"%Ga, %gc",
},
{"<CONV>", "conv.fd", OP_CONV_FD, false,
ev_float, ev_invalid, ev_double,
PROG_VERSION,
"%Ga, %gc",
},
{"<CONV>", "conv.df", OP_CONV_DF, false,
ev_double, ev_invalid, ev_float,
PROG_VERSION,
"%Ga, %gc",
},
{"=", "store.d", OP_STORE_D, true,
ev_double, ev_double, ev_invalid,
PROG_VERSION,
"%Ga, %gb",
},
{"=", "store.f", OP_STORE_F, true,
ev_float, ev_float, ev_invalid,
PROG_ID_VERSION,
@ -522,6 +628,11 @@ VISIBLE opcode_t pr_opcodes[] = {
"%Ga, %gb",
},
{".=", "storep.d", OP_STOREP_D, true,
ev_double, ev_pointer, ev_invalid,
PROG_ID_VERSION,
"%Ga, *%Gb",
},
{".=", "storep.f", OP_STOREP_F, true,
ev_float, ev_pointer, ev_invalid,
PROG_ID_VERSION,
@ -568,6 +679,11 @@ VISIBLE opcode_t pr_opcodes[] = {
"%Ga, *%Gb",
},
{".=", "storeb.d", OP_STOREB_D, true,
ev_double, ev_pointer, ev_integer,
PROG_VERSION,
"%Ga, *(%Gb + %Gc)",
},
{".=", "storeb.f", OP_STOREB_F, true,
ev_float, ev_pointer, ev_integer,
PROG_VERSION,
@ -614,6 +730,11 @@ VISIBLE opcode_t pr_opcodes[] = {
"%Ga, *(%Gb + %Gc)",
},
{".=", "storebi.d", OP_STOREBI_D, true,
ev_double, ev_pointer, ev_short,
PROG_VERSION,
"%Ga, *(%Gb + %sc)",
},
{".=", "storebi.f", OP_STOREBI_F, true,
ev_float, ev_pointer, ev_short,
PROG_VERSION,
@ -672,6 +793,11 @@ VISIBLE opcode_t pr_opcodes[] = {
"",
},
{"!", "not.d", OP_NOT_D, false,
ev_double, ev_invalid, ev_integer,
PROG_VERSION,
"%Ga, %gc",
},
{"!", "not.f", OP_NOT_F, false,
ev_float, ev_invalid, ev_integer,
PROG_ID_VERSION,

View file

@ -70,6 +70,7 @@ struct strref_s {
#define FMT_ADDSIGN (1<<3)
#define FMT_ADDBLANK (1<<4)
#define FMT_HEX (1<<5)
#define FMT_LONG (1<<6)
typedef struct fmt_item_s {
byte type;
@ -81,6 +82,7 @@ typedef struct fmt_item_s {
int integer_var;
unsigned uinteger_var;
float float_var;
double double_var;
} data;
struct fmt_item_s *next;
} fmt_item_t;
@ -596,11 +598,19 @@ I_DoPrint (dstring_t *result, fmt_item_t *formatting)
break;
case 'f':
dstring_appendstr (tmp, "f");
PRINT (float);
if (current->flags & FMT_LONG) {
PRINT (double);
} else {
PRINT (float);
}
break;
case 'g':
dstring_appendstr (tmp, "g");
PRINT (float);
if (current->flags & FMT_LONG) {
PRINT (double);
} else {
PRINT (float);
}
break;
default:
break;
@ -650,7 +660,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name,
int fmt_count = 0;
if (!name)
name = "PF_InternalSprintf";
name = "PR_Sprintf";
*fi = new_fmt_item ();
c = l = format;
@ -742,12 +752,19 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name,
fi = &(*fi)->next;
break;
case 'f':
// float
// float or double
case 'g':
// float, no trailing zeroes, trim "." if nothing
// after
// float or double, no trailing zeroes, trim "."
// if nothing after
(*fi)->type = *c;
(*fi)->data.float_var = P_FLOAT (pr, fmt_count);
if (pr->float_promoted) {
(*fi)->flags |= FMT_LONG;
(*fi)->data.double_var
= P_DOUBLE (pr, fmt_count);
} else {
(*fi)->data.float_var
= P_FLOAT (pr, fmt_count);
}
fmt_count++;
(*fi)->next = new_fmt_item ();

View file

@ -42,55 +42,55 @@
#include "rua_internal.h"
static void
bi_sin (progs_t *pr)
bi_sinf (progs_t *pr)
{
R_FLOAT (pr) = sinf (P_FLOAT (pr, 0));
}
static void
bi_cos (progs_t *pr)
bi_cosf (progs_t *pr)
{
R_FLOAT (pr) = cosf (P_FLOAT (pr, 0));
}
static void
bi_tan (progs_t *pr)
bi_tanf (progs_t *pr)
{
R_FLOAT (pr) = tanf (P_FLOAT (pr, 0));
}
static void
bi_asin (progs_t *pr)
bi_asinf (progs_t *pr)
{
R_FLOAT (pr) = asinf (P_FLOAT (pr, 0));
}
static void
bi_acos (progs_t *pr)
bi_acosf (progs_t *pr)
{
R_FLOAT (pr) = acosf (P_FLOAT (pr, 0));
}
static void
bi_atan (progs_t *pr)
bi_atanf (progs_t *pr)
{
R_FLOAT (pr) = atanf (P_FLOAT (pr, 0));
}
static void
bi_atan2 (progs_t *pr)
bi_atan2f (progs_t *pr)
{
R_FLOAT (pr) = atan2f (P_FLOAT (pr, 0), P_FLOAT (pr, 1));
}
static void
bi_log (progs_t *pr)
bi_logf (progs_t *pr)
{
R_FLOAT (pr) = logf (P_FLOAT (pr, 0));
}
static void
bi_log2 (progs_t *pr)
bi_log2f (progs_t *pr)
{
#ifdef HAVE_LOG2F
R_FLOAT (pr) = log2f (P_FLOAT (pr, 0));
@ -100,95 +100,238 @@ bi_log2 (progs_t *pr)
}
static void
bi_log10 (progs_t *pr)
bi_log10f (progs_t *pr)
{
R_FLOAT (pr) = log10f (P_FLOAT (pr, 0));
}
static void
bi_pow (progs_t *pr)
bi_powf (progs_t *pr)
{
R_FLOAT (pr) = powf (P_FLOAT (pr, 0), P_FLOAT (pr, 1));
}
static void
bi_sqrt (progs_t *pr)
bi_sqrtf (progs_t *pr)
{
R_FLOAT (pr) = sqrtf (P_FLOAT (pr, 0));
}
static void
bi_cbrt (progs_t *pr)
bi_cbrtf (progs_t *pr)
{
R_FLOAT (pr) = cbrtf (P_FLOAT (pr, 0));
}
static void
bi_hypot (progs_t *pr)
bi_hypotf (progs_t *pr)
{
R_FLOAT (pr) = hypotf (P_FLOAT (pr, 0), P_FLOAT (pr, 1));
}
static void
bi_sinh (progs_t *pr)
bi_sinhf (progs_t *pr)
{
R_FLOAT (pr) = sinhf (P_FLOAT (pr, 0));
}
static void
bi_cosh (progs_t *pr)
bi_coshf (progs_t *pr)
{
R_FLOAT (pr) = coshf (P_FLOAT (pr, 0));
}
static void
bi_tanh (progs_t *pr)
bi_tanhf (progs_t *pr)
{
R_FLOAT (pr) = tanhf (P_FLOAT (pr, 0));
}
static void
bi_asinh (progs_t *pr)
bi_asinhf (progs_t *pr)
{
double y = P_FLOAT (pr, 0);
R_FLOAT (pr) = logf (y + sqrtf (y * y + 1));
}
static void
bi_acosh (progs_t *pr)
bi_acoshf (progs_t *pr)
{
double y = P_FLOAT (pr, 0);
R_FLOAT (pr) = logf (y + sqrtf (y * y - 1));
}
static void
bi_atanh (progs_t *pr)
bi_atanhf (progs_t *pr)
{
double y = P_FLOAT (pr, 0);
R_FLOAT (pr) = logf ((1 + y) / (1 - y)) / 2;
}
static void
bi_sin (progs_t *pr)
{
R_DOUBLE (pr) = sin (P_DOUBLE (pr, 0));
}
static void
bi_cos (progs_t *pr)
{
R_DOUBLE (pr) = cos (P_DOUBLE (pr, 0));
}
static void
bi_tan (progs_t *pr)
{
R_DOUBLE (pr) = tan (P_DOUBLE (pr, 0));
}
static void
bi_asin (progs_t *pr)
{
R_DOUBLE (pr) = asin (P_DOUBLE (pr, 0));
}
static void
bi_acos (progs_t *pr)
{
R_DOUBLE (pr) = acos (P_DOUBLE (pr, 0));
}
static void
bi_atan (progs_t *pr)
{
R_DOUBLE (pr) = atan (P_DOUBLE (pr, 0));
}
static void
bi_atan2 (progs_t *pr)
{
R_DOUBLE (pr) = atan2 (P_DOUBLE (pr, 0), P_DOUBLE (pr, 1));
}
static void
bi_log (progs_t *pr)
{
R_DOUBLE (pr) = log (P_DOUBLE (pr, 0));
}
static void
bi_log2 (progs_t *pr)
{
R_DOUBLE (pr) = log (P_DOUBLE (pr, 0)) / M_LOG2E;
}
static void
bi_log10 (progs_t *pr)
{
R_DOUBLE (pr) = log10 (P_DOUBLE (pr, 0));
}
static void
bi_pow (progs_t *pr)
{
R_DOUBLE (pr) = pow (P_DOUBLE (pr, 0), P_DOUBLE (pr, 1));
}
static void
bi_sqrt (progs_t *pr)
{
R_DOUBLE (pr) = sqrt (P_DOUBLE (pr, 0));
}
static void
bi_cbrt (progs_t *pr)
{
R_DOUBLE (pr) = cbrt (P_DOUBLE (pr, 0));
}
static void
bi_hypot (progs_t *pr)
{
R_DOUBLE (pr) = hypot (P_DOUBLE (pr, 0), P_DOUBLE (pr, 1));
}
static void
bi_sinh (progs_t *pr)
{
R_DOUBLE (pr) = sinh (P_DOUBLE (pr, 0));
}
static void
bi_cosh (progs_t *pr)
{
R_DOUBLE (pr) = cosh (P_DOUBLE (pr, 0));
}
static void
bi_tanh (progs_t *pr)
{
R_DOUBLE (pr) = tanh (P_DOUBLE (pr, 0));
}
static void
bi_asinh (progs_t *pr)
{
double y = P_DOUBLE (pr, 0);
R_DOUBLE (pr) = log (y + sqrt (y * y + 1));
}
static void
bi_acosh (progs_t *pr)
{
double y = P_DOUBLE (pr, 0);
R_DOUBLE (pr) = log (y + sqrt (y * y - 1));
}
static void
bi_atanh (progs_t *pr)
{
double y = P_DOUBLE (pr, 0);
R_DOUBLE (pr) = log ((1 + y) / (1 - y)) / 2;
}
static builtin_t builtins[] = {
{"sin", bi_sin, -1},
{"cos", bi_cos, -1},
{"tan", bi_tan, -1},
{"asin", bi_asin, -1},
{"acos", bi_acos, -1},
{"atan", bi_atan, -1},
{"atan2", bi_atan2, -1},
{"log", bi_log, -1},
{"log2", bi_log2, -1},
{"log10", bi_log10, -1},
{"pow", bi_pow, -1},
{"sqrt", bi_sqrt, -1},
{"cbrt", bi_cbrt, -1},
{"hypot", bi_hypot, -1},
{"sinh", bi_sinh, -1},
{"cosh", bi_cosh, -1},
{"tanh", bi_tanh, -1},
{"asinh", bi_asinh, -1},
{"acosh", bi_acosh, -1},
{"atanh", bi_atanh, -1},
{"sin|f", bi_sinf, -1},
{"cos|f", bi_cosf, -1},
{"tan|f", bi_tanf, -1},
{"asin|f", bi_asinf, -1},
{"acos|f", bi_acosf, -1},
{"atan|f", bi_atanf, -1},
{"atan2|f", bi_atan2f, -1},
{"log|f", bi_logf, -1},
{"log2|f", bi_log2f, -1},
{"log10|f", bi_log10f, -1},
{"pow|f", bi_powf, -1},
{"sqrt|f", bi_sqrtf, -1},
{"cbrt|f", bi_cbrtf, -1},
{"hypot|f", bi_hypotf, -1},
{"sinh|f", bi_sinhf, -1},
{"cosh|f", bi_coshf, -1},
{"tanh|f", bi_tanhf, -1},
{"asinh|f", bi_asinhf, -1},
{"acosh|f", bi_acoshf, -1},
{"atanh|f", bi_atanhf, -1},
{"sin|d", bi_sin, -1},
{"cos|d", bi_cos, -1},
{"tan|d", bi_tan, -1},
{"asin|d", bi_asin, -1},
{"acos|d", bi_acos, -1},
{"atan|d", bi_atan, -1},
{"atan2|d", bi_atan2, -1},
{"log|d", bi_log, -1},
{"log2|d", bi_log2, -1},
{"log10|d", bi_log10, -1},
{"pow|d", bi_pow, -1},
{"sqrt|d", bi_sqrt, -1},
{"cbrt|d", bi_cbrt, -1},
{"hypot|d", bi_hypot, -1},
{"sinh|d", bi_sinh, -1},
{"cosh|d", bi_cosh, -1},
{"tanh|d", bi_tanh, -1},
{"asinh|d", bi_asinh, -1},
{"acosh|d", bi_acosh, -1},
{"atanh|d", bi_atanh, -1},
{0}
};

View file

@ -210,6 +210,11 @@ extern progs_t sv_pr_state;
#define SVentity(e,f) SVFIELD (e, f, entity)
#define SVvector(e,f) SVFIELD (e, f, vector)
#define SVinteger(e,f) SVFIELD (e, f, integer)
#if TYPECHECK_PROGS
#define SVdouble(e,f) E_DOUBLE (e, PR_AccessField (&sv_pr_state, #f, ev_##t, __FILE__, __LINE__))
#else
#define SVdouble(e,f) E_DOUBLE (e, sv_fields.f)
#endif
typedef struct edict_leaf_s {
struct edict_leaf_s *next;

View file

@ -361,6 +361,9 @@ set_address (sv_def_t *def, void *address)
case ev_quat:
*(float **)def->field = (float *) address;
break;
case ev_double:
*(double **)def->field = (double *) address;
break;
case ev_string:
case ev_entity:
case ev_field:

View file

@ -195,6 +195,11 @@ extern progs_t sv_pr_state;
#define SVentity(e,f) SVFIELD (e, f, entity)
#define SVvector(e,f) SVFIELD (e, f, vector)
#define SVinteger(e,f) SVFIELD (e, f, integer)
#if TYPECHECK_PROGS
#define SVdouble(e,f) E_DOUBLE (e, PR_AccessField (&sv_pr_state, #f, ev_##t, __FILE__, __LINE__))
#else
#define SVdouble(e,f) E_DOUBLE (e, sv_fields.f)
#endif
typedef struct edict_leaf_s {
struct edict_leaf_s *next;

View file

@ -371,6 +371,9 @@ set_address (sv_def_t *def, void *address)
case ev_quat:
*(float **)def->field = (float *) address;
break;
case ev_double:
*(double **)def->field = (double *) address;
break;
case ev_string:
case ev_entity:
case ev_field:

View file

@ -60,17 +60,20 @@
/**
Returns \a f, rounded down to the next lower integer
*/
@extern float floor (float f);
@extern @overload float floor (float f);
@extern @overload double floor (double f);
/**
Returns \a f, rounded up to the next highest integer
*/
@extern float ceil (float f);
@extern @overload float ceil (float f);
@extern @overload double ceil (double f);
/**
Returns the absolute value of \a f
*/
@extern float fabs (float f);
@extern @overload float fabs (float f);
@extern @overload double fabs (double f);
//\}
///\name Exponentials and Logarithms
@ -78,32 +81,38 @@
/**
Returns the natural log of \a x.
*/
@extern float log (float x);
@extern @overload float log (float x);
@extern @overload double log (double x);
/**
Returns the base-2 log of \a x.
*/
@extern float log2 (float x);
@extern @overload float log2 (float x);
@extern @overload double log2 (double x);
/**
Returns the base-10 log of \a x.
*/
@extern float log10 (float x);
@extern @overload float log10 (float x);
@extern @overload double log10 (double x);
/**
Returns \a x to the \a y power
*/
@extern float pow (float x, float y);
@extern @overload float pow (float x, float y);
@extern @overload double pow (double x, double y);
/**
Returns the square root of \a x
*/
@extern float sqrt (float x);
@extern @overload float sqrt (float x);
@extern @overload double sqrt (double x);
/**
Returns the cube root of \a x
*/
@extern float cbrt (float x);
@extern @overload float cbrt (float x);
@extern @overload double cbrt (double x);
//\}
///\name Trigonometric functions
@ -112,40 +121,52 @@
/**
Returns the sine of \a x.
*/
@extern float sin (float x);
@extern @overload float sin (float x);
@extern @overload double sin (double x);
/**
Returns the cosine of \a x.
*/
@extern float cos (float x);
@extern @overload float cos (float x);
@extern @overload double cos (double x);
/**
Returns the tangent of \a x.
*/
@extern float tan (float x);
@extern @overload float tan (float x);
@extern @overload double tan (double x);
/**
Returns the arcsine of \a x.
*/
@extern float asin (float x);
@extern @overload float asin (float x);
@extern @overload double asin (double x);
/**
Returns the arccosine of \a x.
*/
@extern float acos (float x);
@extern @overload float acos (float x);
@extern @overload double acos (double x);
/**
Returns the arctangent of \a x.
*/
@extern float atan (float x);
@extern float atan2 (float y, float x);
@extern @overload float atan (float x);
@extern @overload double atan (double x);
/**
Returns the arctangent of \a y / \a x preserving the quadrant.
*/
@extern @overload float atan2 (float y, float x);
@extern @overload double atan2 (double y, double x);
/**
Returns the length of the hypotenuse of a right triangle with sides \a x
and \a y. That is, this function returns
<code>sqrt (\a x*\a x + \a y*\a y)</code>.
*/
@extern float hypot (float x, float y);
@extern @overload float hypot (float x, float y);
@extern @overload double hypot (double x, double y);
//\}
///\name Hyperbolic functions
@ -153,32 +174,38 @@
/**
Returns the hyperbolic sine of \a x
*/
@extern float sinh (float x);
@extern @overload float sinh (float x);
@extern @overload double sinh (double x);
/**
Returns the hyperbolic cosine of \a x
*/
@extern float cosh (float x);
@extern @overload float cosh (float x);
@extern @overload double cosh (double x);
/**
Returns the hyperbolic tangent of \a x
*/
@extern float tanh (float x);
@extern @overload float tanh (float x);
@extern @overload double tanh (double x);
/**
Returns the area hyperbolic sine of \a x
*/
@extern float asinh (float x);
@extern @overload float asinh (float x);
@extern @overload double asinh (double x);
/**
Returns the area hyperbolic cosine of \a x
*/
@extern float acosh (float x);
@extern @overload float acosh (float x);
@extern @overload double acosh (double x);
/**
Returns the area hyperbolic tangent of \a x
*/
@extern float atanh (float x);
@extern @overload float atanh (float x);
@extern @overload double atanh (double x);
//\}
///\name Vector Functions

View file

@ -34,3 +34,27 @@ float (float x) atanh = #0;
float (float x) sqrt = #0;
float (float x) cbrt = #0;
float (float x, float y) hypot = #0;
double (double v) floor = #0;
double (double v) ceil = #0;
double (double f) fabs = #0;
double (double x) sin = #0;
double (double x) cos = #0;
double (double x) tan = #0;
double (double x) asin = #0;
double (double x) acos = #0;
double (double x) atan = #0;
double (double y, double x) atan2 = #0;
double (double x) log = #0;
double (double x) log2 = #0;
double (double x) log10 = #0;
double (double x, double y) pow = #0;
double (double x) sinh = #0;
double (double x) cosh = #0;
double (double x) tanh = #0;
double (double x) asinh = #0;
double (double x) acosh = #0;
double (double x) atanh = #0;
double (double x) sqrt = #0;
double (double x) cbrt = #0;
double (double x, double y) hypot = #0;

View file

@ -174,6 +174,7 @@ typedef struct ex_value_s {
etype_t lltype;
union {
const char *string_val; ///< string constant
float double_val; ///< double constant
float float_val; ///< float constant
float vector_val[3]; ///< vector constant
int entity_val; ///< entity constant
@ -397,6 +398,15 @@ expr_t *new_name_expr (const char *name);
expr_t *new_string_expr (const char *string_val);
const char *expr_string (expr_t *e) __attribute__((pure));
/** Create a new double constant expression node.
\param double_val The double constant being represented.
\return The new double constant expression node
(expr_t::e::double_val).
*/
expr_t *new_double_expr (double double_val);
double expr_double (expr_t *e) __attribute__((pure));
/** Create a new float constant expression node.
\param float_val The float constant being represented.

View file

@ -98,6 +98,7 @@ typedef struct {
extern type_t type_invalid;
extern type_t type_void;
extern type_t type_string;
extern type_t type_double;
extern type_t type_float;
extern type_t type_vector;
extern type_t type_entity;
@ -153,6 +154,7 @@ const char *type_get_encoding (const type_t *type);
int is_void (const type_t *type) __attribute__((pure));
int is_enum (const type_t *type) __attribute__((pure));
int is_integral (const type_t *type) __attribute__((pure));
int is_double (const type_t *type) __attribute__((pure));
int is_float (const type_t *type) __attribute__((pure));
int is_scalar (const type_t *type) __attribute__((pure));
int is_vector (const type_t *type) __attribute__((pure));

View file

@ -40,6 +40,7 @@ struct ex_value_s;
struct type_s;
struct ex_value_s *new_string_val (const char *string_val);
struct ex_value_s *new_double_val (double double_val);
struct ex_value_s *new_float_val (float float_val);
struct ex_value_s *new_vector_val (const float *vector_val);
struct ex_value_s *new_entity_val (int entity_val);

View file

@ -48,6 +48,7 @@
#include "qfcc.h"
#include "strpool.h"
#include "type.h"
#include "value.h"
#include "qc-parse.h"
typedef expr_t *(*operation_t) (int op, expr_t *e, expr_t *e1, expr_t *e2);
@ -163,6 +164,40 @@ convert_to_float (expr_t *e)
}
}
static expr_t *
convert_to_double (expr_t *e)
{
if (get_type (e) == &type_double)
return e;
switch (e->type) {
case ex_value:
switch (e->e.value->lltype) {
case ev_integer:
e->e.value = new_double_val (expr_integer (e));
return e;
case ev_short:
e->e.value = new_double_val (expr_short (e));
return e;
case ev_float:
e->e.value = new_double_val (expr_float (e));
return e;
default:
internal_error (e, 0);
}
break;
case ex_symbol:
case ex_expr:
case ex_uexpr:
case ex_temp:
case ex_block:
e = cf_cast_expr (&type_float, e);
return e;
default:
internal_error (e, 0);
}
}
static expr_t *
do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
@ -292,6 +327,111 @@ do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2)
return e;
}
static expr_t *
do_op_double (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
double d1, d2;
expr_t *conv;
type_t *type = &type_double;
static int valid[] = {
'=', '+', '-', '*', '/', '%',
LT, GT, LE, GE, EQ, NE, 0
};
if (!valid_op (op, valid))
return error (e1, "invalid operator for double");
if (op == '=' || op == PAS) {
if ((type = get_type (e1)) != &type_double) {
//FIXME optimize casting a constant
e->e.expr.e2 = e2 = cf_cast_expr (type, e2);
} else if ((conv = convert_to_double (e2)) != e2) {
e->e.expr.e2 = e2 = conv;
}
} else {
if ((conv = convert_to_double (e1)) != e1) {
e->e.expr.e1 = e1 = conv;
}
if ((conv = convert_to_double (e2)) != e2) {
e->e.expr.e2 = e2 = conv;
}
}
if (is_compare (op) || is_logic (op)) {
type = &type_integer;
}
e->e.expr.type = type;
if (op == '*' && is_constant (e1) && expr_double (e1) == 1)
return e2;
if (op == '*' && is_constant (e2) && expr_double (e2) == 1)
return e1;
if (op == '*' && is_constant (e1) && expr_double (e1) == 0)
return e1;
if (op == '*' && is_constant (e2) && expr_double (e2) == 0)
return e2;
if (op == '/' && is_constant (e2) && expr_double (e2) == 1)
return e1;
if (op == '/' && is_constant (e2) && expr_double (e2) == 0)
return error (e, "division by zero");
if (op == '/' && is_constant (e1) && expr_double (e1) == 0)
return e1;
if (op == '+' && is_constant (e1) && expr_double (e1) == 0)
return e2;
if (op == '+' && is_constant (e2) && expr_double (e2) == 0)
return e1;
if (op == '-' && is_constant (e2) && expr_double (e2) == 0)
return e1;
if (op == '=' || !is_constant (e1) || !is_constant (e2))
return e;
d1 = expr_double (e1);
d2 = expr_double (e2);
switch (op) {
case '+':
e = new_double_expr (d1 + d2);
break;
case '-':
e = new_double_expr (d1 - d2);
break;
case '*':
e = new_double_expr (d1 * d2);
break;
case '/':
if (!d2)
return error (e1, "divide by zero");
e = new_double_expr (d1 / d2);
break;
case '%':
e = new_double_expr ((int)d1 % (int)d2);
break;
case LT:
e = new_integer_expr (d1 < d2);
break;
case GT:
e = new_integer_expr (d1 > d2);
break;
case LE:
e = new_integer_expr (d1 <= d2);
break;
case GE:
e = new_integer_expr (d1 >= d2);
break;
case EQ:
e = new_integer_expr (d1 == d2);
break;
case NE:
e = new_integer_expr (d1 != d2);
break;
default:
internal_error (e1, 0);
}
e->file = e1->file;
e->line = e1->line;
return e;
}
static expr_t *
do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
@ -884,11 +1024,15 @@ do_op_compound (int op, expr_t *e, expr_t *e1, expr_t *e2)
return do_op_struct (op, e, e1, e2);
if (is_scalar (t1) && is_scalar (t2)) {
if (is_enum (t1)) {
if (t2->type == ev_float)
if (t2->type == ev_double)
return do_op_float (op, e, e1, e2);
if (t2->type == ev_double)
return do_op_float (op, e, e1, e2);
return do_op_integer (op, e, e1, e2);
}
if (is_enum (t2)) {
if (t1->type == ev_double)
return do_op_double (op, e, e1, e2);
if (t1->type == ev_float)
return do_op_float (op, e, e1, e2);
return do_op_integer (op, e, e1, e2);
@ -947,6 +1091,7 @@ static operation_t op_void[ev_type_count] = {
do_op_invalid, // ev_integer
do_op_invalid, // ev_uinteger
do_op_invalid, // ev_short
do_op_invalid, // ev_double
do_op_invalid, // ev_invalid
};
@ -963,6 +1108,7 @@ static operation_t op_string[ev_type_count] = {
do_op_invalid, // ev_integer
do_op_invalid, // ev_uinteger
do_op_invalid, // ev_short
do_op_invalid, // ev_double
do_op_invalid, // ev_invalid
};
@ -979,6 +1125,7 @@ static operation_t op_float[ev_type_count] = {
do_op_float, // ev_integer
do_op_float, // ev_uinteger
do_op_float, // ev_short
do_op_double, // ev_double
do_op_invalid, // ev_invalid
};
@ -995,6 +1142,7 @@ static operation_t op_vector[ev_type_count] = {
do_op_vector, // ev_integer
do_op_vector, // ev_uinteger
do_op_vector, // ev_short
do_op_vector, // ev_double
do_op_invalid, // ev_invalid
};
@ -1011,6 +1159,7 @@ static operation_t op_entity[ev_type_count] = {
do_op_invalid, // ev_integer
do_op_invalid, // ev_uinteger
do_op_invalid, // ev_short
do_op_invalid, // ev_double
do_op_invalid, // ev_invalid
};
@ -1027,6 +1176,7 @@ static operation_t op_field[ev_type_count] = {
do_op_invalid, // ev_integer
do_op_invalid, // ev_uinteger
do_op_invalid, // ev_short
do_op_invalid, // ev_double
do_op_invalid, // ev_invalid
};
@ -1043,6 +1193,7 @@ static operation_t op_func[ev_type_count] = {
do_op_func, // ev_integer
do_op_func, // ev_uinteger
do_op_func, // ev_short
do_op_func, // ev_double
do_op_func, // ev_invalid
};
@ -1059,6 +1210,7 @@ static operation_t op_pointer[ev_type_count] = {
do_op_pointer, // ev_integer
do_op_pointer, // ev_uinteger
do_op_pointer, // ev_short
do_op_pointer, // ev_double
do_op_pointer, // ev_invalid
};
@ -1075,6 +1227,7 @@ static operation_t op_quaternion[ev_type_count] = {
do_op_quaternion, // ev_integer
do_op_quaternion, // ev_uinteger
do_op_quaternion, // ev_short
do_op_quaternion, // ev_double
do_op_invalid, // ev_invalid
};
@ -1091,6 +1244,7 @@ static operation_t op_integer[ev_type_count] = {
do_op_integer, // ev_integer
do_op_uinteger, // ev_uinteger
do_op_integer, // ev_short
do_op_double, // ev_double
do_op_invalid, // ev_invalid
};
@ -1107,6 +1261,7 @@ static operation_t op_uinteger[ev_type_count] = {
do_op_uinteger, // ev_integer
do_op_uinteger, // ev_uinteger
do_op_uinteger, // ev_short
do_op_double, // ev_double
do_op_invalid, // ev_invalid
};
@ -1123,6 +1278,24 @@ static operation_t op_short[ev_type_count] = {
do_op_integer, // ev_integer
do_op_uinteger, // ev_uinteger
do_op_short, // ev_short
do_op_double, // ev_double
do_op_invalid, // ev_invalid
};
static operation_t op_double[ev_type_count] = {
do_op_invalid, // ev_void
do_op_invalid, // ev_string
do_op_float, // ev_float
do_op_vector, // ev_vector
do_op_invalid, // ev_entity
do_op_invalid, // ev_field
do_op_invalid, // ev_func
do_op_invalid, // ev_pointer
do_op_quaternion, // ev_quaternion
do_op_integer, // ev_integer
do_op_uinteger, // ev_uinteger
do_op_short, // ev_short
do_op_double, // ev_double
do_op_invalid, // ev_invalid
};
@ -1139,6 +1312,7 @@ static operation_t op_compound[ev_type_count] = {
do_op_compound, // ev_integer
do_op_compound, // ev_uinteger
do_op_compound, // ev_short
do_op_compound, // ev_double
do_op_compound, // ev_invalid
};
@ -1155,6 +1329,7 @@ static operation_t *do_op[ev_type_count] = {
op_integer, // ev_integer
op_uinteger, // ev_uinteger
op_short, // ev_short
op_double, // ev_double
op_compound, // ev_invalid
};
@ -1203,13 +1378,15 @@ static expr_t *
uop_float (int op, expr_t *e, expr_t *e1)
{
static int valid[] = { '+', '-', '!', '~', 'C', 0 };
type_t *type;
if (!valid_op (op, valid))
return error (e1, "invalid unary operator for float: %s",
get_op_string (op));
if (op == '+')
return e1;
if (op == 'C' && get_type (e) != &type_integer)
type = get_type (e);
if (op == 'C' && type != &type_integer && type != &type_double)
return error (e1, "invalid cast of float");
if (!is_constant (e1))
return e;
@ -1222,7 +1399,11 @@ uop_float (int op, expr_t *e, expr_t *e1)
case '~':
return new_float_expr (~(int) expr_float (e1));
case 'C':
return new_integer_expr (expr_float (e1));
if (type == &type_integer) {
return new_integer_expr (expr_float (e1));
} else {
return new_double_expr (expr_float (e1));
}
}
internal_error (e, "float unary op blew up");
}
@ -1420,6 +1601,38 @@ uop_short (int op, expr_t *e, expr_t *e1)
internal_error (e, "short unary op blew up");
}
static expr_t *
uop_double (int op, expr_t *e, expr_t *e1)
{
static int valid[] = { '+', '-', '!', 'C', 0 };
type_t *type;
if (!valid_op (op, valid))
return error (e1, "invalid unary operator for double: %s",
get_op_string (op));
if (op == '+')
return e1;
type = get_type (e);
if (op == 'C' && type != &type_integer && type != &type_float)
return error (e1, "invalid cast of double");
if (!is_constant (e1))
return e;
switch (op) {
case '-':
return new_double_expr (-expr_double (e1));
case '!':
print_type (get_type (e));
return new_integer_expr (!expr_double (e1));
case 'C':
if (type == &type_integer) {
return new_integer_expr (expr_double (e1));
} else {
return new_float_expr (expr_double (e1));
}
}
internal_error (e, "float unary op blew up");
}
static expr_t *
uop_compound (int op, expr_t *e, expr_t *e1)
{
@ -1446,6 +1659,7 @@ static unaryop_t do_unary_op[ev_type_count] = {
uop_integer, // ev_integer
uop_uinteger, // ev_uinteger
uop_short, // ev_short
uop_double, // ev_double
uop_compound, // ev_invalid
};
@ -1487,7 +1701,7 @@ fold_constants (expr_t *e)
if (t1 >= ev_type_count || t2 >= ev_type_count
|| !do_op[t1] || !do_op[t1][t2])
internal_error (e, "invalid type");
internal_error (e, "invalid type %d %d", t1, t2);
return do_op[t1][t2] (op, e, e1, e2);
}
return e;

View file

@ -438,6 +438,9 @@ print_value (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
case ev_string:
label = va ("\\\"%s\\\"", quote_string (e->e.value->v.string_val));
break;
case ev_double:
label = va ("f %g", e->e.value->v.double_val);
break;
case ev_float:
label = va ("f %g", e->e.value->v.float_val);
break;

View file

@ -611,6 +611,15 @@ new_string_expr (const char *string_val)
return e;
}
expr_t *
new_double_expr (double double_val)
{
expr_t *e = new_expr ();
e->type = ex_value;
e->e.value = new_double_val (double_val);
return e;
}
expr_t *
new_float_expr (float float_val)
{
@ -845,6 +854,23 @@ is_float_val (expr_t *e)
return 0;
}
double
expr_double (expr_t *e)
{
if (e->type == ex_nil)
return 0;
if (e->type == ex_value && e->e.value->lltype == ev_double)
return e->e.value->v.double_val;
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
&& e->e.symbol->type->type == ev_double)
return e->e.symbol->s.value->v.double_val;
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var
&& e->e.symbol->s.def->constant
&& is_double (e->e.symbol->s.def->type))
return D_FLOAT (e->e.symbol->s.def);
internal_error (e, "not a double constant");
}
float
expr_float (expr_t *e)
{
@ -1276,6 +1302,9 @@ test_expr (expr_t *e)
}
new = new_float_expr (0);
break;
case ev_double:
new = new_double_expr (0);
break;
case ev_vector:
new = new_vector_expr (zero);
break;
@ -1610,6 +1639,8 @@ unary_expr (int op, expr_t *e)
case ev_func:
case ev_pointer:
internal_error (e, "type check failed!");
case ev_double:
return new_double_expr (-expr_double (e));
case ev_float:
return new_float_expr (-expr_float (e));
case ev_vector:
@ -1676,6 +1707,8 @@ unary_expr (int op, expr_t *e)
case ev_string:
s = expr_string (e);
return new_integer_expr (!s || !s[0]);
case ev_double:
return new_integer_expr (!expr_double (e));
case ev_float:
return new_integer_expr (!expr_float (e));
case ev_vector:
@ -1735,6 +1768,7 @@ unary_expr (int op, expr_t *e)
case ev_func:
case ev_pointer:
case ev_vector:
case ev_double:
return error (e, "invalid type for unary ~");
case ev_float:
return new_float_expr (~(int) expr_float (e));

View file

@ -333,6 +333,7 @@ static keyword_t at_keywords[] = {
// be supported (sanely) by v6 progs.
static keyword_t qf_keywords[] = {
{"quaternion", TYPE, &type_quaternion},
{"double", TYPE, &type_double},
{"int", TYPE, &type_integer },
{"unsigned", TYPE, &type_integer },//FIXME
{"function", TYPE, &type_function },

View file

@ -87,6 +87,8 @@ operand_string (operand_t *op)
case ev_string:
return va ("\"%s\"",
quote_string (op->o.value->v.string_val));
case ev_double:
return va ("%g", op->o.value->v.double_val);
case ev_float:
return va ("%g", op->o.value->v.float_val);
case ev_vector:
@ -159,6 +161,9 @@ print_operand (operand_t *op)
case ev_string:
printf ("\"%s\"", op->o.value->v.string_val);
break;
case ev_double:
printf ("%g", op->o.value->v.double_val);
break;
case ev_float:
printf ("%g", op->o.value->v.float_val);
break;

View file

@ -76,6 +76,7 @@ type_t type_quaternion = { ev_quat, "quaternion" };
type_t type_integer = { ev_integer, "int" };
type_t type_uinteger = { ev_uinteger, "uint" };
type_t type_short = { ev_short, "short" };
type_t type_double = { ev_double, "double" };
type_t *type_nil;
type_t *type_default;
@ -101,6 +102,7 @@ type_t *ev_types[ev_type_count] = {
&type_integer,
&type_uinteger,
&type_short,
&type_double,
&type_invalid,
};
@ -180,6 +182,7 @@ free_type (type_t *type)
case ev_integer:
case ev_uinteger:
case ev_short:
case ev_double:
break;
case ev_field:
case ev_pointer:
@ -214,6 +217,7 @@ append_type (type_t *type, type_t *new)
case ev_integer:
case ev_uinteger:
case ev_short:
case ev_double:
internal_error (0, "append to basic type");
case ev_field:
case ev_pointer:
@ -582,6 +586,9 @@ encode_type (dstring_t *encoding, const type_t *type)
case ev_string:
dasprintf (encoding, "*");
break;
case ev_double:
dasprintf (encoding, "d");
break;
case ev_float:
dasprintf (encoding, "f");
break;
@ -685,6 +692,12 @@ is_integral (const type_t *type)
return is_enum (type);
}
int
is_double (const type_t *type)
{
return type->type == ev_double;
}
int
is_float (const type_t *type)
{
@ -694,7 +707,7 @@ is_float (const type_t *type)
int
is_scalar (const type_t *type)
{
return is_float (type) || is_integral (type);
return is_float (type) || is_integral (type) || is_double (type);
}
int
@ -830,6 +843,7 @@ type_size (const type_t *type)
case ev_integer:
case ev_uinteger:
case ev_short:
case ev_double:
case ev_type_count:
return pr_type_size[type->type];
case ev_invalid:
@ -869,6 +883,7 @@ init_types (void)
{
static struct_def_t zero_struct[] = {
{"string_val", &type_string},
{"double_val", &type_double},
{"float_val", &type_float},
{"entity_val", &type_entity},
{"field_val", &type_field},
@ -884,6 +899,7 @@ init_types (void)
};
static struct_def_t param_struct[] = {
{"string_val", &type_string},
{"double_val", &type_double},
{"float_val", &type_float},
{"vector_val", &type_vector},
{"entity_val", &type_entity},
@ -982,6 +998,7 @@ chain_initial_types (void)
chain_type (&type_integer);
chain_type (&type_uinteger);
chain_type (&type_short);
chain_type (&type_double);
}
chain_type (&type_param);

View file

@ -132,6 +132,16 @@ new_string_val (const char *string_val)
return find_value (&val);
}
ex_value_t *
new_double_val (double double_val)
{
ex_value_t val;
memset (&val, 0, sizeof (val));
set_val_type (&val, &type_double);
val.v.double_val = double_val;
return find_value (&val);
}
ex_value_t *
new_float_val (float float_val)
{