mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-04-07 18:01:30 +00:00
[qfcc] Parse vector literals correctly
It turned out that for v6 progs (due to lack of double or long) weren't getting correctly parsed vector literals: incorrect "implicit" flag and then a lot of brittleness around constant value conversions.
This commit is contained in:
parent
b58e7791fd
commit
291f920e2a
10 changed files with 173 additions and 56 deletions
|
@ -652,7 +652,7 @@ double expr_double (const expr_t *e) __attribute__((pure));
|
|||
\return The new float constant expression node
|
||||
(expr_t::e::float_val).
|
||||
*/
|
||||
const expr_t *new_float_expr (float float_val);
|
||||
const expr_t *new_float_expr (float float_val, bool implicit);
|
||||
float expr_float (const expr_t *e) __attribute__((pure));
|
||||
|
||||
/** Create a new vector constant expression node.
|
||||
|
@ -737,6 +737,7 @@ unsigned expr_uint (const expr_t *e) __attribute__((pure));
|
|||
|
||||
const expr_t *new_long_expr (pr_long_t long_val, bool implicit);
|
||||
pr_long_t expr_long (const expr_t *e) __attribute__((pure));
|
||||
pr_ulong_t expr_ulong (const expr_t *e) __attribute__((pure));
|
||||
const expr_t *new_ulong_expr (pr_ulong_t ulong_val);
|
||||
|
||||
/** Create a new short constant expression node.
|
||||
|
@ -749,7 +750,8 @@ const expr_t *new_short_expr (short short_val);
|
|||
short expr_short (const expr_t *e) __attribute__((pure));
|
||||
unsigned short expr_ushort (const expr_t *e) __attribute__((pure));
|
||||
|
||||
int expr_integral (const expr_t *e) __attribute__((pure));
|
||||
pr_long_t expr_integral (const expr_t *e) __attribute__((pure));
|
||||
double expr_floating (const expr_t *e) __attribute__((pure));
|
||||
|
||||
bool is_error (const expr_t *e) __attribute__((pure));
|
||||
|
||||
|
@ -817,8 +819,11 @@ int is_quaternion_val (const expr_t *e) __attribute__((pure));
|
|||
int is_int_val (const expr_t *e) __attribute__((pure));
|
||||
int is_uint_val (const expr_t *e) __attribute__((pure));
|
||||
int is_short_val (const expr_t *e) __attribute__((pure));
|
||||
int is_long_val (const expr_t *e) __attribute__((pure));
|
||||
int is_ulong_val (const expr_t *e) __attribute__((pure));
|
||||
int is_double_val (const expr_t *e) __attribute__((pure));
|
||||
int is_integral_val (const expr_t *e) __attribute__((pure));
|
||||
int is_floating_val (const expr_t *e) __attribute__((pure));
|
||||
int is_pointer_val (const expr_t *e) __attribute__((pure));
|
||||
int is_math_val (const expr_t *e) __attribute__((pure));
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ typedef struct {
|
|||
bool assoc_float_add; // allow fp addition to be associative
|
||||
bool assoc_float_mul; // allow fp multiplication to be associative
|
||||
bool no_double; // double fp type is not supported
|
||||
bool no_int; // int type is not supported
|
||||
|
||||
bool help;
|
||||
} code_options_t;
|
||||
|
|
|
@ -69,7 +69,7 @@ static const expr_t *
|
|||
cmp_result_expr (int result)
|
||||
{
|
||||
if (is_float (type_default)) {
|
||||
return new_float_expr (result);
|
||||
return new_float_expr (result, false);
|
||||
} else {
|
||||
return new_int_expr (result, false);
|
||||
}
|
||||
|
@ -224,36 +224,36 @@ do_op_float (int op, const expr_t *e, const expr_t *e1, const expr_t *e2)
|
|||
const expr_t *new = 0;
|
||||
switch (op) {
|
||||
case '+':
|
||||
new = new_float_expr (f1 + f2);
|
||||
new = new_float_expr (f1 + f2, false);
|
||||
break;
|
||||
case '-':
|
||||
new = new_float_expr (f1 - f2);
|
||||
new = new_float_expr (f1 - f2, false);
|
||||
break;
|
||||
case '*':
|
||||
new = new_float_expr (f1 * f2);
|
||||
new = new_float_expr (f1 * f2, false);
|
||||
break;
|
||||
case '/':
|
||||
if (!f2)
|
||||
return error (e1, "divide by zero");
|
||||
new = new_float_expr (f1 / f2);
|
||||
new = new_float_expr (f1 / f2, false);
|
||||
break;
|
||||
case '&':
|
||||
new = new_float_expr ((int)f1 & (int)f2);
|
||||
new = new_float_expr ((int)f1 & (int)f2, false);
|
||||
break;
|
||||
case '|':
|
||||
new = new_float_expr ((int)f1 | (int)f2);
|
||||
new = new_float_expr ((int)f1 | (int)f2, false);
|
||||
break;
|
||||
case '^':
|
||||
new = new_float_expr ((int)f1 ^ (int)f2);
|
||||
new = new_float_expr ((int)f1 ^ (int)f2, false);
|
||||
break;
|
||||
case '%':
|
||||
new = new_float_expr ((int)f1 % (int)f2);
|
||||
new = new_float_expr ((int)f1 % (int)f2, false);
|
||||
break;
|
||||
case QC_SHL:
|
||||
new = new_float_expr ((int)f1 << (int)f2);
|
||||
new = new_float_expr ((int)f1 << (int)f2, false);
|
||||
break;
|
||||
case QC_SHR:
|
||||
new = new_float_expr ((int)f1 >> (int)f2);
|
||||
new = new_float_expr ((int)f1 >> (int)f2, false);
|
||||
break;
|
||||
case QC_AND:
|
||||
new = cmp_result_expr (f1 && f2);
|
||||
|
@ -414,7 +414,7 @@ do_op_vector (int op, const expr_t *e, const expr_t *e1, const expr_t *e2)
|
|||
} else if (op == QC_DOT && is_vector(get_type (e2))) {
|
||||
//e->expr.type = &type_float;
|
||||
} else if (op == '/' && !is_constant (e1)) {
|
||||
e2 = fold_constants (binary_expr ('/', new_float_expr (1), e2));
|
||||
e2 = fold_constants (binary_expr ('/', new_float_expr (1, false), e2));
|
||||
e = fold_constants (binary_expr ('*', e1, e2));
|
||||
} else {
|
||||
//e->expr.type = &type_vector;
|
||||
|
@ -475,7 +475,7 @@ do_op_vector (int op, const expr_t *e, const expr_t *e1, const expr_t *e2)
|
|||
new = new_vector_expr (v);
|
||||
break;
|
||||
case QC_DOT:
|
||||
new = new_float_expr (DotProduct (v1, v2));
|
||||
new = new_float_expr (DotProduct (v1, v2), false);
|
||||
break;
|
||||
case QC_SCALE:
|
||||
VectorScale (v1, v2[0], v);
|
||||
|
@ -561,7 +561,7 @@ do_op_quaternion (int op, const expr_t *e, const expr_t *e1, const expr_t *e2)
|
|||
else
|
||||
e->expr.type = &type_float;
|
||||
} else if (op == '/' && !is_constant (e1)) {
|
||||
e2 = fold_constants (binary_expr ('/', new_float_expr (1), e2));
|
||||
e2 = fold_constants (binary_expr ('/', new_float_expr (1, false), e2));
|
||||
e = fold_constants (binary_expr ('*', e1, e2));
|
||||
} else {
|
||||
e->expr.type = &type_quaternion;
|
||||
|
@ -1314,12 +1314,12 @@ uop_float (int op, const expr_t *e, const expr_t *e1)
|
|||
return e;
|
||||
switch (op) {
|
||||
case '-':
|
||||
return new_float_expr (-expr_float (e1));
|
||||
return new_float_expr (-expr_float (e1), false);
|
||||
case '!':
|
||||
print_type (get_type (e));
|
||||
return cmp_result_expr (!expr_float (e1));
|
||||
case '~':
|
||||
return new_float_expr (~(int) expr_float (e1));
|
||||
return new_float_expr (~(int) expr_float (e1), false);
|
||||
case 'C':
|
||||
if (is_int(type)) {
|
||||
return new_int_expr (expr_float (e1), false);
|
||||
|
@ -1472,7 +1472,7 @@ uop_int (int op, const expr_t *e, const expr_t *e1)
|
|||
case '~':
|
||||
return new_int_expr (~expr_int (e1), false);
|
||||
case 'C':
|
||||
return new_float_expr (expr_int (e1));
|
||||
return new_float_expr (expr_int (e1), false);
|
||||
}
|
||||
internal_error (e, "int unary op blew up");
|
||||
}
|
||||
|
@ -1548,7 +1548,7 @@ uop_double (int op, const expr_t *e, const expr_t *e1)
|
|||
if (is_int(type)) {
|
||||
return new_int_expr (expr_double (e1), false);
|
||||
} else {
|
||||
return new_float_expr (expr_double (e1));
|
||||
return new_float_expr (expr_double (e1), false);
|
||||
}
|
||||
}
|
||||
internal_error (e, "float unary op blew up");
|
||||
|
|
|
@ -93,7 +93,7 @@ convert_name (const expr_t *e)
|
|||
}
|
||||
if (!strcmp (sym->name, "__INFINITY__")
|
||||
&& current_func) {
|
||||
return new_float_expr (INFINITY);
|
||||
return new_float_expr (INFINITY, false);
|
||||
}
|
||||
if (!strcmp (sym->name, "__FILE__")
|
||||
&& current_func) {
|
||||
|
@ -784,9 +784,9 @@ new_double_expr (double double_val, bool implicit)
|
|||
}
|
||||
|
||||
const expr_t *
|
||||
new_float_expr (float float_val)
|
||||
new_float_expr (float float_val, bool implicit)
|
||||
{
|
||||
return new_value_expr (new_float_val (float_val), false);
|
||||
return new_value_expr (new_float_val (float_val), implicit);
|
||||
}
|
||||
|
||||
const expr_t *
|
||||
|
@ -843,6 +843,54 @@ new_long_expr (pr_long_t long_val, bool implicit)
|
|||
return new_value_expr (new_long_val (long_val), implicit);
|
||||
}
|
||||
|
||||
int
|
||||
is_long_val (const expr_t *e)
|
||||
{
|
||||
if (e->type == ex_nil) {
|
||||
return 1;
|
||||
}
|
||||
if (e->type == ex_value && e->value->lltype == ev_long) {
|
||||
return 1;
|
||||
}
|
||||
if (e->type == ex_symbol && e->symbol->sy_type == sy_const) {
|
||||
auto type = e->symbol->type;
|
||||
if (is_long (type)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (e->type == ex_def && e->def->constant) {
|
||||
auto type = e->def->type;
|
||||
if (is_long (type)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
is_ulong_val (const expr_t *e)
|
||||
{
|
||||
if (e->type == ex_nil) {
|
||||
return 1;
|
||||
}
|
||||
if (e->type == ex_value && e->value->lltype == ev_ulong) {
|
||||
return 1;
|
||||
}
|
||||
if (e->type == ex_symbol && e->symbol->sy_type == sy_const) {
|
||||
auto type = e->symbol->type;
|
||||
if (is_ulong (type)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (e->type == ex_def && e->def->constant) {
|
||||
auto type = e->def->type;
|
||||
if (is_ulong (type)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
pr_long_t
|
||||
expr_long (const expr_t *e)
|
||||
{
|
||||
|
@ -861,6 +909,18 @@ new_ulong_expr (pr_ulong_t ulong_val)
|
|||
return new_value_expr (new_ulong_val (ulong_val), false);
|
||||
}
|
||||
|
||||
pr_ulong_t
|
||||
expr_ulong (const expr_t *e)
|
||||
{
|
||||
if (e->type == ex_nil) {
|
||||
return 0;
|
||||
}
|
||||
if (e->type == ex_value && e->value->lltype == ev_ulong) {
|
||||
return e->value->ulong_val;
|
||||
}
|
||||
internal_error (e, "not a ulong constant");
|
||||
}
|
||||
|
||||
const expr_t *
|
||||
new_short_expr (short short_val)
|
||||
{
|
||||
|
@ -1093,13 +1153,17 @@ is_int_val (const expr_t *e)
|
|||
if (e->type == ex_value && e->value->lltype == ev_int) {
|
||||
return 1;
|
||||
}
|
||||
if (e->type == ex_symbol && e->symbol->sy_type == sy_const
|
||||
&& is_integral (e->symbol->type)) {
|
||||
return 1;
|
||||
if (e->type == ex_symbol && e->symbol->sy_type == sy_const) {
|
||||
auto type = e->symbol->type;
|
||||
if (!is_long (type) && !is_ulong (type) && is_integral (type)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (e->type == ex_def && e->def->constant
|
||||
&& is_integral (e->def->type)) {
|
||||
return 1;
|
||||
if (e->type == ex_def && e->def->constant) {
|
||||
auto type = e->def->type;
|
||||
if (!is_long (type) && !is_ulong (type) && is_integral (type)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1239,11 +1303,31 @@ is_integral_val (const expr_t *e)
|
|||
if (is_short_val (e)) {
|
||||
return 1;
|
||||
}
|
||||
if (is_long_val (e)) {
|
||||
return 1;
|
||||
}
|
||||
if (is_ulong_val (e)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
is_floating_val (const expr_t *e)
|
||||
{
|
||||
if (is_constant (e)) {
|
||||
if (is_float_val (e)) {
|
||||
return 1;
|
||||
}
|
||||
if (is_double_val (e)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
pr_long_t
|
||||
expr_integral (const expr_t *e)
|
||||
{
|
||||
if (is_constant (e)) {
|
||||
|
@ -1256,6 +1340,26 @@ expr_integral (const expr_t *e)
|
|||
if (is_short_val (e)) {
|
||||
return expr_short (e);
|
||||
}
|
||||
if (is_long_val (e)) {
|
||||
return expr_long (e);
|
||||
}
|
||||
if (is_ulong_val (e)) {
|
||||
return expr_ulong (e);
|
||||
}
|
||||
}
|
||||
internal_error (e, "not an integral constant");
|
||||
}
|
||||
|
||||
double
|
||||
expr_floating (const expr_t *e)
|
||||
{
|
||||
if (is_constant (e)) {
|
||||
if (is_float_val (e)) {
|
||||
return expr_float (e);
|
||||
}
|
||||
if (is_double_val (e)) {
|
||||
return expr_double (e);
|
||||
}
|
||||
}
|
||||
internal_error (e, "not an integral constant");
|
||||
}
|
||||
|
@ -1647,8 +1751,8 @@ convert_from_bool (const expr_t *e, const type_t *type)
|
|||
expr_t *enum_zero, *enum_one;
|
||||
|
||||
if (is_float (type)) {
|
||||
one = new_float_expr (1);
|
||||
zero = new_float_expr (0);
|
||||
one = new_float_expr (1, false);
|
||||
zero = new_float_expr (0, false);
|
||||
} else if (is_int (type)) {
|
||||
one = new_int_expr (1, false);
|
||||
zero = new_int_expr (0, false);
|
||||
|
@ -1835,7 +1939,7 @@ unary_expr (int op, const expr_t *e)
|
|||
case ev_double:
|
||||
return new_double_expr (-expr_double (e), e->implicit);
|
||||
case ev_float:
|
||||
return new_float_expr (-expr_float (e));
|
||||
return new_float_expr (-expr_float (e), e->implicit);
|
||||
case ev_vector:
|
||||
VectorNegate (expr_vector (e), v);
|
||||
return new_vector_expr (v);
|
||||
|
@ -2047,7 +2151,8 @@ unary_expr (int op, const expr_t *e)
|
|||
case ev_double:
|
||||
return error (e, "invalid type for unary ~");
|
||||
case ev_float:
|
||||
return new_float_expr (~(int) expr_float (e));
|
||||
return new_float_expr (~(int) expr_float (e),
|
||||
e->implicit);
|
||||
case ev_quaternion:
|
||||
QuatConj (expr_vector (e), q);
|
||||
return new_vector_expr (q);
|
||||
|
|
|
@ -985,7 +985,7 @@ inverse_multiply (int op, const expr_t *e1, const expr_t *e2)
|
|||
{
|
||||
// There is no vector/float or quaternion/float instruction and adding
|
||||
// one would mean the engine would have to do 1/f every time
|
||||
auto one = new_float_expr (1);
|
||||
auto one = new_float_expr (1, false);
|
||||
return binary_expr ('*', e1, binary_expr ('/', one, e2));
|
||||
}
|
||||
|
||||
|
|
|
@ -861,6 +861,7 @@ DecodeArgs (int argc, char **argv)
|
|||
if (options.code.progsversion == PROG_ID_VERSION) {
|
||||
options.code.promote_float = false;
|
||||
options.code.no_double = true;
|
||||
options.code.no_int = true;
|
||||
cpp_define ("__VERSION6__=1");
|
||||
if (!options_user_set.code.crc) {
|
||||
options.code.crc = true;
|
||||
|
|
|
@ -593,10 +593,10 @@ parse_number (const rua_tok_t *tok, yyscan_t scanner)
|
|||
|
||||
if (fp) {
|
||||
if (expl == suff_float) {
|
||||
return new_float_expr (fvalue);
|
||||
return new_float_expr (fvalue, false);
|
||||
} else {
|
||||
if (options.code.no_double) {
|
||||
return new_float_expr (fvalue);
|
||||
return new_float_expr (fvalue, expl == suff_implicit);
|
||||
} else {
|
||||
return new_double_expr (fvalue, expl == suff_implicit);
|
||||
}
|
||||
|
@ -609,7 +609,7 @@ parse_number (const rua_tok_t *tok, yyscan_t scanner)
|
|||
} else if (expl == suff_unsigned_long) {
|
||||
return new_ulong_expr (lvalue);
|
||||
} else if (expl == suff_float) {
|
||||
return new_float_expr (lvalue);
|
||||
return new_float_expr (lvalue, false);
|
||||
} else if (expl == suff_double) {
|
||||
return new_double_expr (lvalue, false);
|
||||
} else {
|
||||
|
@ -688,11 +688,12 @@ parse_vector (const rua_tok_t *tok, yyscan_t scanner)
|
|||
bool fp = false;
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (!components[i]->implicit) {
|
||||
error (0, "explict numeric constant in vector literal."
|
||||
" Suggest suffix after closing '.");
|
||||
warning (0, "explicit numeric constant in vector literal."
|
||||
" Suggest suffix after closing '.");
|
||||
return 0;
|
||||
}
|
||||
fp |= is_double (get_type (components[i]));
|
||||
auto t = get_type (components[i]);
|
||||
fp |= is_double (t) || is_float (t);
|
||||
}
|
||||
|
||||
// end points at the final ' and thus any suffix is after that
|
||||
|
@ -721,10 +722,10 @@ parse_vector (const rua_tok_t *tok, yyscan_t scanner)
|
|||
if (expl == suff_float) {
|
||||
for (int i = 0; i < width; i++) {
|
||||
auto c = components[i];
|
||||
if (is_double (get_type (c))) {
|
||||
data.f[i] = expr_double (c);
|
||||
if (is_floating_val (c)) {
|
||||
data.f[i] = expr_floating (c);
|
||||
} else {
|
||||
data.f[i] = expr_long (c);
|
||||
data.f[i] = expr_integral (c);
|
||||
}
|
||||
if (negate[i]) {
|
||||
data.f[i] = -data.f[i];
|
||||
|
@ -734,10 +735,10 @@ parse_vector (const rua_tok_t *tok, yyscan_t scanner)
|
|||
} else if (expl == suff_double) {
|
||||
for (int i = 0; i < width; i++) {
|
||||
auto c = components[i];
|
||||
if (is_double (get_type (c))) {
|
||||
data.d[i] = expr_double (c);
|
||||
if (is_floating_val (c)) {
|
||||
data.d[i] = expr_floating (c);
|
||||
} else {
|
||||
data.d[i] = expr_long (c);
|
||||
data.d[i] = expr_integral (c);
|
||||
}
|
||||
if (negate[i]) {
|
||||
data.d[i] = -data.d[i];
|
||||
|
@ -748,10 +749,10 @@ parse_vector (const rua_tok_t *tok, yyscan_t scanner)
|
|||
if (fp) {
|
||||
for (int i = 0; i < width; i++) {
|
||||
auto c = components[i];
|
||||
if (is_double (get_type (c))) {
|
||||
data.f[i] = expr_double (c);
|
||||
if (is_floating_val (c)) {
|
||||
data.f[i] = expr_floating (c);
|
||||
} else {
|
||||
data.f[i] = expr_long (c);
|
||||
data.f[i] = expr_integral (c);
|
||||
}
|
||||
if (negate[i]) {
|
||||
data.f[i] = -data.f[i];
|
||||
|
@ -761,7 +762,11 @@ parse_vector (const rua_tok_t *tok, yyscan_t scanner)
|
|||
} else {
|
||||
for (int i = 0; i < width; i++) {
|
||||
auto c = components[i];
|
||||
data.i[i] = expr_long (c);
|
||||
if (is_floating_val (c)) {
|
||||
data.i[i] = expr_floating (c);
|
||||
} else {
|
||||
data.i[i] = expr_integral (c);
|
||||
}
|
||||
if (negate[i]) {
|
||||
data.i[i] = -data.i[i];
|
||||
}
|
||||
|
@ -983,7 +988,7 @@ convert_long (const expr_t *value)
|
|||
if (f != v) {
|
||||
warning (0, "cannot represent value");
|
||||
}
|
||||
return new_float_expr (f);
|
||||
return new_float_expr (f, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ FRAMEID {ID}(\.{ID})*
|
|||
|
||||
{FLOAT} {
|
||||
float f = strtof (yytext, 0);
|
||||
yylval->expr = new_float_expr (f);
|
||||
yylval->expr = new_float_expr (f, false);
|
||||
return VALUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -1057,7 +1057,7 @@ vector_call (sblock_t *sblock, const expr_t *earg, const expr_t *param, int ind,
|
|||
|
||||
for (i = 0; i < 3; i++) {
|
||||
n = new_name_expr (names[i]);
|
||||
v = new_float_expr (earg->value->vector_val[i]);
|
||||
v = new_float_expr (earg->value->vector_val[i], false);
|
||||
a = assign_expr (field_expr (param, n), v);
|
||||
param = new_param_expr (get_type (earg), ind);
|
||||
//a->line = earg->line;
|
||||
|
@ -1554,7 +1554,7 @@ statement_return (sblock_t *sblock, const expr_t *e)
|
|||
if (options.code.progsversion == PROG_ID_VERSION) {
|
||||
auto n = new_expr ();
|
||||
*n = *e;
|
||||
n->retrn.ret_val = new_float_expr (0);
|
||||
n->retrn.ret_val = new_float_expr (0, false);
|
||||
e = n;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,9 +143,9 @@ case_label_expr (switch_block_t *switch_block, const expr_t *value)
|
|||
value = new_int_expr (expr_float (value), false);
|
||||
} else if (is_float (type) && is_integral (val_type)) {
|
||||
debug (value, "integeral label used in float switch");
|
||||
value = new_float_expr (expr_int (value));
|
||||
value = new_float_expr (expr_int (value), false);
|
||||
} else if (is_float (type) && is_float (val_type)) {
|
||||
value = new_float_expr (expr_float (value));
|
||||
value = new_float_expr (expr_float (value), false);
|
||||
debug (value, "float label used in float switch");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue