Skip to content
Snippets Groups Projects
Commit 21336ef4 authored by Rui Ueyama's avatar Rui Ueyama
Browse files

Handle struct initializers for local variables

parent 53c6fc6f
Branches
No related merge requests found
......@@ -236,6 +236,7 @@ struct Member {
Type *ty;
Token *tok; // for error message
Token *name;
int idx;
int offset;
};
......
......@@ -81,6 +81,7 @@ typedef struct InitDesg InitDesg;
struct InitDesg {
InitDesg *next;
int idx;
Member *member;
Var *var;
};
......@@ -243,6 +244,20 @@ static Initializer *new_initializer(Type *ty, bool is_flexible) {
init->children = calloc(ty->array_len, sizeof(Initializer *));
for (int i = 0; i < ty->array_len; i++)
init->children[i] = new_initializer(ty->base, false);
return init;
}
if (ty->kind == TY_STRUCT) {
// Count the number of struct members.
int len = 0;
for (Member *mem = ty->members; mem; mem = mem->next)
len++;
init->children = calloc(len, sizeof(Initializer *));
for (Member *mem = ty->members; mem; mem = mem->next)
init->children[mem->idx] = new_initializer(mem->ty, false);
return init;
}
return init;
......@@ -673,7 +688,27 @@ static void array_initializer(Token **rest, Token *tok, Initializer *init) {
}
}
// initializer = string-initializer | array-initializer | assign
// struct-initializer = "{" initializer ("," initializer)* "}"
static void struct_initializer(Token **rest, Token *tok, Initializer *init) {
tok = skip(tok, "{");
Member *mem = init->ty->members;
while (!consume(rest, tok, "}")) {
if (mem != init->ty->members)
tok = skip(tok, ",");
if (mem) {
initializer2(&tok, tok, init->children[mem->idx]);
mem = mem->next;
} else {
tok = skip_excess_element(tok);
}
}
}
// initializer = string-initializer | array-initializer
// | struct-initializer | assign
static void initializer2(Token **rest, Token *tok, Initializer *init) {
if (init->ty->kind == TY_ARRAY && tok->kind == TK_STR) {
string_initializer(rest, tok, init);
......@@ -685,6 +720,11 @@ static void initializer2(Token **rest, Token *tok, Initializer *init) {
return;
}
if (init->ty->kind == TY_STRUCT) {
struct_initializer(rest, tok, init);
return;
}
init->expr = assign(rest, tok);
}
......@@ -699,6 +739,12 @@ static Node *init_desg_expr(InitDesg *desg, Token *tok) {
if (desg->var)
return new_var_node(desg->var, tok);
if (desg->member) {
Node *node = new_unary(ND_MEMBER, init_desg_expr(desg->next, tok), tok);
node->member = desg->member;
return node;
}
Node *lhs = init_desg_expr(desg->next, tok);
Node *rhs = new_num(desg->idx, tok);
return new_unary(ND_DEREF, new_add(lhs, rhs, tok), tok);
......@@ -715,6 +761,17 @@ static Node *create_lvar_init(Initializer *init, Type *ty, InitDesg *desg, Token
return node;
}
if (ty->kind == TY_STRUCT) {
Node *node = new_node(ND_NULL_EXPR, tok);
for (Member *mem = ty->members; mem; mem = mem->next) {
InitDesg desg2 = {desg, 0, mem};
Node *rhs = create_lvar_init(init->children[mem->idx], mem->ty, &desg2, tok);
node = new_binary(ND_COMMA, node, rhs, tok);
}
return node;
}
if (!init->expr)
return new_node(ND_NULL_EXPR, tok);
......@@ -734,7 +791,7 @@ static Node *create_lvar_init(Initializer *init, Type *ty, InitDesg *desg, Token
// x[1][1] = 9;
static Node *lvar_initializer(Token **rest, Token *tok, Var *var) {
Initializer *init = initializer(rest, tok, var->ty, &var->ty);
InitDesg desg = {NULL, 0, var};
InitDesg desg = {NULL, 0, NULL, var};
// If a partial initializer list is given, the standard requires
// that unspecified elements are set to 0. Here, we simply
......@@ -1430,18 +1487,21 @@ static Node *unary(Token **rest, Token *tok) {
static void struct_members(Token **rest, Token *tok, Type *ty) {
Member head = {};
Member *cur = &head;
int idx = 0;
while (!equal(tok, "}")) {
Type *basety = typespec(&tok, tok, NULL);
int i = 0;
bool first = true;
while (!consume(&tok, tok, ";")) {
if (i++)
if (!first)
tok = skip(tok, ",");
first = false;
Member *mem = calloc(1, sizeof(Member));
mem->ty = declarator(&tok, tok, basety);
mem->name = mem->ty->name;
mem->idx = idx++;
cur = cur->next = mem;
}
}
......
......@@ -35,6 +35,26 @@ int main() {
ASSERT(2, ({ typedef char T[]; T x="x"; T y="foo"; sizeof(x); }));
ASSERT(4, ({ typedef char T[]; T x="x"; T y="foo"; sizeof(y); }));
ASSERT(1, ({ struct {int a; int b; int c;} x={1,2,3}; x.a; }));
ASSERT(2, ({ struct {int a; int b; int c;} x={1,2,3}; x.b; }));
ASSERT(3, ({ struct {int a; int b; int c;} x={1,2,3}; x.c; }));
ASSERT(1, ({ struct {int a; int b; int c;} x={1}; x.a; }));
ASSERT(0, ({ struct {int a; int b; int c;} x={1}; x.b; }));
ASSERT(0, ({ struct {int a; int b; int c;} x={1}; x.c; }));
ASSERT(1, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].a; }));
ASSERT(2, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].b; }));
ASSERT(3, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].a; }));
ASSERT(4, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].b; }));
ASSERT(0, ({ struct {int a; int b;} x[2]={{1,2}}; x[1].b; }));
ASSERT(0, ({ struct {int a; int b;} x={}; x.a; }));
ASSERT(0, ({ struct {int a; int b;} x={}; x.b; }));
ASSERT(5, ({ typedef struct {int a,b,c,d,e,f;} T; T x={1,2,3,4,5,6}; T y; y=x; y.e; }));
ASSERT(2, ({ typedef struct {int a,b;} T; T x={1,2}; T y, z; z=y=x; z.b; }));
printf("OK\n");
return 0;
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment