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
#define __expr_h
#include "QF/pr_comp.h"
typedef enum {
ex_error,
ex_bool,
@ -135,6 +137,8 @@ extern etype_t qc_types[];
extern struct type_s *ev_types[];
extern expr_type expr_types[];
expr_t *type_mismatch (expr_t *e1, expr_t *e2, int op);
extern expr_t *local_expr;
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_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 *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_uint (expr_t *e);
void convert_short (expr_t *e);
void convert_uint_int (expr_t *e);
void convert_int_uint (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 *sizeof_expr (expr_t *expr, struct type_s *type);
expr_t *fold_constants (expr_t *e);
#endif//__expr_h

View file

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

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;
ret = var_c;
}
#if 0
#if 1
printf ("%s %s(%d) %s(%d) %s(%d)\n", op->opname,
var_a ? var_a->name : "", statement->a,
var_b ? var_b->name : "", statement->b,
@ -413,6 +413,8 @@ emit_deref_expr (expr_t *e, def_t *dest)
}
if (!dest) {
dest = get_tempdef (type, current_scope);
dest->line = e->line;
dest->file = e->file;
dest->users += 2;
}
@ -616,6 +618,8 @@ emit_sub_expr (expr_t *e, def_t *dest)
operator = get_op_string (e->e.expr.op);
if (!dest) {
dest = get_tempdef (e->e.expr.type, current_scope);
dest->file = e->file;
dest->line = e->line;
dest->users += 2;
}
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);
if (!dest) {
dest = get_tempdef (e->e.expr.type, current_scope);
dest->file = e->file;
dest->line = e->line;
dest->users += 2;
}
break;
@ -652,6 +658,8 @@ emit_sub_expr (expr_t *e, def_t *dest)
if (e->e.expr.e1->type == ex_expr
&& e->e.expr.e1->e.expr.op == '.') {
tmp = get_tempdef (e->e.expr.type, current_scope);
tmp->file = e->file;
tmp->line = e->line;
tmp->users += 2;
def_b = emit_sub_expr (&zero, 0);
} else {
@ -660,6 +668,8 @@ emit_sub_expr (expr_t *e, def_t *dest)
def_a = emit_sub_expr (e->e.expr.e1, tmp);
if (!dest) {
dest = get_tempdef (e->e.expr.type, current_scope);
dest->file = e->file;
dest->line = e->line;
dest->users += 2;
}
break;
@ -694,6 +704,8 @@ emit_sub_expr (expr_t *e, def_t *dest)
def_b = &def_void;
if (!dest) {
dest = get_tempdef (e->e.expr.type, current_scope);
dest->file = e->file;
dest->line = e->line;
dest->users = 2;
}
operator = "=";
@ -712,8 +724,11 @@ emit_sub_expr (expr_t *e, def_t *dest)
if (!e->e.temp.def) {
if (dest)
e->e.temp.def = dest;
else
else {
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->expr = e;
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)
{
etype_t t1, t2;
@ -543,13 +543,20 @@ new_short_expr (short short_val)
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 *
constant_expr (expr_t *var)
{
if (var->type != ex_def || !var->e.def->constant) {
error (var, "internal error");
abort ();
}
if (var->type != ex_def || !var->e.def->constant)
return var;
switch (var->e.def->type->type) {
case ev_string:
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));
case ev_uinteger:
return new_uinteger_expr (G_INT (var->e.def->ofs));
case ev_func: // can't convert
return var;
default:
error (var, "internal error");
abort ();
return var;
}
}
@ -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 *
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;
}
void
convert_short (expr_t *e)
{
e->type = ex_float;
e->e.float_val = e->e.short_val;
}
void
convert_uint_int (expr_t *e)
{
@ -1664,7 +1245,7 @@ convert_nil (expr_t *e, type_t *t)
e->e.pointer.type = &type_void;
}
static int
int
is_compare (int op)
{
if (op == EQ || op == NE || op == LE || op == GE || op == LT || op == GT
@ -1673,7 +1254,7 @@ is_compare (int op)
return 0;
}
static int
int
is_logic (int op)
{
if (op == OR || op == AND)
@ -1772,10 +1353,8 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
return e1;
if (e2->type == ex_error)
return e2;
if (e1->type == ex_def && e1->e.def->constant)
e1 = constant_expr (e1);
if (e2->type == ex_def && e2->e.def->constant)
e2 = constant_expr (e2);
e1 = constant_expr (e1);
e2 = constant_expr (e2);
t1 = get_type (e1);
t2 = get_type (e2);
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)))
return e;
if (t1 != t2) {
switch (t1->type) {
case ev_float:
if (t2 == &type_vector && op == '*') {
if (t2 == &type_vector || t2 == &type_quaternion) {
type = &type_vector;
} else {
goto type_mismatch;
type = &type_float;
}
break;
case ev_vector:
if (t2 == &type_float && op == '*') {
type = &type_vector;
if (t2 == &type_quaternion) {
type = &type_quaternion;
} else {
goto type_mismatch;
type = &type_vector;
}
break;
case ev_field:
@ -1905,7 +1481,9 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
break;
default:
type_mismatch:
return type_mismatch (e1, e2, op);
type = t1;
break;
//return type_mismatch (e1, e2, op);
}
} else {
type = t1;
@ -2296,11 +1874,11 @@ function_expr (expr_t *e1, expr_t *e2)
for (e = e2, i = 0; e; e = e->next, i++) {
if (has_function_call (e)) {
*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_expr_count++;
} else {
*a = e;
*a = fold_constants (e);
}
// 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
@ -2484,8 +2062,9 @@ array_expr (expr_t *array, expr_t *index)
e = address_expr (array, index, array_type->aux_type);
} else {
if (index->type != ex_short || index->e.integer_val) {
e = new_binary_expr ('.', array, index);
e->e.expr.type = pointer_type (array_type->aux_type);
e = new_binary_expr ('&', array, index);
//e->e.expr.type = array_type->aux_type;
e->e.expr.type = array_type;
} else {
e = array;
}
@ -2653,28 +2232,6 @@ assign_expr (expr_t *e1, expr_t *e2)
if (e2->type == ex_bool)
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) {
t2 = t1;
convert_nil (e2, t2);
@ -2726,6 +2283,7 @@ assign_expr (expr_t *e1, expr_t *e2)
} else if (is_indirect (e2)) {
if (extract_type (e1) == ev_struct) {
e2 = address_expr (e2, 0, 0);
e2->rvalue = 1;
return new_move_expr (e1, e2, get_type (e2));
}
if (e2->type == ex_uexpr) {
@ -2738,6 +2296,8 @@ assign_expr (expr_t *e1, expr_t *e2)
&& e->e.expr.e1->type < ex_string) {
e2 = e;
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)
return e;
check_initialized (e);
e_type = get_type (e);
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))
|| (type == &type_float
&& (e_type == &type_integer || e_type == &type_uinteger)))) {
c = error (e, "can not cast from %s to %s",
pr_type_name[extract_type (e)], pr_type_name[type->type]);
return c;
return error (e, "can not cast from %s to %s",
pr_type_name[extract_type (e)],
pr_type_name[type->type]);
}
if (e->type == ex_uexpr && e->e.expr.op == '.') {
e->e.expr.type = type;
@ -2795,7 +2357,7 @@ cast_expr (type_t *type, expr_t *e)
void
init_elements (def_t *def, expr_t *eles)
{
expr_t *e;
expr_t *e, *c;
int count, i, num_params;
pr_type_t *g;
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) {
g = G_POINTER (pr_type_t, elements[i].ofs);
if (e->type == ex_def && e->e.def->constant)
e = constant_expr (e);
if (e->type == ex_block) {
c = constant_expr (fold_constants (e));
if (c->type == ex_block) {
if (elements[i].type->type != ev_array
&& elements[i].type->type != ev_struct) {
error (e, "type mismatch in initializer");
continue;
}
init_elements (&elements[i], e);
} else if (e->type >= ex_string) {
if (e->type == ex_integer
init_elements (&elements[i], c);
} else if (c->type >= ex_string) {
if (c->type == ex_integer
&& elements[i].type->type == ev_float)
convert_int (e);
else if (e->type == ex_integer
convert_int (c);
else if (c->type == ex_integer
&& elements[i].type->type == ev_uinteger)
convert_int_uint (e);
else if (e->type == ex_uinteger
convert_int_uint (c);
else if (c->type == ex_uinteger
&& elements[i].type->type == ev_float)
convert_uint (e);
else if (e->type == ex_uinteger
convert_uint (c);
else if (c->type == ex_uinteger
&& elements[i].type->type == ev_integer)
convert_uint_int (e);
if (get_type (e) != elements[i].type) {
convert_uint_int (c);
if (get_type (c) != elements[i].type) {
error (e, "type mismatch in initializer");
continue;
}
if (e->type == ex_string) {
EMIT_STRING (g->string_var, e->e.string_val);
if (c->type == ex_string) {
EMIT_STRING (g->string_var, c->e.string_val);
} else {
memcpy (g, &e->e, type_size (get_type (e)) * 4);
memcpy (g, &c->e, type_size (get_type (c)) * 4);
}
} else {
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);
return 0;
}
bi_val = fold_constants (bi_val);
if (bi_val->type != ex_integer && bi_val->type != ex_float) {
error (bi_val, "invalid constant for = #");
return 0;
@ -262,6 +263,7 @@ emit_function (function_t *f, expr_t *e)
//print_expr (e);
//puts("");
fold_constants (e);
emit_expr (e);
e = e->next;
}

View file

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

View file

@ -542,6 +542,16 @@ parse_type (const char *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
type_assignable (type_t *dst, type_t *src)
{
@ -550,7 +560,7 @@ type_assignable (type_t *dst, type_t *src)
if (dst == src)
return 1;
if (dst->type != ev_pointer || src->type != ev_pointer)
return 0;
return is_scalar (dst) && is_scalar (src);
dst = dst->aux_type;
src = src->aux_type;
if (dst->type == ev_void)