diff options
| -rw-r--r-- | src/ast.c | 27 | ||||
| -rw-r--r-- | src/ast.h | 3 | ||||
| -rw-r--r-- | src/parse.c | 43 | ||||
| -rw-r--r-- | tests/examples.sh | 134 | ||||
| -rw-r--r-- | tests/helpers.sh | 6 |
5 files changed, 64 insertions, 149 deletions
@@ -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; @@ -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" +} |
