mirror of https://github.com/rui314/chibicc
Add array and struct initializers for global variables
This commit is contained in:
parent
5b0e79f99a
commit
042d671cd9
57
parse.c
57
parse.c
|
@ -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
23
tests
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue