Add array and struct initializers for global variables

This commit is contained in:
Rui Ueyama 2019-08-18 20:35:17 +09:00
parent 5b0e79f99a
commit 042d671cd9
2 changed files with 80 additions and 0 deletions

57
parse.c
View File

@ -674,6 +674,12 @@ static Initializer *new_init_label(Initializer *cur, char *label) {
return init;
}
static Initializer *new_init_zero(Initializer *cur, int nbytes) {
for (int i = 0; i < nbytes; i++)
cur = new_init_val(cur, 1, 0);
return cur;
}
static Initializer *gvar_init_string(char *p, int len) {
Initializer head = {};
Initializer *cur = &head;
@ -682,9 +688,60 @@ static Initializer *gvar_init_string(char *p, int len) {
return head.next;
}
static Initializer *emit_struct_padding(Initializer *cur, Type *parent, Member *mem) {
int start = mem->offset + mem->ty->size;
int end = mem->next ? mem->next->offset : parent->size;
return new_init_zero(cur, end - start);
}
// gvar-initializer2 = assign
// | "{" (gvar-initializer2 ("," gvar-initializer2)* ","?)? "}"
static Initializer *gvar_initializer2(Initializer *cur, Type *ty) {
Token *tok = token;
if (ty->kind == TY_ARRAY) {
expect("{");
int i = 0;
if (!peek("}")) {
do {
cur = gvar_initializer2(cur, ty->base);
i++;
} while (!peek_end() && consume(","));
}
expect_end();
// Set excess array elements to zero.
if (i < ty->array_len)
cur = new_init_zero(cur, ty->base->size * (ty->array_len - i));
if (ty->is_incomplete) {
ty->size = ty->base->size * i;
ty->array_len = i;
ty->is_incomplete = false;
}
return cur;
}
if (ty->kind == TY_STRUCT) {
expect("{");
Member *mem = ty->members;
if (!peek("}")) {
do {
cur = gvar_initializer2(cur, mem->ty);
cur = emit_struct_padding(cur, ty, mem);
mem = mem->next;
} while (!peek_end() && consume(","));
}
expect_end();
// Set excess struct elements to zero.
if (mem)
cur = new_init_zero(cur, ty->size - mem->offset);
return cur;
}
Node *expr = conditional();
if (expr->kind == ND_ADDR) {

23
tests
View File

@ -21,6 +21,10 @@ int g5 = 5;
long g6 = 6;
int *g7 = &g5;
char *g8 = "abc";
int g9[3] = {0, 1, 2};
char *g10[] = {"foo", "bar"};
struct {char a; int b;} g11[2] = {{1, 2}, {3, 4}};
struct {int a[2];} g12[2] = {{{1, 2}}};
int assert(long expected, long actual, char *code) {
if (expected == actual) {
@ -538,6 +542,25 @@ int main() {
assert(5, *g7, "*g7");
assert(0, strcmp(g8, "abc"), "strcmp(g8, \"abc\")");
assert(0, g9[0], "g9[0]");
assert(1, g9[1], "g9[1]");
assert(2, g9[2], "g9[2]");
assert(0, strcmp(g10[0], "foo"), "strcmp(g10[0], \"foo\")");
assert(0, strcmp(g10[1], "bar"), "strcmp(g10[1], \"bar\")");
assert(0, g10[1][3], "g10[1][3]");
assert(2, sizeof(g10) / sizeof(*g10), "sizeof(g10) / sizeof(*g10)");
assert(1, g11[0].a, "g11[0].a");
assert(2, g11[0].b, "g11[0].b");
assert(3, g11[1].a, "g11[1].a");
assert(4, g11[1].b, "g11[1].b");
assert(1, g12[0].a[0], "g12[0].a[0]");
assert(2, g12[0].a[1], "g12[0].a[1]");
assert(0, g12[1].a[0], "g12[1].a[0]");
assert(0, g12[1].a[1], "g12[1].a[1]");
printf("OK\n");
return 0;
}