[cexpr] Add a flags type

Based on the flags type used in vkparse (difference is the lack of
support for plists). Having this will make supporting named flags in
cvars much easier (though setting up the enum type is a bit of a chore).
This commit is contained in:
Bill Currie 2022-04-24 15:12:56 +09:00
parent 392e032ce2
commit d68db74049
2 changed files with 53 additions and 0 deletions

View file

@ -117,6 +117,7 @@ binop_t *cexpr_find_cast (exprtype_t *dst_type, exprtype_t *src_type) __attribut
exprval_t *cexpr_value (exprtype_t *type, exprctx_t *ctx);
exprval_t *cexpr_value_reference (exprtype_t *type, void *data, exprctx_t *ctx);
const char *cexpr_enum_get_string (const exprval_t *val, struct va_ctx_s *va_ctx) __attribute__((pure));
const char *cexpr_flags_get_string (const exprval_t *val, struct va_ctx_s *va_ctx) __attribute__((pure));
int cexpr_eval_string (const char *str, exprctx_t *context);
void cexpr_error(exprctx_t *ctx, const char *fmt, ...) __attribute__((format(PRINTF,2,3)));
@ -151,6 +152,8 @@ extern exprtype_t cexpr_plitem;
extern binop_t cexpr_array_binops[];
extern binop_t cexpr_struct_binops[];
extern binop_t cexpr_struct_pointer_binops[];
extern binop_t cexpr_flag_binops[];
extern unop_t cexpr_flag_unops[];
extern exprsym_t cexpr_lib_symbols[];

View file

@ -815,3 +815,53 @@ cexpr_enum_get_string (const exprval_t *val, va_ctx_t *va_ctx)
}
return "";
}
BINOP(flag, and, int, &)
BINOP(flag, or, int, |)
BINOP(flag, xor, int, ^)
UNOP(flag, not, int, ~)
binop_t cexpr_flag_binops[] = {
{ '&', 0, 0, flag_and },
{ '|', 0, 0, flag_or },
{ '^', 0, 0, flag_xor },
{ '=', &cexpr_int, 0, uint_cast_int },
{}
};
unop_t cexpr_flag_unops[] = {
{ '~', 0, flag_not },
{}
};
VISIBLE const char *
cexpr_flags_get_string (const exprval_t *val, va_ctx_t *va_ctx)
{
exprenum_t *enm = val->type->data;
exprsym_t *symbols = enm->symtab->symbols;
const char *val_str = 0;
if (val->type->size != 4) {
Sys_Error ("cexpr_flags_get_string: only 32-bit values supported");
}
uint32_t flags = *(uint32_t *) val->value;
for (exprsym_t *sym = symbols; sym->name; sym++) {
uint32_t sym_flags = *(uint32_t *) sym->value;
// if there are duplicate values, choose the *later* value
if (sym[1].name && sym_flags == *(uint32_t *) sym[1].value) {
continue;
}
if ((flags & sym_flags) && !(sym_flags & ~flags)) {
if (val_str) {
val_str = va (va_ctx, "%s | %s", val_str, sym->name);
} else {
val_str = sym->name;
}
}
}
if (!val_str) {
val_str = "0";
}
return val_str;
}