mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Add simple bitstruct.
This commit is contained in:
@@ -424,6 +424,7 @@ typedef struct
|
||||
bool big_endian : 1;
|
||||
bool little_endian : 1;
|
||||
bool overlap : 1;
|
||||
bool consecutive : 1;
|
||||
} BitStructDecl;
|
||||
|
||||
typedef struct VarDecl_
|
||||
|
||||
@@ -1698,6 +1698,7 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl)
|
||||
{
|
||||
CONSUME_OR_RET(TOKEN_LBRACE, false);
|
||||
|
||||
bool is_consecutive = false;
|
||||
while (!try_consume(c, TOKEN_RBRACE))
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_type(c), false);
|
||||
@@ -1713,6 +1714,24 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl)
|
||||
SEMA_ERROR_HERE("Expected a field name at this position.");
|
||||
return false;
|
||||
}
|
||||
if (is_consecutive || tok_is(c, TOKEN_EOS))
|
||||
{
|
||||
if (!is_consecutive)
|
||||
{
|
||||
if (decl->bitstruct.members)
|
||||
{
|
||||
SEMA_ERROR_HERE("Expected a ':'.");
|
||||
return false;
|
||||
}
|
||||
is_consecutive = true;
|
||||
}
|
||||
CONSUME_OR_RET(TOKEN_EOS, false);
|
||||
unsigned index = vec_size(decl->bitstruct.members);
|
||||
member_decl->var.start_bit = index;
|
||||
member_decl->var.end_bit = index;
|
||||
vec_add(decl->bitstruct.members, member_decl);
|
||||
continue;
|
||||
}
|
||||
CONSUME_OR_RET(TOKEN_COLON, false);
|
||||
ASSIGN_EXPR_OR_RET(member_decl->var.start, parse_constant_expr(c), false);
|
||||
if (try_consume(c, TOKEN_DOTDOT))
|
||||
@@ -1726,7 +1745,7 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl)
|
||||
CONSUME_EOS_OR_RET(false);
|
||||
vec_add(decl->bitstruct.members, member_decl);
|
||||
}
|
||||
|
||||
decl->bitstruct.consecutive = is_consecutive;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -482,7 +482,8 @@ static bool sema_analyse_struct_union(SemaContext *context, Decl *decl)
|
||||
|
||||
static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *decl, unsigned index, bool allow_overlap)
|
||||
{
|
||||
Decl **members = decl->strukt.members;
|
||||
bool is_consecutive = decl->bitstruct.consecutive;
|
||||
Decl **members = decl->bitstruct.members;
|
||||
Decl *member = members[index];
|
||||
|
||||
// Resolve the type.
|
||||
@@ -511,6 +512,25 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *dec
|
||||
Int max_bits = (Int) { .type = TYPE_I64, .i = { .low = bits } };
|
||||
|
||||
// Resolve the bit range, starting with the beginning
|
||||
|
||||
unsigned start_bit, end_bit;
|
||||
|
||||
if (is_consecutive)
|
||||
{
|
||||
if (member_type != type_bool)
|
||||
{
|
||||
SEMA_ERROR(member->var.type_info, "For bitstructs without bit ranges, the types must all be 'bool'.");
|
||||
return false;
|
||||
}
|
||||
start_bit = end_bit = member->var.start_bit;
|
||||
if (start_bit >= bits)
|
||||
{
|
||||
SEMA_ERROR(member, "This element would overflow the bitstruct size (%d bits).", bits);
|
||||
return false;
|
||||
}
|
||||
goto AFTER_BITCHECK;
|
||||
}
|
||||
|
||||
Expr *start = member->var.start;
|
||||
if (!sema_analyse_expr(context, start)) return false;
|
||||
|
||||
@@ -528,7 +548,6 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *dec
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned start_bit, end_bit;
|
||||
end_bit = start_bit = (unsigned)start->const_expr.ixx.i.low;
|
||||
|
||||
// Handle the end
|
||||
@@ -567,6 +586,7 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *dec
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Check how many bits we need.
|
||||
TypeSize bitsize_type = member_type == type_bool ? 1 : type_size(member_type) * 8;
|
||||
|
||||
@@ -585,6 +605,7 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *dec
|
||||
member->var.start_bit = start_bit;
|
||||
member->var.end_bit = end_bit;
|
||||
|
||||
AFTER_BITCHECK:
|
||||
// Check for duplicate members.
|
||||
for (unsigned i = 0; i < index; i++)
|
||||
{
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.75"
|
||||
#define COMPILER_VERSION "0.4.76"
|
||||
18
test/test_suite/bitstruct/bitstruct_simple.c3
Normal file
18
test/test_suite/bitstruct/bitstruct_simple.c3
Normal file
@@ -0,0 +1,18 @@
|
||||
bitstruct Foo : char
|
||||
{
|
||||
bool a;
|
||||
int b; // #error: For bitstructs without bit ranges, the types must all be 'bool'
|
||||
}
|
||||
|
||||
bitstruct Foo2 : char
|
||||
{
|
||||
bool a0;
|
||||
bool a1;
|
||||
bool a2;
|
||||
bool a3;
|
||||
bool a4;
|
||||
bool a5;
|
||||
bool a6;
|
||||
bool a7;
|
||||
bool a8; // #error: overflow
|
||||
}
|
||||
11
test/test_suite/bitstruct/bitstruct_simple_err_decl.c3
Normal file
11
test/test_suite/bitstruct/bitstruct_simple_err_decl.c3
Normal file
@@ -0,0 +1,11 @@
|
||||
bitstruct Foo : char
|
||||
{
|
||||
bool a : 1;
|
||||
bool b; // #error: Expected a ':'
|
||||
}
|
||||
|
||||
bitstruct Foo2 : char
|
||||
{
|
||||
bool a;
|
||||
bool b : 1; // #error: Expected ';'
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
module test;
|
||||
module bitstruct_ops;
|
||||
import std::io;
|
||||
|
||||
bitstruct Foo : int
|
||||
@@ -41,3 +41,4 @@ fn void! test_bitops() @test
|
||||
b3 ^= Bar { true, true, false };
|
||||
assert(b3.z == true && b3.w == false && b3.gh == true);
|
||||
}
|
||||
|
||||
|
||||
44
test/unit/regression/bitstruct_ops2.c3
Normal file
44
test/unit/regression/bitstruct_ops2.c3
Normal file
@@ -0,0 +1,44 @@
|
||||
module bitstruct_ops_bool;
|
||||
import std::io;
|
||||
|
||||
bitstruct Foo : int
|
||||
{
|
||||
bool a;
|
||||
bool b;
|
||||
}
|
||||
|
||||
bitstruct Bar : char[13]
|
||||
{
|
||||
bool z;
|
||||
bool w;
|
||||
bool gh;
|
||||
}
|
||||
|
||||
fn void! test_bitops() @test
|
||||
{
|
||||
Foo f1 = { true, true };
|
||||
Foo f2 = { true, false };
|
||||
|
||||
Foo f3 = f1 & f2;
|
||||
assert(f3.a == true);
|
||||
assert(f3.b == false);
|
||||
|
||||
Foo f4 = (f1 | ~f2) ^ f3;
|
||||
assert(f4.a == false && f4.b == true);
|
||||
Foo f5 = Foo { true, false } | Foo { false, true };
|
||||
assert(f5.a == true && f5.b == true);
|
||||
|
||||
f5 &= f2;
|
||||
assert(f5.a == true && f5.b == false);
|
||||
|
||||
Bar b1 = { true, true, true };
|
||||
Bar b2 = { true, false, false };
|
||||
|
||||
Bar b3 = b1 & b2;
|
||||
assert(b3.z == true && b3.w == false && b3.gh == false);
|
||||
b3 = ~b3;
|
||||
assert(b3.z == false && b3.w == true && b3.gh == true);
|
||||
b3 ^= Bar { true, true, false };
|
||||
assert(b3.z == true && b3.w == false && b3.gh == true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user