Add simple bitstruct.

This commit is contained in:
Christoffer Lerno
2023-02-18 16:59:16 +01:00
parent 6e8c69cd52
commit 62fbf4da47
8 changed files with 120 additions and 5 deletions

View File

@@ -424,6 +424,7 @@ typedef struct
bool big_endian : 1;
bool little_endian : 1;
bool overlap : 1;
bool consecutive : 1;
} BitStructDecl;
typedef struct VarDecl_

View File

@@ -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;
}
/**

View File

@@ -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++)
{

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.75"
#define COMPILER_VERSION "0.4.76"

View 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
}

View 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 ';'
}

View File

@@ -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);
}

View 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);
}