better constant folding with auto-conversion between scalar types (might

make that optional for non-constants)
This commit is contained in:
Bill Currie 2004-01-25 08:55:03 +00:00
parent 58ce134a3c
commit 51b0a66ac7
9 changed files with 1430 additions and 521 deletions

View file

@ -32,6 +32,8 @@
#ifndef __expr_h #ifndef __expr_h
#define __expr_h #define __expr_h
#include "QF/pr_comp.h"
typedef enum { typedef enum {
ex_error, ex_error,
ex_bool, ex_bool,
@ -135,6 +137,8 @@ extern etype_t qc_types[];
extern struct type_s *ev_types[]; extern struct type_s *ev_types[];
extern expr_type expr_types[]; extern expr_type expr_types[];
expr_t *type_mismatch (expr_t *e1, expr_t *e2, int op);
extern expr_t *local_expr; extern expr_t *local_expr;
struct type_s *get_type (expr_t *e); struct type_s *get_type (expr_t *e);
@ -166,6 +170,9 @@ expr_t *new_integer_expr (int integer_val);
expr_t *new_uinteger_expr (unsigned int uinteger_val); expr_t *new_uinteger_expr (unsigned int uinteger_val);
expr_t *new_short_expr (short short_val); expr_t *new_short_expr (short short_val);
int is_constant (expr_t *e);
int is_compare (int op);
int is_logic (int op);
expr_t *constant_expr (expr_t *var); expr_t *constant_expr (expr_t *var);
expr_t *new_bind_expr (expr_t *e1, expr_t *e2); expr_t *new_bind_expr (expr_t *e1, expr_t *e2);
@ -184,6 +191,7 @@ void print_expr (expr_t *e);
void convert_int (expr_t *e); void convert_int (expr_t *e);
void convert_uint (expr_t *e); void convert_uint (expr_t *e);
void convert_short (expr_t *e);
void convert_uint_int (expr_t *e); void convert_uint_int (expr_t *e);
void convert_int_uint (expr_t *e); void convert_int_uint (expr_t *e);
void convert_short_int (expr_t *e); void convert_short_int (expr_t *e);
@ -225,4 +233,6 @@ expr_t *super_expr (struct class_type_s *class_type);
expr_t *message_expr (expr_t *receiver, struct keywordarg_s *message); expr_t *message_expr (expr_t *receiver, struct keywordarg_s *message);
expr_t *sizeof_expr (expr_t *expr, struct type_s *type); expr_t *sizeof_expr (expr_t *expr, struct type_s *type);
expr_t *fold_constants (expr_t *e);
#endif//__expr_h #endif//__expr_h

View file

@ -48,9 +48,9 @@ noinst_PROGRAMS= $(qfodump)
EXTRA_PROGRAMS= qfcc qfodump EXTRA_PROGRAMS= qfcc qfodump
qfcc_SOURCES= \ qfcc_SOURCES= \
class.c cpp.c debug.c def.c emit.c expr.c function.c idstuff.c \ class.c constfold.c cpp.c debug.c def.c emit.c expr.c function.c \
immediate.c linker.c method.c obj_file.c opcodes.c options.c qc-lex.l \ idstuff.c immediate.c linker.c method.c obj_file.c opcodes.c options.c \
qc-parse.y qfcc.c reloc.c strpool.c struct.c switch.c type.c qc-lex.l qc-parse.y qfcc.c reloc.c strpool.c struct.c switch.c type.c
qfcc_LDADD= $(QFCC_LIBS) qfcc_LDADD= $(QFCC_LIBS)
qfcc_DEPENDENCIES= $(QFCC_DEPS) qfcc_DEPENDENCIES= $(QFCC_DEPS)
@ -59,6 +59,6 @@ qfodump_SOURCES= obj_file.c qfodump.c strpool.c
qfodump_LDADD= $(QFCC_LIBS) qfodump_LDADD= $(QFCC_LIBS)
qfodump_DEPENDENCIES= $(QFCC_DEPS) qfodump_DEPENDENCIES= $(QFCC_DEPS)
emit.c expr.c switch.c qc-lex.l: qc-parse.h constfold.$(OBJEXT) emit.$(OBJEXT) expr.$(OBJEXT) switch.$(OBJEXT) qc-lex.$(OBJEXT): qc-parse.h
EXTRA_DIST=qc-lex.c qc-parse.c qc-parse.h EXTRA_DIST=qc-lex.c qc-parse.c qc-parse.h

File diff suppressed because it is too large Load diff

View file

@ -157,7 +157,7 @@ emit_statement (expr_t *e, opcode_t *op, def_t *var_a, def_t *var_b,
statement->c = var_c->ofs; statement->c = var_c->ofs;
ret = var_c; ret = var_c;
} }
#if 0 #if 1
printf ("%s %s(%d) %s(%d) %s(%d)\n", op->opname, printf ("%s %s(%d) %s(%d) %s(%d)\n", op->opname,
var_a ? var_a->name : "", statement->a, var_a ? var_a->name : "", statement->a,
var_b ? var_b->name : "", statement->b, var_b ? var_b->name : "", statement->b,
@ -413,6 +413,8 @@ emit_deref_expr (expr_t *e, def_t *dest)
} }
if (!dest) { if (!dest) {
dest = get_tempdef (type, current_scope); dest = get_tempdef (type, current_scope);
dest->line = e->line;
dest->file = e->file;
dest->users += 2; dest->users += 2;
} }
@ -616,6 +618,8 @@ emit_sub_expr (expr_t *e, def_t *dest)
operator = get_op_string (e->e.expr.op); operator = get_op_string (e->e.expr.op);
if (!dest) { if (!dest) {
dest = get_tempdef (e->e.expr.type, current_scope); dest = get_tempdef (e->e.expr.type, current_scope);
dest->file = e->file;
dest->line = e->line;
dest->users += 2; dest->users += 2;
} }
op = opcode_find (operator, def_a->type, def_b->type, op = opcode_find (operator, def_a->type, def_b->type,
@ -642,6 +646,8 @@ emit_sub_expr (expr_t *e, def_t *dest)
def_b = emit_sub_expr (e->e.expr.e1, 0); def_b = emit_sub_expr (e->e.expr.e1, 0);
if (!dest) { if (!dest) {
dest = get_tempdef (e->e.expr.type, current_scope); dest = get_tempdef (e->e.expr.type, current_scope);
dest->file = e->file;
dest->line = e->line;
dest->users += 2; dest->users += 2;
} }
break; break;
@ -652,6 +658,8 @@ emit_sub_expr (expr_t *e, def_t *dest)
if (e->e.expr.e1->type == ex_expr if (e->e.expr.e1->type == ex_expr
&& e->e.expr.e1->e.expr.op == '.') { && e->e.expr.e1->e.expr.op == '.') {
tmp = get_tempdef (e->e.expr.type, current_scope); tmp = get_tempdef (e->e.expr.type, current_scope);
tmp->file = e->file;
tmp->line = e->line;
tmp->users += 2; tmp->users += 2;
def_b = emit_sub_expr (&zero, 0); def_b = emit_sub_expr (&zero, 0);
} else { } else {
@ -660,6 +668,8 @@ emit_sub_expr (expr_t *e, def_t *dest)
def_a = emit_sub_expr (e->e.expr.e1, tmp); def_a = emit_sub_expr (e->e.expr.e1, tmp);
if (!dest) { if (!dest) {
dest = get_tempdef (e->e.expr.type, current_scope); dest = get_tempdef (e->e.expr.type, current_scope);
dest->file = e->file;
dest->line = e->line;
dest->users += 2; dest->users += 2;
} }
break; break;
@ -694,6 +704,8 @@ emit_sub_expr (expr_t *e, def_t *dest)
def_b = &def_void; def_b = &def_void;
if (!dest) { if (!dest) {
dest = get_tempdef (e->e.expr.type, current_scope); dest = get_tempdef (e->e.expr.type, current_scope);
dest->file = e->file;
dest->line = e->line;
dest->users = 2; dest->users = 2;
} }
operator = "="; operator = "=";
@ -712,8 +724,11 @@ emit_sub_expr (expr_t *e, def_t *dest)
if (!e->e.temp.def) { if (!e->e.temp.def) {
if (dest) if (dest)
e->e.temp.def = dest; e->e.temp.def = dest;
else else {
e->e.temp.def = get_tempdef (e->e.temp.type, current_scope); e->e.temp.def = get_tempdef (e->e.temp.type, current_scope);
e->e.temp.def->line = e->line;
e->e.temp.def->file = e->file;
}
e->e.temp.def->users = e->e.temp.users; e->e.temp.def->users = e->e.temp.users;
e->e.temp.def->expr = e; e->e.temp.def->expr = e;
e->e.temp.def->managed = 1; e->e.temp.def->managed = 1;

View file

@ -274,7 +274,7 @@ get_op_string (int op)
} }
} }
static expr_t * expr_t *
type_mismatch (expr_t *e1, expr_t *e2, int op) type_mismatch (expr_t *e1, expr_t *e2, int op)
{ {
etype_t t1, t2; etype_t t1, t2;
@ -543,13 +543,20 @@ new_short_expr (short short_val)
return e; return e;
} }
int
is_constant (expr_t *e)
{
if (e->type >= ex_string
|| (e->type == ex_def && e->e.def->constant))
return 1;
return 0;
}
expr_t * expr_t *
constant_expr (expr_t *var) constant_expr (expr_t *var)
{ {
if (var->type != ex_def || !var->e.def->constant) { if (var->type != ex_def || !var->e.def->constant)
error (var, "internal error"); return var;
abort ();
}
switch (var->e.def->type->type) { switch (var->e.def->type->type) {
case ev_string: case ev_string:
return new_string_expr (G_GETSTR (var->e.def->ofs)); return new_string_expr (G_GETSTR (var->e.def->ofs));
@ -563,11 +570,8 @@ constant_expr (expr_t *var)
return new_integer_expr (G_INT (var->e.def->ofs)); return new_integer_expr (G_INT (var->e.def->ofs));
case ev_uinteger: case ev_uinteger:
return new_uinteger_expr (G_INT (var->e.def->ofs)); return new_uinteger_expr (G_INT (var->e.def->ofs));
case ev_func: // can't convert
return var;
default: default:
error (var, "internal error"); return var;
abort ();
} }
} }
@ -781,436 +785,6 @@ print_expr (expr_t *e)
} }
} }
static expr_t *
do_op_string (int op, expr_t *e1, expr_t *e2)
{
const char *s1, *s2;
static dstring_t *temp_str;
s1 = e1->e.string_val ? e1->e.string_val : "";
s2 = e2->e.string_val ? e2->e.string_val : "";
switch (op) {
case '+':
if (!temp_str)
temp_str = dstring_newstr ();
dstring_clearstr (temp_str);
dstring_appendstr (temp_str, s1);
dstring_appendstr (temp_str, s2);
e1->e.string_val = save_string (temp_str->str);
break;
case LT:
e1->type = ex_integer;
e1->e.integer_val = strcmp (s1, s2) < 0;
break;
case GT:
e1->type = ex_integer;
e1->e.integer_val = strcmp (s1, s2) > 0;
break;
case LE:
e1->type = ex_integer;
e1->e.integer_val = strcmp (s1, s2) <= 0;
break;
case GE:
e1->type = ex_integer;
e1->e.integer_val = strcmp (s1, s2) >= 0;
break;
case EQ:
e1->type = ex_integer;
e1->e.integer_val = strcmp (s1, s2) == 0;
break;
case NE:
e1->type = ex_integer;
e1->e.integer_val = strcmp (s1, s2) != 0;
break;
default:
return error (e1, "invalid operand for string");
}
return e1;
}
static expr_t *
do_op_float (int op, expr_t *e1, expr_t *e2)
{
float f1, f2;
f1 = e1->e.float_val;
f2 = e2->e.float_val;
switch (op) {
case '+':
e1->e.float_val += f2;
break;
case '-':
e1->e.float_val -= f2;
break;
case '*':
e1->e.float_val *= f2;
break;
case '/':
e1->e.float_val /= f2;
break;
case '&':
e1->e.float_val = (int) f1 & (int) f2;
break;
case '|':
e1->e.float_val = (int) f1 | (int) f2;
break;
case '^':
e1->e.float_val = (int) f1 ^ (int) f2;
break;
case '%':
e1->e.float_val = (int) f1 % (int) f2;
break;
case SHL:
e1->e.float_val = (int) f1 << (int) f2;
break;
case SHR:
e1->e.float_val = (int) f1 >> (int) f2;
break;
case AND:
e1->type = ex_integer;
e1->e.integer_val = f1 && f2;
break;
case OR:
e1->type = ex_integer;
e1->e.integer_val = f1 || f2;
break;
case LT:
e1->type = ex_integer;
e1->e.integer_val = f1 < f2;
break;
case GT:
e1->type = ex_integer;
e1->e.integer_val = f1 > f2;
break;
case LE:
e1->type = ex_integer;
e1->e.integer_val = f1 <= f2;
break;
case GE:
e1->type = ex_integer;
e1->e.integer_val = f1 >= f2;
break;
case EQ:
e1->type = ex_integer;
e1->e.integer_val = f1 == f2;
break;
case NE:
e1->type = ex_integer;
e1->e.integer_val = f1 != f2;
break;
default:
return error (e1, "invalid operand for float");
}
return e1;
}
static expr_t *
do_op_vector (int op, expr_t *e1, expr_t *e2)
{
float *v1, *v2;
v1 = e1->e.vector_val;
v2 = e2->e.vector_val;
switch (op) {
case '+':
VectorAdd (v1, v2, v1);
break;
case '-':
VectorSubtract (v1, v2, v1);
break;
case '*':
e1->type = ex_float;
e1->e.float_val = DotProduct (v1, v2);
break;
case EQ:
e1->type = ex_integer;
e1->e.integer_val = (v1[0] == v2[0])
&& (v1[1] == v2[1])
&& (v1[2] == v2[2]);
break;
case NE:
e1->type = ex_integer;
e1->e.integer_val = (v1[0] == v2[0])
|| (v1[1] != v2[1])
|| (v1[2] != v2[2]);
break;
default:
return error (e1, "invalid operand for vector");
}
return e1;
}
static expr_t *
do_op_integer (int op, expr_t *e1, expr_t *e2)
{
int i1, i2;
i1 = e1->e.integer_val;
i2 = e2->e.integer_val;
switch (op) {
case '+':
e1->e.integer_val += i2;
break;
case '-':
e1->e.integer_val -= i2;
break;
case '*':
e1->e.integer_val *= i2;
break;
case '/':
if (options.warnings.integer_divide)
warning (e2, "%d / %d == %d", i1, i2, i1 / i2);
e1->e.integer_val /= i2;
break;
case '&':
e1->e.integer_val = i1 & i2;
break;
case '|':
e1->e.integer_val = i1 | i2;
break;
case '^':
e1->e.integer_val = i1 ^ i2;
break;
case '%':
e1->e.integer_val = i1 % i2;
break;
case SHL:
e1->e.integer_val = i1 << i2;
break;
case SHR:
e1->e.integer_val = i1 >> i2;
break;
case AND:
e1->e.integer_val = i1 && i2;
break;
case OR:
e1->e.integer_val = i1 || i2;
break;
case LT:
e1->type = ex_integer;
e1->e.integer_val = i1 < i2;
break;
case GT:
e1->type = ex_integer;
e1->e.integer_val = i1 > i2;
break;
case LE:
e1->type = ex_integer;
e1->e.integer_val = i1 <= i2;
break;
case GE:
e1->type = ex_integer;
e1->e.integer_val = i1 >= i2;
break;
case EQ:
e1->type = ex_integer;
e1->e.integer_val = i1 == i2;
break;
case NE:
e1->type = ex_integer;
e1->e.integer_val = i1 != i2;
break;
default:
return error (e1, "invalid operand for integer");
}
return e1;
}
static expr_t *
do_op_uinteger (int op, expr_t *e1, expr_t *e2)
{
unsigned int i1, i2;
i1 = e1->e.uinteger_val;
i2 = e2->e.uinteger_val;
switch (op) {
case '+':
e1->e.uinteger_val += i2;
break;
case '-':
e1->e.uinteger_val -= i2;
break;
case '*':
e1->e.uinteger_val *= i2;
break;
case '/':
if (options.warnings.integer_divide)
warning (e2, "%d / %d == %d", i1, i2, i1 / i2);
e1->e.uinteger_val /= i2;
break;
case '&':
e1->e.uinteger_val = i1 & i2;
break;
case '|':
e1->e.uinteger_val = i1 | i2;
break;
case '^':
e1->e.uinteger_val = i1 ^ i2;
break;
case '%':
e1->e.uinteger_val = i1 % i2;
break;
case SHL:
e1->e.uinteger_val = i1 << i2;
break;
case SHR:
e1->e.uinteger_val = i1 >> i2;
break;
case AND:
e1->e.uinteger_val = i1 && i2;
break;
case OR:
e1->e.uinteger_val = i1 || i2;
break;
case LT:
e1->type = ex_integer;
e1->e.integer_val = i1 < i2;
break;
case GT:
e1->type = ex_integer;
e1->e.integer_val = i1 > i2;
break;
case LE:
e1->type = ex_integer;
e1->e.integer_val = i1 <= i2;
break;
case GE:
e1->type = ex_integer;
e1->e.integer_val = i1 >= i2;
break;
case EQ:
e1->type = ex_integer;
e1->e.integer_val = i1 == i2;
break;
case NE:
e1->type = ex_integer;
e1->e.integer_val = i1 != i2;
break;
default:
return error (e1, "invalid operand for uinteger");
}
return e1;
}
static expr_t *
do_op_short (int op, expr_t *e1, expr_t *e2)
{
int i1, i2;
i1 = e1->e.short_val;
i2 = e2->e.short_val;
switch (op) {
case '+':
e1->e.short_val += i2;
break;
case '-':
e1->e.short_val -= i2;
break;
case '*':
e1->e.short_val *= i2;
break;
case '/':
if (options.warnings.integer_divide)
warning (e2, "%d / %d == %d", i1, i2, i1 / i2);
e1->e.short_val /= i2;
break;
case '&':
e1->e.short_val = i1 & i2;
break;
case '|':
e1->e.short_val = i1 | i2;
break;
case '^':
e1->e.short_val = i1 ^ i2;
break;
case '%':
e1->e.short_val = i1 % i2;
break;
case SHL:
e1->e.short_val = i1 << i2;
break;
case SHR:
e1->e.short_val = i1 >> i2;
break;
case AND:
e1->e.short_val = i1 && i2;
break;
case OR:
e1->e.short_val = i1 || i2;
break;
case LT:
e1->type = ex_integer;
e1->e.integer_val = i1 < i2;
break;
case GT:
e1->type = ex_integer;
e1->e.integer_val = i1 > i2;
break;
case LE:
e1->type = ex_integer;
e1->e.integer_val = i1 <= i2;
break;
case GE:
e1->type = ex_integer;
e1->e.integer_val = i1 >= i2;
break;
case EQ:
e1->type = ex_integer;
e1->e.integer_val = i1 == i2;
break;
case NE:
e1->type = ex_integer;
e1->e.integer_val = i1 != i2;
break;
default:
return error (e1, "invalid operand for uinteger");
}
return e1;
}
static expr_t *
do_op_huh (int op, expr_t *e1, expr_t *e2)
{
return error (e1, "funny constant");
}
static expr_t *(*do_op[]) (int op, expr_t *e1, expr_t *e2) = {
do_op_huh, // ev_void
do_op_string, // ev_string
do_op_float, // ev_float
do_op_vector, // ev_vector
do_op_huh, // ev_entity
do_op_huh, // ev_field
do_op_huh, // ev_func
do_op_huh, // ev_pointer
do_op_huh, // ev_quaternion
do_op_integer, // ev_integer
do_op_uinteger, // ev_uinteger
do_op_short, // ev_short
do_op_huh, // ev_struct
};
static expr_t *
binary_const (int op, expr_t *e1, expr_t *e2)
{
etype_t t1, t2;
t1 = extract_type (e1);
t2 = extract_type (e2);
if (t1 == t2) {
return do_op[t1] (op, e1, e2);
} else {
return type_mismatch (e1, e2, op);
}
}
static expr_t * static expr_t *
field_expr (expr_t *e1, expr_t *e2) field_expr (expr_t *e1, expr_t *e2)
{ {
@ -1628,6 +1202,13 @@ convert_uint (expr_t *e)
e->e.float_val = e->e.uinteger_val; e->e.float_val = e->e.uinteger_val;
} }
void
convert_short (expr_t *e)
{
e->type = ex_float;
e->e.float_val = e->e.short_val;
}
void void
convert_uint_int (expr_t *e) convert_uint_int (expr_t *e)
{ {
@ -1664,7 +1245,7 @@ convert_nil (expr_t *e, type_t *t)
e->e.pointer.type = &type_void; e->e.pointer.type = &type_void;
} }
static int int
is_compare (int op) is_compare (int op)
{ {
if (op == EQ || op == NE || op == LE || op == GE || op == LT || op == GT if (op == EQ || op == NE || op == LE || op == GE || op == LT || op == GT
@ -1673,7 +1254,7 @@ is_compare (int op)
return 0; return 0;
} }
static int int
is_logic (int op) is_logic (int op)
{ {
if (op == OR || op == AND) if (op == OR || op == AND)
@ -1772,10 +1353,8 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
return e1; return e1;
if (e2->type == ex_error) if (e2->type == ex_error)
return e2; return e2;
if (e1->type == ex_def && e1->e.def->constant) e1 = constant_expr (e1);
e1 = constant_expr (e1); e2 = constant_expr (e2);
if (e2->type == ex_def && e2->e.def->constant)
e2 = constant_expr (e2);
t1 = get_type (e1); t1 = get_type (e1);
t2 = get_type (e2); t2 = get_type (e2);
if (!t1 || !t2) { if (!t1 || !t2) {
@ -1860,26 +1439,23 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
} }
} }
if (e1->type >= ex_string && e2->type >= ex_string)
return binary_const (op, e1, e2);
if ((e = check_precedence (op, e1, e2))) if ((e = check_precedence (op, e1, e2)))
return e; return e;
if (t1 != t2) { if (t1 != t2) {
switch (t1->type) { switch (t1->type) {
case ev_float: case ev_float:
if (t2 == &type_vector && op == '*') { if (t2 == &type_vector || t2 == &type_quaternion) {
type = &type_vector; type = &type_vector;
} else { } else {
goto type_mismatch; type = &type_float;
} }
break; break;
case ev_vector: case ev_vector:
if (t2 == &type_float && op == '*') { if (t2 == &type_quaternion) {
type = &type_vector; type = &type_quaternion;
} else { } else {
goto type_mismatch; type = &type_vector;
} }
break; break;
case ev_field: case ev_field:
@ -1905,7 +1481,9 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
break; break;
default: default:
type_mismatch: type_mismatch:
return type_mismatch (e1, e2, op); type = t1;
break;
//return type_mismatch (e1, e2, op);
} }
} else { } else {
type = t1; type = t1;
@ -2296,11 +1874,11 @@ function_expr (expr_t *e1, expr_t *e2)
for (e = e2, i = 0; e; e = e->next, i++) { for (e = e2, i = 0; e; e = e->next, i++) {
if (has_function_call (e)) { if (has_function_call (e)) {
*a = new_temp_def_expr (arg_types[i]); *a = new_temp_def_expr (arg_types[i]);
arg_exprs[arg_expr_count][0] = e; arg_exprs[arg_expr_count][0] = fold_constants (e);
arg_exprs[arg_expr_count][1] = *a; arg_exprs[arg_expr_count][1] = *a;
arg_expr_count++; arg_expr_count++;
} else { } else {
*a = e; *a = fold_constants (e);
} }
// new_binary_expr calls inc_users for both args, but in_users doesn't // new_binary_expr calls inc_users for both args, but in_users doesn't
// walk expression chains so only the first arg expression in the chain // walk expression chains so only the first arg expression in the chain
@ -2484,8 +2062,9 @@ array_expr (expr_t *array, expr_t *index)
e = address_expr (array, index, array_type->aux_type); e = address_expr (array, index, array_type->aux_type);
} else { } else {
if (index->type != ex_short || index->e.integer_val) { if (index->type != ex_short || index->e.integer_val) {
e = new_binary_expr ('.', array, index); e = new_binary_expr ('&', array, index);
e->e.expr.type = pointer_type (array_type->aux_type); //e->e.expr.type = array_type->aux_type;
e->e.expr.type = array_type;
} else { } else {
e = array; e = array;
} }
@ -2653,28 +2232,6 @@ assign_expr (expr_t *e1, expr_t *e2)
if (e2->type == ex_bool) if (e2->type == ex_bool)
e2 = convert_from_bool (e2, t1); e2 = convert_from_bool (e2, t1);
if (e2->type == ex_integer) {
if (t1 == &type_float
|| t1 == &type_vector
|| t1 == &type_quaternion) {
convert_int (e2);
t2 = &type_float;
} else if (t1 == &type_uinteger) {
convert_int_uint (e2);
t2 = &type_uinteger;
}
} else if (e2->type == ex_uinteger) {
if (t1 == &type_float
|| t1 == &type_vector
|| t1 == &type_quaternion) {
convert_uint (e2);
t2 = &type_float;
} else if (t1 == &type_integer) {
convert_uint_int (e2);
t2 = &type_integer;
}
}
if (t1->type != ev_void && e2->type == ex_nil) { if (t1->type != ev_void && e2->type == ex_nil) {
t2 = t1; t2 = t1;
convert_nil (e2, t2); convert_nil (e2, t2);
@ -2726,6 +2283,7 @@ assign_expr (expr_t *e1, expr_t *e2)
} else if (is_indirect (e2)) { } else if (is_indirect (e2)) {
if (extract_type (e1) == ev_struct) { if (extract_type (e1) == ev_struct) {
e2 = address_expr (e2, 0, 0); e2 = address_expr (e2, 0, 0);
e2->rvalue = 1;
return new_move_expr (e1, e2, get_type (e2)); return new_move_expr (e1, e2, get_type (e2));
} }
if (e2->type == ex_uexpr) { if (e2->type == ex_uexpr) {
@ -2738,6 +2296,8 @@ assign_expr (expr_t *e1, expr_t *e2)
&& e->e.expr.e1->type < ex_string) { && e->e.expr.e1->type < ex_string) {
e2 = e; e2 = e;
e2->e.expr.op = '.'; e2->e.expr.op = '.';
e2->e.expr.type = t2;
e2->rvalue = 1;
} }
} }
} }
@ -2764,6 +2324,8 @@ cast_expr (type_t *type, expr_t *e)
if (e->type == ex_error) if (e->type == ex_error)
return e; return e;
check_initialized (e);
e_type = get_type (e); e_type = get_type (e);
if (type == e_type) if (type == e_type)
@ -2778,9 +2340,9 @@ cast_expr (type_t *type, expr_t *e)
|| e_type == &type_uinteger || e_type->type == ev_pointer)) || e_type == &type_uinteger || e_type->type == ev_pointer))
|| (type == &type_float || (type == &type_float
&& (e_type == &type_integer || e_type == &type_uinteger)))) { && (e_type == &type_integer || e_type == &type_uinteger)))) {
c = error (e, "can not cast from %s to %s", return error (e, "can not cast from %s to %s",
pr_type_name[extract_type (e)], pr_type_name[type->type]); pr_type_name[extract_type (e)],
return c; pr_type_name[type->type]);
} }
if (e->type == ex_uexpr && e->e.expr.op == '.') { if (e->type == ex_uexpr && e->e.expr.op == '.') {
e->e.expr.type = type; e->e.expr.type = type;
@ -2795,7 +2357,7 @@ cast_expr (type_t *type, expr_t *e)
void void
init_elements (def_t *def, expr_t *eles) init_elements (def_t *def, expr_t *eles)
{ {
expr_t *e; expr_t *e, *c;
int count, i, num_params; int count, i, num_params;
pr_type_t *g; pr_type_t *g;
def_t *elements; def_t *elements;
@ -2835,36 +2397,35 @@ init_elements (def_t *def, expr_t *eles)
} }
for (i = 0, e = eles->e.block.head; i < count; i++, e = e->next) { for (i = 0, e = eles->e.block.head; i < count; i++, e = e->next) {
g = G_POINTER (pr_type_t, elements[i].ofs); g = G_POINTER (pr_type_t, elements[i].ofs);
if (e->type == ex_def && e->e.def->constant) c = constant_expr (fold_constants (e));
e = constant_expr (e); if (c->type == ex_block) {
if (e->type == ex_block) {
if (elements[i].type->type != ev_array if (elements[i].type->type != ev_array
&& elements[i].type->type != ev_struct) { && elements[i].type->type != ev_struct) {
error (e, "type mismatch in initializer"); error (e, "type mismatch in initializer");
continue; continue;
} }
init_elements (&elements[i], e); init_elements (&elements[i], c);
} else if (e->type >= ex_string) { } else if (c->type >= ex_string) {
if (e->type == ex_integer if (c->type == ex_integer
&& elements[i].type->type == ev_float) && elements[i].type->type == ev_float)
convert_int (e); convert_int (c);
else if (e->type == ex_integer else if (c->type == ex_integer
&& elements[i].type->type == ev_uinteger) && elements[i].type->type == ev_uinteger)
convert_int_uint (e); convert_int_uint (c);
else if (e->type == ex_uinteger else if (c->type == ex_uinteger
&& elements[i].type->type == ev_float) && elements[i].type->type == ev_float)
convert_uint (e); convert_uint (c);
else if (e->type == ex_uinteger else if (c->type == ex_uinteger
&& elements[i].type->type == ev_integer) && elements[i].type->type == ev_integer)
convert_uint_int (e); convert_uint_int (c);
if (get_type (e) != elements[i].type) { if (get_type (c) != elements[i].type) {
error (e, "type mismatch in initializer"); error (e, "type mismatch in initializer");
continue; continue;
} }
if (e->type == ex_string) { if (c->type == ex_string) {
EMIT_STRING (g->string_var, e->e.string_val); EMIT_STRING (g->string_var, c->e.string_val);
} else { } else {
memcpy (g, &e->e, type_size (get_type (e)) * 4); memcpy (g, &c->e, type_size (get_type (c)) * 4);
} }
} else { } else {
error (e, "non-constant initializer"); error (e, "non-constant initializer");

View file

@ -205,7 +205,8 @@ build_builtin_function (def_t *def, expr_t *bi_val)
error (bi_val, "%s is not a function", def->name); error (bi_val, "%s is not a function", def->name);
return 0; return 0;
} }
bi_val = fold_constants (bi_val);
if (bi_val->type != ex_integer && bi_val->type != ex_float) { if (bi_val->type != ex_integer && bi_val->type != ex_float) {
error (bi_val, "invalid constant for = #"); error (bi_val, "invalid constant for = #");
return 0; return 0;
@ -262,6 +263,7 @@ emit_function (function_t *f, expr_t *e)
//print_expr (e); //print_expr (e);
//puts(""); //puts("");
fold_constants (e);
emit_expr (e); emit_expr (e);
e = e->next; e = e->next;
} }

View file

@ -100,16 +100,16 @@ expr_t *argv_expr (void);
%union { %union {
int op; int op;
struct def_s *def; struct def_s *def;
struct hashtab_s *def_list; struct hashtab_s *def_list;
type_t *type; struct type_s *type;
expr_t *expr; struct expr_s *expr;
int integer_val; int integer_val;
float float_val; float float_val;
const char *string_val; const char *string_val;
float vector_val[3]; float vector_val[3];
float quaternion_val[4]; float quaternion_val[4];
struct function_s *function; struct function_s *function;
struct switch_block_s *switch_block; struct switch_block_s *switch_block;
struct param_s *param; struct param_s *param;
struct method_s *method; struct method_s *method;
struct class_s *class; struct class_s *class;
@ -284,8 +284,7 @@ enum
| NAME '=' expr | NAME '=' expr
{ {
$$ = 0; $$ = 0;
if ($3->type == ex_def && $3->e.def->constant) $3 = constant_expr ($3);
$3 = constant_expr ($3);
if ($3->type < ex_string) { if ($3->type < ex_string) {
error ($3, "non-constant initializer"); error ($3, "non-constant initializer");
} else if ($3->type != ex_integer) { } else if ($3->type != ex_integer) {
@ -430,8 +429,7 @@ var_initializer
assign_expr (new_def_expr ($<def>0), $2)); assign_expr (new_def_expr ($<def>0), $2));
def_initialized ($<def>0); def_initialized ($<def>0);
} else { } else {
if ($2->type == ex_def && $2->e.def->constant) $2 = constant_expr ($2);
$2 = constant_expr ($2);
if ($2->type >= ex_string) { if ($2->type >= ex_string) {
if ($<def>0->constant) { if ($<def>0->constant) {
error ($2, "%s re-initialized", $<def>0->name); error ($2, "%s re-initialized", $<def>0->name);
@ -454,8 +452,7 @@ var_initializer
} }
| '=' '#' expr | '=' '#' expr
{ {
if ($3->type == ex_def && $3->e.def->constant) $3 = constant_expr ($3);
$3 = constant_expr ($3);
build_builtin_function ($<def>0, $3); build_builtin_function ($<def>0, $3);
} }
| '=' opt_state_expr { $$ = $<def>0; } | '=' opt_state_expr { $$ = $<def>0; }

View file

@ -94,10 +94,10 @@ case_label_expr (switch_block_t *switch_block, expr_t *value)
SYS_CHECKMEM (cl); SYS_CHECKMEM (cl);
if (value) if (value) {
convert_name (value); convert_name (value);
if (value && value->type == ex_def && value->e.def->constant)
value = constant_expr (value); value = constant_expr (value);
}
if (value && value->type < ex_string) { if (value && value->type < ex_string) {
error (value, "non-constant case value"); error (value, "non-constant case value");
free (cl); free (cl);

View file

@ -542,6 +542,16 @@ parse_type (const char *str)
return _parse_type (&str); return _parse_type (&str);
} }
static int
is_scalar (type_t *type)
{
etype_t t = type->type;
if (t == ev_float || t == ev_integer || t == ev_uinteger || t == ev_short)
return 1;
return 0;
}
int int
type_assignable (type_t *dst, type_t *src) type_assignable (type_t *dst, type_t *src)
{ {
@ -550,7 +560,7 @@ type_assignable (type_t *dst, type_t *src)
if (dst == src) if (dst == src)
return 1; return 1;
if (dst->type != ev_pointer || src->type != ev_pointer) if (dst->type != ev_pointer || src->type != ev_pointer)
return 0; return is_scalar (dst) && is_scalar (src);
dst = dst->aux_type; dst = dst->aux_type;
src = src->aux_type; src = src->aux_type;
if (dst->type == ev_void) if (dst->type == ev_void)