Fix aggregate initializers.

Initializing arrays and structs seems to be working.
This commit is contained in:
Bill Currie 2011-02-15 09:30:37 +09:00
parent d162838299
commit 19f6faf0ad
3 changed files with 117 additions and 19 deletions

View file

@ -564,8 +564,6 @@ expr_t *build_state_expr (expr_t *frame, expr_t *think, expr_t *step);
expr_t *assign_expr (expr_t *e1, expr_t *e2); expr_t *assign_expr (expr_t *e1, expr_t *e2);
expr_t *cast_expr (struct type_s *t, expr_t *e); expr_t *cast_expr (struct type_s *t, expr_t *e);
void init_elements (struct def_s *def, expr_t *eles);
const char *get_op_string (int op); const char *get_op_string (int op);
struct keywordarg_s; struct keywordarg_s;

View file

@ -51,6 +51,7 @@ static __attribute__ ((used)) const char rcsid[] =
#include "def.h" #include "def.h"
#include "defspace.h" #include "defspace.h"
#include "diagnostic.h" #include "diagnostic.h"
#include "emit.h"
#include "expr.h" #include "expr.h"
#include "immediate.h" #include "immediate.h"
#include "options.h" #include "options.h"
@ -178,6 +179,106 @@ def_to_ddef (def_t *def, ddef_t *ddef, int aux)
ddef->s_name = ReuseString (def->name); ddef->s_name = ReuseString (def->name);
} }
static void
init_elements (struct def_s *def, expr_t *eles)
{
expr_t *e, *c;
int count, i, num_params, base_offset;
pr_type_t *g;
def_t *elements;
base_offset = def->offset;
if (def->local && local_expr)
base_offset = 0;
if (is_array (def->type)) {
type_t *array_type = def->type->t.array.type;
int array_size = def->type->t.array.size;
elements = calloc (array_size, sizeof (def_t));
for (i = 0; i < array_size; i++) {
elements[i].type = array_type;
elements[i].space = def->space;
elements[i].offset = base_offset + i * type_size (array_type);
}
num_params = i;
} else if (is_struct (def->type)) {
symtab_t *symtab = def->type->t.symtab;
symbol_t *field;
for (i = 0, field = symtab->symbols; field; field = field->next) {
if (field->sy_type != sy_var)
continue;
i++;
}
elements = calloc (i, sizeof (def_t));
for (i = 0, field = symtab->symbols; field; field = field->next) {
if (field->sy_type != sy_var)
continue;
elements[i].type = field->type;
elements[i].space = def->space;
elements[i].offset = base_offset + field->s.offset;
i++;
}
num_params = i;
} else {
error (eles, "invalid initializer");
return;
}
for (count = 0, e = eles->e.block.head; e; count++, e = e->next) {
convert_name (e);
if (e->type == ex_nil && count < num_params)
convert_nil (e, elements[count].type);
if (e->type == ex_error) {
free (elements);
return;
}
}
if (count > num_params) {
if (options.warnings.initializer)
warning (eles, "excessive elements in initializer");
count = num_params;
}
for (i = 0, e = eles->e.block.head; i < count; i++, e = e->next) {
g = D_POINTER (pr_type_t, &elements[i]);
c = constant_expr (e);
if (c->type == ex_block) {
if (!is_array (elements[i].type)
&& !is_struct (elements[i].type)) {
error (e, "type mismatch in initializer");
continue;
}
init_elements (&elements[i], c);
} else if (c->type == ex_value) {
if (c->e.value.type == ev_integer
&& elements[i].type->type == ev_float)
convert_int (c);
if (get_type (c) != elements[i].type) {
error (e, "type mismatch in initializer");
continue;
}
} else {
if (!def->local || !local_expr) {
error (e, "non-constant initializer");
continue;
}
}
if (def->local && local_expr) {
int offset = elements[i].offset;
type_t *type = elements[i].type;
expr_t *ptr = new_pointer_expr (offset, type, def);
append_expr (local_expr, assign_expr (unary_expr ('.', ptr), c));
} else {
if (c->e.value.type == ev_string) {
EMIT_STRING (def->space, g->string_var,
c->e.value.v.string_val);
} else {
memcpy (g, &c->e, type_size (get_type (c)) * 4);
}
}
}
free (elements);
}
void void
initialize_def (symbol_t *sym, type_t *type, expr_t *init, defspace_t *space, initialize_def (symbol_t *sym, type_t *type, expr_t *init, defspace_t *space,
storage_class_t storage) storage_class_t storage)
@ -210,7 +311,7 @@ initialize_def (symbol_t *sym, type_t *type, expr_t *init, defspace_t *space,
sym->type = type; sym->type = type;
if (!sym->table) if (!sym->table)
symtab_addsymbol (current_symtab, sym); symtab_addsymbol (current_symtab, sym);
if (storage == st_global && init) { if (storage == st_global && init && is_scalar (type)) {
sym->sy_type = sy_const; sym->sy_type = sy_const;
memset (&sym->s.value, 0, sizeof (&sym->s.value)); memset (&sym->s.value, 0, sizeof (&sym->s.value));
if (init->type != ex_value) { //FIXME arrays/structs if (init->type != ex_value) { //FIXME arrays/structs
@ -238,18 +339,23 @@ initialize_def (symbol_t *sym, type_t *type, expr_t *init, defspace_t *space,
return; return;
if (init->type == ex_nil) if (init->type == ex_nil)
convert_nil (init, type); convert_nil (init, type);
if (!type_assignable (type, get_type (init))) { if (init->type == ex_block) {
error (init, "type mismatch in initializer"); init_elements (sym->s.def, init);
return;
}
if (local_expr) {
append_expr (local_expr, assign_expr (new_symbol_expr (sym), init));
} else { } else {
if (init->type != ex_value) { //FIXME arrays/structs if (!type_assignable (type, get_type (init))) {
error (0, "non-constant initializier"); error (init, "type mismatch in initializer");
return; return;
} }
memcpy (D_POINTER (void, sym->s.def), &init->e.value, if (local_expr) {
type_size (type) * sizeof (pr_type_t)); append_expr (local_expr,
assign_expr (new_symbol_expr (sym), init));
} else {
if (init->type != ex_value) { //FIXME enum etc
error (0, "non-constant initializier");
return;
}
memcpy (D_POINTER (void, sym->s.def), &init->e.value,
type_size (type) * sizeof (pr_type_t));
}
} }
} }

View file

@ -2497,12 +2497,6 @@ cast_expr (type_t *type, expr_t *e)
return c; return c;
} }
void
init_elements (def_t *def, expr_t *eles)
{
//FIXME
}
expr_t * expr_t *
selector_expr (keywordarg_t *selector) selector_expr (keywordarg_t *selector)
{ {