struct type *next;
int size, align;
void (*init)(struct type *type, struct value *val);
+ void (*prepare_type)(struct type *type, int parse_time);
void (*print)(struct type *type, struct value *val);
void (*print_type)(struct type *type, FILE *f);
int (*cmp_order)(struct type *t1, struct type *t2,
{
struct value *ret;
- if (!t->size)
- val_init(t, NULL);
+ if (t->prepare_type)
+ t->prepare_type(t, 0);
+
ret = calloc(1, t->size);
if (init)
memcpy(ret, init, t->size);
{
struct lrval ret = _interp_exec(e);
- if (typeret)
+ if (ret.lval)
*typeret = ret.type;
+ else
+ free_value(ret.type, &ret.rval);
return ret.lval;
}
a "`copy`" primitive will eventually be define which can be used to
make a copy of an array with controllable recursive depth.
+For now we have two sorts of array, those with fixed size either because
+it is given as a literal number or because it is a struct member (which
+cannot have a runtime-changing size), and those with a size that is
+determined at runtime - local variables with a const size. The former
+have their size calculated at parse time, the latter at run time.
+
+For the latter type, the `size` field of the type is the size of a
+pointer, and the array is reallocated every time it comes into scope.
+
+We differentiate struct fields with a const size from local variables
+with a const size by whether they are prepared at parse time or not.
+
###### type union fields
struct {
- int size;
+ short size;
+ short static_size;
struct variable *vsize;
struct type *member;
} array;
+###### value union fields
+ void *array; // used if not static_size
+
###### value functions
- static void array_init(struct type *type, struct value *val)
+ static void array_prepare_type(struct type *type, int parse_time)
{
- int i;
+ mpz_t q;
+ if (!type->array.vsize || type->array.static_size)
+ return;
- if (type->array.vsize) {
- mpz_t q;
- mpz_init(q);
- mpz_tdiv_q(q, mpq_numref(type->array.vsize->val->num),
- mpq_denref(type->array.vsize->val->num));
- type->array.size = mpz_get_si(q);
- mpz_clear(q);
+ mpz_init(q);
+ mpz_tdiv_q(q, mpq_numref(type->array.vsize->val->num),
+ mpq_denref(type->array.vsize->val->num));
+ type->array.size = mpz_get_si(q);
+ mpz_clear(q);
+
+ if (parse_time) {
+ type->array.static_size = 1;
+ type->size = type->array.size * type->array.member->size;
+ type->align = type->array.member->align;
}
- type->size = type->array.size * type->array.member->size;
- type->align = type->array.member->align;
+ }
+
+ static void array_init(struct type *type, struct value *val)
+ {
+ int i;
+ void *ptr = val->ptr;
if (!val)
- return;
+ return;
+ if (!type->array.static_size) {
+ val->array = calloc(type->array.size,
+ type->array.member->size);
+ ptr = val->array;
+ }
for (i = 0; i < type->array.size; i++) {
struct value *v;
- v = (void*)val->ptr + i * type->array.member->size;
+ v = (void*)ptr + i * type->array.member->size;
val_init(type->array.member, v);
}
}
static void array_free(struct type *type, struct value *val)
{
int i;
+ void *ptr = val->ptr;
+ if (!type->array.static_size)
+ ptr = val->array;
for (i = 0; i < type->array.size; i++) {
struct value *v;
- v = (void*)val->ptr + i * type->array.member->size;
+ v = (void*)ptr + i * type->array.member->size;
free_value(type->array.member, v);
}
+ if (!type->array.static_size)
+ free(ptr);
}
static int array_compat(struct type *require, struct type *have)
static struct type array_prototype = {
.init = array_init,
+ .prepare_type = array_prepare_type,
.print_type = array_print_type,
.compat = array_compat,
.free = array_free,
+ .size = sizeof(void*),
+ .align = sizeof(void*),
};
###### declare terminals
char tail[3];
mpq_t num;
struct text noname = { "", 0 };
+ struct type *t;
- $0 = add_type(c, noname, &array_prototype);
- $0->array.member = $<4;
- $0->array.vsize = NULL;
+ $0 = t = add_type(c, noname, &array_prototype);
+ t->array.member = $<4;
+ t->array.vsize = NULL;
if (number_parse(num, tail, $2.txt) == 0)
tok_err(c, "error: unrecognised number", &$2);
else if (tail[0])
tok_err(c, "error: unsupported number suffix", &$2);
else {
- $0->array.size = mpz_get_ui(mpq_numref(num));
+ t->array.size = mpz_get_ui(mpq_numref(num));
if (mpz_cmp_ui(mpq_denref(num), 1) != 0) {
tok_err(c, "error: array size must be an integer",
&$2);
&$2);
mpq_clear(num);
}
+ t->array.static_size = 1;
+ t->size = t->array.size * t->array.member->size;
+ t->align = t->array.member->align;
} }$
| [ IDENTIFIER ] Type ${ {
case Index: {
mpz_t q;
long i;
+ void *ptr;
lleft = linterp_exec(b->left, <ype);
right = interp_exec(b->right, &rtype);
i = mpz_get_si(q);
mpz_clear(q);
+ if (ltype->array.static_size)
+ ptr = lleft;
+ else
+ ptr = *(void**)lleft;
rvtype = ltype->array.member;
if (i >= 0 && i < ltype->array.size)
- lrv = (void*)lleft + i * rvtype->size;
+ lrv = ptr + i * rvtype->size;
else
val_init(ltype->array.member, &rv);
ltype = NULL;
for (i = 0; i < type->structure.nfields; i++) {
struct value *v;
v = (void*) val->ptr + type->structure.fields[i].offset;
- val_init(type->structure.fields[i].type, v);
+ if (type->structure.fields[i].init)
+ dup_value(type->structure.fields[i].type,
+ type->structure.fields[i].init,
+ v);
+ else
+ val_init(type->structure.fields[i].type, v);
}
}
$0 = calloc(1, sizeof(struct fieldlist));
$0->f.name = $1.txt;
$0->f.type = $<3;
- $0->f.init = val_alloc($0->f.type, NULL);
+ if ($0->f.type->prepare_type)
+ $0->f.type->prepare_type($0->f.type, 1);
}$
###### forward decls
struct variable *v = cast(var, b->left)->var;
if (v->merged)
v = v->merged;
+ free_value(v->type, v->val);
+ free(v->val);
if (b->right) {
right = interp_exec(b->right, &rtype);
- free_value(v->type, v->val);
- free(v->val);
v->val = val_alloc(v->type, &right);
rtype = Tnone;
} else {
- free_value(v->type, v->val);
v->val = val_alloc(v->type, NULL);
}
break;