reshape bits parsers

This commit is contained in:
Sven M. Hallberg 2013-05-14 17:20:05 +02:00
parent c794be5b6f
commit d081cf4284
3 changed files with 58 additions and 2 deletions

View file

@ -19,8 +19,8 @@ typedef struct HCFGrammar_ {
* therefore we must avoid 0 as a token value because NULL means "not in set". * therefore we must avoid 0 as a token value because NULL means "not in set".
*/ */
typedef uintptr_t HCFToken; typedef uintptr_t HCFToken;
static inline HCFToken char_token(char c) { return (0x100 | c); } static inline HCFToken char_token(uint8_t c) { return (0x100 | c); }
static inline char token_char(HCFToken t) { return (0xFF & t); } static inline uint8_t token_char(HCFToken t) { return (0xFF & t); }
static const HCFToken end_token = 0x200; static const HCFToken end_token = 0x200;

View file

@ -17,6 +17,41 @@ static HParseResult* parse_bits(void* env, HParseState *state) {
return make_result(state->arena, result); return make_result(state->arena, result);
} }
static HParsedToken *reshape_bits(const HParseResult *p, bool signedp) {
// XXX works only for whole bytes
// XXX assumes big-endian
assert(p->ast);
assert(p->ast->token_type == TT_SEQUENCE);
HCountedArray *seq = p->ast->seq;
HParsedToken *ret = h_arena_malloc(p->arena, sizeof(HParsedToken));
ret->token_type = TT_UINT;
if(signedp && (seq->elements[0]->uint & 128))
ret->uint = -1; // all ones
for(size_t i=0; i<seq->used; i++) {
HParsedToken *t = seq->elements[i];
assert(t->token_type == TT_UINT);
ret->uint <<= 8;
ret->uint |= t->uint & 0xFF;
}
if(signedp) {
ret->token_type = TT_SINT;
ret->sint = ret->uint;
}
return ret;
}
static const HParsedToken *reshape_bits_unsigned(const HParseResult *p) {
return reshape_bits(p, false);
}
static const HParsedToken *reshape_bits_signed(const HParseResult *p) {
return reshape_bits(p, true);
}
static HCFChoice* desugar_bits(HAllocator *mm__, void *env) { static HCFChoice* desugar_bits(HAllocator *mm__, void *env) {
struct bits_env *bits = (struct bits_env*)env; struct bits_env *bits = (struct bits_env*)env;
if (0 != bits->length % 8) if (0 != bits->length % 8)
@ -46,6 +81,11 @@ static HCFChoice* desugar_bits(HAllocator *mm__, void *env) {
ret->seq[1] = NULL; ret->seq[1] = NULL;
ret->action = NULL; ret->action = NULL;
if(bits->signedp)
ret->reshape = reshape_bits_signed;
else
ret->reshape = reshape_bits_unsigned;
return ret; return ret;
} }

View file

@ -41,6 +41,13 @@ static void test_int32(void) {
g_check_parse_failed(int32_, "\xff\xfe\x00", 3); g_check_parse_failed(int32_, "\xff\xfe\x00", 3);
} }
static void test_int32_pos(void) {
const HParser *int32_ = h_int32();
g_check_parse_ok(int32_, "\x00\x02\x00\x00", 4, "s0x20000");
g_check_parse_failed(int32_, "\x00\x02\x00", 3);
}
static void test_int16(void) { static void test_int16(void) {
const HParser *int16_ = h_int16(); const HParser *int16_ = h_int16();
@ -48,6 +55,13 @@ static void test_int16(void) {
g_check_parse_failed(int16_, "\xfe", 1); g_check_parse_failed(int16_, "\xfe", 1);
} }
static void test_int16_pos(void) {
const HParser *int16_ = h_int16();
g_check_parse_ok(int16_, "\x02\x00", 2, "s0x200");
g_check_parse_failed(int16_, "\x02", 1);
}
static void test_int8(void) { static void test_int8(void) {
const HParser *int8_ = h_int8(); const HParser *int8_ = h_int8();
@ -395,7 +409,9 @@ void register_parser_tests(void) {
g_test_add_func("/core/parser/ch_range", test_ch_range); g_test_add_func("/core/parser/ch_range", test_ch_range);
g_test_add_func("/core/parser/int64", test_int64); g_test_add_func("/core/parser/int64", test_int64);
g_test_add_func("/core/parser/int32", test_int32); g_test_add_func("/core/parser/int32", test_int32);
g_test_add_func("/core/parser/int32_pos", test_int32_pos);
g_test_add_func("/core/parser/int16", test_int16); g_test_add_func("/core/parser/int16", test_int16);
g_test_add_func("/core/parser/int16_pos", test_int16_pos);
g_test_add_func("/core/parser/int8", test_int8); g_test_add_func("/core/parser/int8", test_int8);
g_test_add_func("/core/parser/uint64", test_uint64); g_test_add_func("/core/parser/uint64", test_uint64);
g_test_add_func("/core/parser/uint32", test_uint32); g_test_add_func("/core/parser/uint32", test_uint32);