aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-01-24 12:29:17 +0900
committernsfisis <nsfisis@gmail.com>2026-01-24 12:32:39 +0900
commita5bff442c1f09792ff7291652103048688c3a128 (patch)
treed30d94201236471591b2af495f8ad41ae6a4cef5
parentc780cbb6acd0e0526f2d305138190392bdc8cdd7 (diff)
downloadducc-a5bff442c1f09792ff7291652103048688c3a128.tar.gz
ducc-a5bff442c1f09792ff7291652103048688c3a128.tar.zst
ducc-a5bff442c1f09792ff7291652103048688c3a128.zip
feat: implement array initializer
-rw-r--r--docs/c_grammar.md19
-rw-r--r--src/ast.c9
-rw-r--r--src/ast.h7
-rw-r--r--src/parse.c57
-rw-r--r--tests/variables.c5
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 '='
diff --git a/src/ast.c b/src/ast.c
index 7c7df72..c2e1aba 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -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;
diff --git a/src/ast.h b/src/ast.h
index 498e6c3..3f9eb82 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -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]);
}