diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-01-24 12:29:17 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-01-24 12:32:39 +0900 |
| commit | a5bff442c1f09792ff7291652103048688c3a128 (patch) | |
| tree | d30d94201236471591b2af495f8ad41ae6a4cef5 | |
| parent | c780cbb6acd0e0526f2d305138190392bdc8cdd7 (diff) | |
| download | ducc-a5bff442c1f09792ff7291652103048688c3a128.tar.gz ducc-a5bff442c1f09792ff7291652103048688c3a128.tar.zst ducc-a5bff442c1f09792ff7291652103048688c3a128.zip | |
feat: implement array initializer
| -rw-r--r-- | docs/c_grammar.md | 19 | ||||
| -rw-r--r-- | src/ast.c | 9 | ||||
| -rw-r--r-- | src/ast.h | 7 | ||||
| -rw-r--r-- | src/parse.c | 57 | ||||
| -rw-r--r-- | tests/variables.c | 5 |
5 files changed, 81 insertions, 16 deletions
diff --git a/docs/c_grammar.md b/docs/c_grammar.md index 6529b2b..3bde591 100644 --- a/docs/c_grammar.md +++ b/docs/c_grammar.md @@ -9,8 +9,14 @@ * `A?`: Optional A * `{ A }+`: 1 or more repetitions of A * `{ A }*`: 0 or more repetitions of A -* `{ A | S }`: Repetition of A separated by S - * Note that trailing S is not allowed. +* `{ A | S }+`: 1 or more repetitions of A separated by S + * Equivalent to `A { S A }*` +* `{ A | S }*`: 0 or more repetitions of A separated by S + * Equivalent to `{ A | S }+?` +* `{ A |? S }+`: 1 or more repetitions of A separated by S, allowing optional trailing S + * Equivalent to `A { S A }* S?` +* `{ A |? S }*`: 1 or more repetitions of A separated by S, allowing optional trailing S + * Equivalent to `{ A |? S }+?` * `( A )`: Grouping * `# ...`: Additional constraints @@ -222,11 +228,11 @@ member-declarator: declarator? ':' constant-expr enum-specifier: - 'enum' attribute-specifier-sequence? identifier? enum-type-specifier? '{' enumerator-list ','? '}' + 'enum' attribute-specifier-sequence? identifier? enum-type-specifier? '{' enumerator-list '}' 'enum' identifier enum-type-specifier? enumerator-list: - { enumerator | ',' }+ + { enumerator |? ',' }+ enumerator: enumeration-constant attribute-specifier-sequence? ( '=' constant-expr )? @@ -317,15 +323,12 @@ typedef-name: identifier braced-initializer: - '{' ( initializer-list ','? )? '}' + '{' { designation? initializer |? ',' }* '}' initializer: assignment-expr braced-initializer -initializer-list: - { designation? initializer | ',' }+ - designation: designator-list '=' @@ -192,6 +192,8 @@ const char* astnode_kind_stringify(AstNodeKind k) { return "unknown"; case AstNodeKind_nop: return "nop"; + case AstNodeKind_array_initializer: + return "array_initializer"; case AstNodeKind_assign_expr: return "assign_expr"; case AstNodeKind_binary_expr: @@ -631,6 +633,13 @@ AstNode* ast_new_enum_def(const char* name) { return e; } +AstNode* ast_new_array_initializer(AstNode* list) { + AstNode* e = ast_new(AstNodeKind_array_initializer); + e->as.array_initializer = calloc(1, sizeof(ArrayInitializerNode)); + e->as.array_initializer->list = list; + return e; +} + int type_sizeof_struct(Type* ty) { int next_offset = 0; int struct_align = 0; @@ -88,6 +88,7 @@ typedef enum { AstNodeKind_unknown, AstNodeKind_nop, + AstNodeKind_array_initializer, AstNodeKind_assign_expr, AstNodeKind_binary_expr, AstNodeKind_break_stmt, @@ -310,6 +311,10 @@ typedef struct { } TypedefDeclNode; typedef struct { + AstNode* list; +} ArrayInitializerNode; + +typedef struct { AstNode* items; int len; int cap; @@ -354,6 +359,7 @@ struct AstNode { GvarNode* gvar; StructMemberNode* struct_member; TypedefDeclNode* typedef_decl; + ArrayInitializerNode* array_initializer; ListNode* list; } as; }; @@ -407,5 +413,6 @@ AstNode* ast_new_typedef_decl(const char* name, Type* ty); AstNode* ast_new_struct_def(const char* name); AstNode* ast_new_union_def(const char* name); AstNode* ast_new_enum_def(const char* name); +AstNode* ast_new_array_initializer(AstNode* list); #endif diff --git a/src/parse.c b/src/parse.c index ba1f46b..c6ad44c 100644 --- a/src/parse.c +++ b/src/parse.c @@ -395,6 +395,7 @@ static void parse_enum_members(Parser*, int); static AstNode* parse_enum_member(Parser*, int); static Type* parse_type_name(Parser*); static Type* parse_abstract_declarator_opt(Parser*, Type*); +static AstNode* parse_braced_initializer(Parser*); static AstNode* parse_initializer(Parser*); static AstNode* parse_attribute_specifier_sequence_opt(Parser*); static AstNode* parse_attribute_specifier_opt(Parser*); @@ -1315,11 +1316,30 @@ static void declare_func_or_var(Parser* p, AstNode* decl) { int stack_offset = add_lvar(p, name, decl->ty, calc_lvar_stack_offset(p, decl->ty)); if (decl->as.declarator->init) { - AstNode* lhs = ast_new_lvar(name, stack_offset, decl->ty); - AstNode* assign = ast_new_assign_expr(TokenKind_assign, lhs, decl->as.declarator->init); - decl->kind = AstNodeKind_expr_stmt; - decl->as.expr_stmt = calloc(1, sizeof(ExprStmtNode)); - decl->as.expr_stmt->expr = assign; + if (decl->as.declarator->init->kind == AstNodeKind_array_initializer) { + ArrayInitializerNode* inits = decl->as.declarator->init->as.array_initializer; + int len = inits->list->as.list->len; + AstNode* lhs_base = ast_new_lvar(name, stack_offset, decl->ty); + decl->kind = AstNodeKind_list; + decl->as.list = calloc(1, sizeof(ListNode)); + decl->as.list->cap = len; + decl->as.list->len = 0; + decl->as.list->items = calloc(len, sizeof(AstNode)); + for (int i = 0; i < len; ++i) { + AstNode* idx = ast_new_binary_expr(TokenKind_star, ast_new_int(i), + ast_new_int(type_sizeof(lhs_base->ty->base))); + AstNode* lhs = ast_new_deref_expr(ast_new_binary_expr(TokenKind_plus, lhs_base, idx)); + AstNode* assign = ast_new_assign_expr(TokenKind_assign, lhs, &inits->list->as.list->items[i]); + AstNode* stmt = ast_new_expr_stmt(assign); + ast_append(decl, stmt); + } + } else { + AstNode* lhs = ast_new_lvar(name, stack_offset, decl->ty); + AstNode* assign = ast_new_assign_expr(TokenKind_assign, lhs, decl->as.declarator->init); + decl->kind = AstNodeKind_expr_stmt; + decl->as.expr_stmt = calloc(1, sizeof(ExprStmtNode)); + decl->as.expr_stmt->expr = assign; + } } else { decl->kind = AstNodeKind_nop; } @@ -2085,7 +2105,7 @@ static Type* parse_enum_specifier(Parser* p) { } // enumerator-list: -// { enumerator | ',' }+ +// { enumerator |? ',' }+ static void parse_enum_members(Parser* p, int enum_idx) { int next_value = 0; AstNode* list = ast_new_list(16); @@ -2138,11 +2158,32 @@ static Type* parse_abstract_declarator_opt(Parser* p, Type* ty) { return parse_pointer_opt(p, ty); } +// braced-initializer: +// '{' { designation? initializer |? ',' }* '}' +static AstNode* parse_braced_initializer(Parser* p) { + AstNode* inits = ast_new_list(4); + expect(p, TokenKind_brace_l); + while (peek_token(p)->kind != TokenKind_brace_r) { + // TODO: support designation + AstNode* init = parse_initializer(p); + ast_append(inits, init); + if (!consume_token_if(p, TokenKind_comma)) { + break; + } + } + expect(p, TokenKind_brace_r); + return ast_new_array_initializer(inits); +} + // initializer: +// braced-initializer // assignment-expr -// TODO braced-initializer static AstNode* parse_initializer(Parser* p) { - return parse_assignment_expr(p); + if (peek_token(p)->kind == TokenKind_brace_l) { + return parse_braced_initializer(p); + } else { + return parse_assignment_expr(p); + } } // attribute-specifier-sequence: diff --git a/tests/variables.c b/tests/variables.c index 0bd2127..228a625 100644 --- a/tests/variables.c +++ b/tests/variables.c @@ -71,4 +71,9 @@ int main() { ASSERT_EQ(2, d); ASSERT_EQ(2, e); ASSERT_EQ(4, f); + + int arr[3] = {10, 20, 30}; + ASSERT_EQ(10, arr[0]); + ASSERT_EQ(20, arr[1]); + ASSERT_EQ(30, arr[2]); } |
