Skip to content

Commit

Permalink
feat: support array initailizer
Browse files Browse the repository at this point in the history
  • Loading branch information
diohabara committed Jul 27, 2023
1 parent 9e5c76b commit bae68dc
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 6 deletions.
95 changes: 89 additions & 6 deletions parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -614,8 +614,86 @@ void global_var() {
push_scope(name)->var = var;
}

// declaration = type-specifier declarator type-suffix ("=" expr)? ";"
// = type-specifier ";"
// Initializer list can end either with "}" or "," followed by "}" to allow a
// trailing comm. This function returns true if it looks like we are at the end
// of an initializer list
bool peek_end() {
Token *tok = token;
bool ret = consume("}") || consume(",") && consume("}");
token = tok;
return ret;
}

void expect_end() {
Token *tok = token;
if (consume(",") && consume("}")) {
return;
}
token = tok;
expect("}");
}

typedef struct Designator Designator;

struct Designator {
Designator *next;
int idx;
};

// Creates a node for an array access. For example, if var represents next a
// variable x and desg represents indices 3 and 4, this function returns a node
// representing x[3][4]
Node *new_desg_node2(Var *var, Designator *desg) {
Token *tok = var->tok;
if (!desg) {
return new_var(var, tok);
}

Node *node = new_desg_node2(var, desg->next);
node = new_binary(ND_ADD, node, new_num(desg->idx, tok), tok);
return new_unary(ND_DEREF, node, tok);
}

Node *new_desg_node(Var *var, Designator *desg, Node *rhs) {
Node *lhs = new_desg_node2(var, desg);
Node *node = new_binary(ND_ASSIGN, lhs, rhs, rhs->tok);
return new_unary(ND_EXPR_STMT, node, rhs->tok);
}

// lvar-initializer = assign
// | "{" lvar-initializer ("," lvar-initializer)* ","? "}"
// An initializer for a local variable is expanded to multiple assignments.
// E.g., this fnction craetes the follwoing nodees for
//
// x[2][3] = {{1, 2, 3}, {4, 5, 6}}
//
// x[0][0] = 1;
// x[0][1] = 2;
// x[0][2] = 3;
// x[1][0] = 4;
// x[1][1] = 5;
// x[1][2] = 6;
Node *lvar_initializer(Node *cur, Var *var, Type *ty, Designator *desg) {
Token *tok = consume("{");
if (!tok) {
cur->next = new_desg_node(var, desg, assign());
return cur->next;
}
if (ty->kind == TY_ARRAY) {
int i = 0;
do {
Designator desg2 = {desg, i++};
cur = lvar_initializer(cur, var, ty->base, &desg2);
} while (!peek_end() && consume(","));
expect_end();
return cur;
}
error_tok(tok, "invalid array intializer");
}

// declaration
// = type-specifier declarator type-suffix ("=" lvar-initializer)? ";"
// = type-specifier ";"
Node *declaration() {
Token *tok = tok;
Type *ty = type_specifier();
Expand Down Expand Up @@ -650,11 +728,16 @@ Node *declaration() {
}

expect("=");
Node *lhs = new_var(var, tok);
Node *rhs = expr();

Node head;
head.next = NULL;
lvar_initializer(&head, var, var->ty, NULL);

expect(";");
Node *node = new_binary(ND_ASSIGN, lhs, rhs, tok);
return new_unary(ND_EXPR_STMT, node, tok);

Node *node = new_node(ND_BLOCK, tok);
node->body = head.next;
return node;
}

Node *read_expr_stmt() {
Expand Down
8 changes: 8 additions & 0 deletions tests
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,14 @@ int main() {
assert(2, ({ char x[1?2:3]; sizeof(x); }), "char x[0?2:3]; sizeof(x);");
assert(3, ({ char x[0?2:3]; sizeof(x); }), "char x[1?2:3]; sizeof(x);");

assert(1, ({ int x[3]={1,2,3}; x[0]; }), "int x[3]={1,2,3}; x[0];");
assert(2, ({ int x[3]={1,2,3}; x[1]; }), "int x[3]={1,2,3}; x[0];");
assert(3, ({ int x[3]={1,2,3}; x[2]; }), "int x[3]={1,2,3}; x[0];");
assert(3, ({ int x[3]={1,2,3,}; x[2]; }), "int x[3]={1,2,3}; x[0];");
assert(2, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[0][1]; }), "int x[2][3]={{1,2,3},{4,5,6}}; x[0][1];");
assert(4, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][0]; }), "int x[2][3]={{1,2,3},{4,5,6}}; x[1][0];");
assert(6, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][2]; }), "int x[2][3]={{1,2,3},{4,5,6}}; x[1][2];");

printf("OK\n");
return 0;
}

0 comments on commit bae68dc

Please sign in to comment.