aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-03-15 12:35:04 +0900
committernsfisis <nsfisis@gmail.com>2026-05-02 18:30:18 +0900
commit76654319325efadf9ef19f4ce181397ad53f6914 (patch)
tree9600fb99a9ac71766a9f5c9fd0b95541e39a34e7
parent2e308aca586b243b96c8e6c817f748d551cf7468 (diff)
downloadducc-76654319325efadf9ef19f4ce181397ad53f6914.tar.gz
ducc-76654319325efadf9ef19f4ce181397ad53f6914.tar.zst
ducc-76654319325efadf9ef19f4ce181397ad53f6914.zip
feat: partially implement bit-fields
-rw-r--r--src/ast.c27
-rw-r--r--src/ast.h3
-rw-r--r--src/parse.c43
-rw-r--r--tests/examples.sh134
-rw-r--r--tests/helpers.sh6
5 files changed, 64 insertions, 149 deletions
diff --git a/src/ast.c b/src/ast.c
index 790eb81..4d30a66 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -662,8 +662,15 @@ int type_sizeof_struct(Type* ty) {
for (int i = 0; i < members_of(ty)->as.list->len; ++i) {
AstNode* member = &members_of(ty)->as.list->items[i];
- int size = type_sizeof(member->ty);
- int align = type_alignof(member->ty);
+ int size, align;
+ if (member->as.struct_member->is_bitfield) {
+ // TODO
+ size = member->as.struct_member->bitfield_width / 8;
+ align = 1;
+ } else {
+ size = type_sizeof(member->ty);
+ align = type_alignof(member->ty);
+ }
next_offset = to_aligned(next_offset, align);
next_offset += size;
@@ -734,11 +741,23 @@ int type_offsetof(Type* ty, const char* name) {
for (int i = 0; i < members_of(ty)->as.list->len; ++i) {
AstNode* member = &members_of(ty)->as.list->items[i];
- int size = type_sizeof(member->ty);
- int align = type_alignof(member->ty);
+ int size, align;
+ if (member->as.struct_member->is_bitfield) {
+ // TODO
+ size = member->as.struct_member->bitfield_width / 8;
+ align = 1;
+ } else {
+ size = type_sizeof(member->ty);
+ align = type_alignof(member->ty);
+ }
next_offset = to_aligned(next_offset, align);
if (strcmp(member->as.struct_member->name, name) == 0) {
+ if (member->as.struct_member->is_bitfield) {
+ // C23: 7.21.4
+ // if the specified member is a bit-field, the behavior is undefined.
+ fatal_error("type_offsetof: the result of offsetof(bit-field) is undefined");
+ }
return next_offset;
}
next_offset += size;
diff --git a/src/ast.h b/src/ast.h
index f1405c6..f12fd83 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -311,6 +311,9 @@ typedef struct {
typedef struct {
const char* name;
+ bool is_bitfield;
+ int bitfield_offset;
+ int bitfield_width;
} StructMemberNode;
typedef struct {
diff --git a/src/parse.c b/src/parse.c
index 12d4fbf..308277f 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -1898,7 +1898,6 @@ static AstNode* parse_member_declaration_list(Parser* p) {
static AstNode* parse_member_declaration(Parser* p) {
Type* base_ty = parse_specifier_qualifier_list(p);
- AstNode* decls = NULL;
if (consume_token_if(p, TokenKind_semicolon)) {
char* name = generate_anonymous_name(p);
AstNode* decls = ast_new_list(1);
@@ -1909,16 +1908,8 @@ static AstNode* parse_member_declaration(Parser* p) {
ast_append(decls, member);
return decls;
}
- decls = parse_member_declarator_list(p, base_ty);
-
+ AstNode* decls = parse_member_declarator_list(p, base_ty);
expect(p, TokenKind_semicolon);
-
- for (int i = 0; i < decls->as.list->len; i++) {
- const char* member_name = decls->as.list->items[i].as.declarator->name;
- decls->as.list->items[i].kind = AstNodeKind_struct_member;
- decls->as.list->items[i].as.struct_member = calloc(1, sizeof(StructMemberNode));
- decls->as.list->items[i].as.struct_member->name = member_name;
- }
return decls;
}
@@ -2104,9 +2095,37 @@ static AstNode* parse_member_declarator_list(Parser* p, Type* base_ty) {
// member-declarator:
// declarator
-// TODO declarator? ':' constant-expr
+// declarator ':' constant-expr
+// TODO ':' constant-expr
static AstNode* parse_member_declarator(Parser* p, Type* base_ty) {
- return parse_declarator(p, base_ty);
+ AstNode* decl = parse_declarator(p, base_ty);
+
+ const char* name = decl->as.declarator->name;
+ decl->kind = AstNodeKind_struct_member;
+ decl->as.struct_member = calloc(1, sizeof(StructMemberNode));
+ decl->as.struct_member->name = name;
+
+ if (consume_token_if(p, TokenKind_colon)) {
+ AstNode* bit_width_node = parse_constant_expr(p);
+ InitData* bit_width_evaluated = eval_init_expr(bit_width_node, type_new(TypeKind_int));
+ if (bit_width_evaluated->len != 1)
+ fatal_error("parse_member_declarator: invalid bit-field");
+ if (bit_width_evaluated->blocks[0].kind != InitDataBlockKind_bytes)
+ fatal_error("parse_member_declarator: invalid bit-field");
+ if (bit_width_evaluated->blocks[0].as.bytes.len != sizeof(int))
+ fatal_error("parse_member_declarator: invalid bit-field");
+ int bit_width;
+ memcpy(&bit_width, bit_width_evaluated->blocks[0].as.bytes.buf, sizeof(int));
+ if (bit_width < 0)
+ fatal_error("parse_member_declarator: invalid bit-field");
+ if (bit_width % 8 != 0)
+ fatal_error("parse_member_declarator: unimplemented");
+ decl->as.struct_member->is_bitfield = true;
+ decl->as.struct_member->bitfield_offset = -1; // TODO
+ decl->as.struct_member->bitfield_width = bit_width;
+ }
+
+ return decl;
}
// enum-specifier:
diff --git a/tests/examples.sh b/tests/examples.sh
index 6b15ed8..39bf15c 100644
--- a/tests/examples.sh
+++ b/tests/examples.sh
@@ -111,136 +111,4 @@ EOF
test_example fizzbuzz
-# example programs
-cat <<'EOF' > expected
-1
-2
-Fizz
-4
-Buzz
-Fizz
-7
-8
-Fizz
-Buzz
-11
-Fizz
-13
-14
-FizzBuzz
-16
-17
-Fizz
-19
-Buzz
-Fizz
-22
-23
-Fizz
-Buzz
-26
-Fizz
-28
-29
-FizzBuzz
-31
-32
-Fizz
-34
-Buzz
-Fizz
-37
-38
-Fizz
-Buzz
-41
-Fizz
-43
-44
-FizzBuzz
-46
-47
-Fizz
-49
-Buzz
-Fizz
-52
-53
-Fizz
-Buzz
-56
-Fizz
-58
-59
-FizzBuzz
-61
-62
-Fizz
-64
-Buzz
-Fizz
-67
-68
-Fizz
-Buzz
-71
-Fizz
-73
-74
-FizzBuzz
-76
-77
-Fizz
-79
-Buzz
-Fizz
-82
-83
-Fizz
-Buzz
-86
-Fizz
-88
-89
-FizzBuzz
-91
-92
-Fizz
-94
-Buzz
-Fizz
-97
-98
-Fizz
-Buzz
-EOF
-test_diff <<'EOF'
-int printf();
-
-int main() {
- int i;
- for (i = 1; i <= 100; i = i + 1) {
- if (i % 15 == 0) {
- printf("FizzBuzz\n");
- } else if (i % 3 == 0) {
- printf("Fizz\n");
- } else if (i % 5 == 0) {
- printf("Buzz\n");
- } else {
- printf("%d\n", i);
- }
- }
- return 0;
-}
-EOF
-
-cat <<'EOF' > expected
-hello, world
-EOF
-test_diff <<'EOF'
-int printf();
-int main() {
- printf("hello, world\n");
- return 0;
-}
-EOF
+test_example_compile_only 2048
diff --git a/tests/helpers.sh b/tests/helpers.sh
index b8de8a9..09de3df 100644
--- a/tests/helpers.sh
+++ b/tests/helpers.sh
@@ -74,3 +74,9 @@ function test_example() {
diff -u expected output
}
+
+function test_example_compile_only() {
+ filename="../../../examples/$1.c"
+
+ "$ducc" "${CFLAGS:-}" -I ../../../tests -o a.out "$filename"
+}