From c9dd8d9e7f9a31cbec0b60b25deacc05aa757c69 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Mon, 19 Aug 2019 06:53:50 +0900 Subject: [PATCH] Allow parentheses in initializers to be omitted --- chibicc.h | 1 + parse.c | 92 +++++++++++++++++++++++++++++-------------------------- tests | 24 +++++++++++++++ 3 files changed, 74 insertions(+), 43 deletions(-) diff --git a/chibicc.h b/chibicc.h index d014d80..d13db44 100644 --- a/chibicc.h +++ b/chibicc.h @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include diff --git a/parse.c b/parse.c index 56d89d3..3c75bb7 100644 --- a/parse.c +++ b/parse.c @@ -656,53 +656,56 @@ Initializer *emit_struct_padding(Initializer *cur, Type *parent, Member *mem) { Initializer *gvar_initializer(Initializer *cur, Type *ty) { Token *tok = token; - if (consume("{")) { - if (ty->kind == TY_ARRAY) { - int i = 0; + if (ty->kind == TY_ARRAY) { + bool open = consume("{"); + int i = 0; + int limit = ty->is_incomplete ? INT_MAX : ty->array_size; - do { - cur = gvar_initializer(cur, ty->base); - i++; - } while (!peek_end() && consume(",")); + do { + cur = gvar_initializer(cur, ty->base); + i++; + } while (i < limit && !peek_end() && consume(",")); + if (open) expect_end(); - // Set excess array elements to zero. - if (i < ty->array_size) - cur = new_init_zero(cur, size_of(ty->base, tok) * (ty->array_size - i)); - - if (ty->is_incomplete) { - ty->array_size = i; - ty->is_incomplete = false; - } + // Set excess array elements to zero. + cur = new_init_zero(cur, size_of(ty->base, tok) * (ty->array_size - i)); - return cur; + if (ty->is_incomplete) { + ty->array_size = i; + ty->is_incomplete = false; } - if (ty->kind == TY_STRUCT) { - Member *mem = ty->members; + return cur; + } - do { - cur = gvar_initializer(cur, mem->ty); - cur = emit_struct_padding(cur, ty, mem); - mem = mem->next; - } while (!peek_end() && consume(",")); + if (ty->kind == TY_STRUCT) { + bool open = consume("{"); + Member *mem = ty->members; + do { + cur = gvar_initializer(cur, mem->ty); + cur = emit_struct_padding(cur, ty, mem); + mem = mem->next; + } while (mem && !peek_end() && consume(",")); + + if (open) expect_end(); - // Set excess struct elements to zero. - if (mem) { - int sz = size_of(ty, tok) - mem->offset; - if (sz) - cur = new_init_zero(cur, sz); - } - return cur; + // Set excess struct elements to zero. + if (mem) { + int sz = size_of(ty, tok) - mem->offset; + if (sz) + cur = new_init_zero(cur, sz); } - - error_tok(tok, "invalid initializer"); + return cur; } + bool open = consume("{"); Node *expr = conditional(); + if (open) + expect("}"); if (expr->kind == ND_ADDR) { if (expr->lhs->kind != ND_VAR) @@ -842,21 +845,18 @@ Node *lvar_initializer(Node *cur, Var *var, Type *ty, Designator *desg) { return cur; } - Token *tok = consume("{"); - if (!tok) { - cur->next = new_desg_node(var, desg, assign()); - return cur->next; - } - if (ty->kind == TY_ARRAY) { + bool open = consume("{"); int i = 0; + int limit = ty->is_incomplete ? INT_MAX : ty->array_size; do { Designator desg2 = {desg, i++, NULL}; cur = lvar_initializer(cur, var, ty->base, &desg2); - } while (!peek_end() && consume(",")); + } while (i < limit && !peek_end() && consume(",")); - expect_end(); + if (open) + expect_end(); // Set excess array elements to zero. while (i < ty->array_size) { @@ -872,15 +872,17 @@ Node *lvar_initializer(Node *cur, Var *var, Type *ty, Designator *desg) { } if (ty->kind == TY_STRUCT) { + bool open = consume("{"); Member *mem = ty->members; do { Designator desg2 = {desg, 0, mem}; cur = lvar_initializer(cur, var, mem->ty, &desg2); mem = mem->next; - } while (!peek_end() && consume(",")); + } while (mem && !peek_end() && consume(",")); - expect_end(); + if (open) + expect_end(); // Set excess struct elements to zero. for (; mem; mem = mem->next) { @@ -890,7 +892,11 @@ Node *lvar_initializer(Node *cur, Var *var, Type *ty, Designator *desg) { return cur; } - error_tok(tok, "invalid array initializer"); + bool open = consume("{"); + cur->next = new_desg_node(var, desg, assign()); + if (open) + expect("}"); + return cur->next; } // declaration = type-specifier declarator type-suffix ("=" lvar-initializer)? ";" diff --git a/tests b/tests index 0415a3b..70480a3 100644 --- a/tests +++ b/tests @@ -19,6 +19,10 @@ 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}}, {{3, 4}}}; +struct {int a[2];} g13[2] = {{1, 2}, 3, 4}; +struct {int a[2];} g14[2] = {1, 2, 3, 4}; +char *g15 = {"foo"}; +char g16[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0}; int assert(long expected, long actual, char *code) { if (expected == actual) { @@ -540,6 +544,26 @@ int main() { assert(3, g12[1].a[0], "g12[1].a[0]"); assert(4, g12[1].a[1], "g12[1].a[1]"); + assert(1, g13[0].a[0], "g13[0].a[0]"); + assert(2, g13[0].a[1], "g13[0].a[1]"); + assert(3, g13[1].a[0], "g13[1].a[0]"); + assert(4, g13[1].a[1], "g13[1].a[1]"); + + assert(1, g14[0].a[0], "g14[0].a[0]"); + assert(2, g14[0].a[1], "g14[0].a[1]"); + assert(3, g14[1].a[0], "g14[1].a[0]"); + assert(4, g14[1].a[1], "g14[1].a[1]"); + + assert(0, ({ int x[2][3]={0,1,2,3,4,5,}; x[0][0]; }), "int x[2][3]={0,1,2,3,4,5,}; x[0][0];"); + assert(3, ({ int x[2][3]={0,1,2,3,4,5,}; x[1][0]; }), "int x[2][3]={0,1,2,3,4,5,}; x[1][0];"); + + assert(0, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[0].a; }), "struct {int a; int b;} x[2]={0,1,2,3}; x[0].a;"); + assert(2, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[1].a; }), "struct {int a; int b;} x[2]={0,1,2,3}; x[1].a;"); + + assert(0, strcmp(g15, "foo"), "strcmp(g15, \"foo\")"); + assert(0, strcmp(g16[0], "foo"), "strcmp(g16[0], \"foo\")"); + assert(0, strcmp(g16[1], "bar"), "strcmp(g16[1], \"bar\")"); + printf("OK\n"); return 0; } -- GitLab