This commit is contained in:
Meredith L. Patterson 2012-05-11 23:42:21 +01:00
commit 7469d09a68
4 changed files with 36 additions and 9 deletions

View file

@ -14,7 +14,7 @@ all: libhammer.a test_suite
test_suite: test_suite.o libhammer.a test_suite: test_suite.o libhammer.a
$(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS) $(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS)
libhammer.a: bitreader.o hammer.o libhammer.a: bitreader.o hammer.o pprint.o
bitreader.o: test_suite.h bitreader.o: test_suite.h
hammer.o: hammer.h hammer.o: hammer.h

View file

@ -13,14 +13,37 @@ long long read_bits(input_stream_t* state, int count, char signed_p) {
// BUG: Does not // BUG: Does not
long long out = 0; long long out = 0;
int offset = 0; int offset = 0;
int final_shift = 0;
long long msb = (!!signed_p) << (count - 1); // 0 if unsigned, else 1 << (nbits - 1) long long msb = (!!signed_p) << (count - 1); // 0 if unsigned, else 1 << (nbits - 1)
// BUG: does not stop early in case of
// overflow check...
int bits_left = (state->length - state->index); // well, bytes for now
if (bits_left <= 64) { // Large enough to handle any valid count, but small enough that overflow isn't a problem.
// not in danger of overflowing, so add in bits
// add in number of bits...
if (state->endianness & BIT_BIG_ENDIAN)
bits_left = (bits_left << 3) - 8 + state->bit_offset;
else
bits_left = (bits_left << 3) - state->bit_offset;
if (bits_left < count) {
if (state->endianness & BYTE_BIG_ENDIAN)
final_shift = count - bits_left;
else
final_shift = 0;
count = bits_left;
state->overrun = true;
} else
final_shift = 0;
}
if ((state->bit_offset & 0x7) == 0 && (count & 0x7) == 0) { if ((state->bit_offset & 0x7) == 0 && (count & 0x7) == 0) {
// fast path // fast path
if (state->endianness & BYTE_BIG_ENDIAN) { if (state->endianness & BYTE_BIG_ENDIAN) {
while (count > 0) while (count > 0) {
count -= 8;
out = (out << 8) | state->input[state->index++]; out = (out << 8) | state->input[state->index++];
}
} else { } else {
while (count > 0) { while (count > 0) {
count -= 8; count -= 8;
@ -65,6 +88,7 @@ long long read_bits(input_stream_t* state, int count, char signed_p) {
count -= segment_len; count -= segment_len;
} }
} }
out <<= final_shift;
return (out ^ msb) - msb; // perform sign extension return (out ^ msb) - msb; // perform sign extension
} }

View file

@ -72,6 +72,8 @@ parse_result_t* do_parse(const parser_t* parser, parse_state_t *state) {
// It doesn't exist... run the // It doesn't exist... run the
parse_result_t *res; parse_result_t *res;
res = parser->fn(parser->env, state); res = parser->fn(parser->env, state);
if (state->input_stream.overrun)
res = NULL; // overrun is always failure.
// update the cache // update the cache
g_hash_table_replace(state->cache, &key, res); g_hash_table_replace(state->cache, &key, res);
#ifdef CONSISTENCY_CHECK #ifdef CONSISTENCY_CHECK
@ -166,7 +168,7 @@ const parser_t* range(const uint8_t lower, const uint8_t upper) {
return (const parser_t*)ret; return (const parser_t*)ret;
} }
const parser_t* notin(const uint8_t *options, int count) { const parser_t* not_in(const uint8_t *options, int count) {
parser_t *ret = g_new(parser_t, 1); parser_t *ret = g_new(parser_t, 1);
charset cs = new_charset(); charset cs = new_charset();
for (int i = 0; i < 256; i++) for (int i = 0; i < 256; i++)
@ -604,11 +606,11 @@ static void test_left_factor_action(void) {
} }
static void test_notin(void) { static void test_not_in(void) {
uint8_t options[3] = { 'a', 'b', 'c' }; uint8_t options[3] = { 'a', 'b', 'c' };
uint8_t test1[1] = { 'd' }; uint8_t test1[1] = { 'd' };
uint8_t test2[1] = { 'a' }; uint8_t test2[1] = { 'a' };
const parser_t *notin_ = notin(options, 3); const parser_t *not_in_ = not_in(options, 3);
parse_result_t *ret1 = parse(notin_, test1, 1); parse_result_t *ret1 = parse(notin_, test1, 1);
parse_result_t *ret2 = parse(notin_, test2, 1); parse_result_t *ret2 = parse(notin_, test2, 1);
g_check_cmpint(ret1->ast->uint, ==, 'd'); g_check_cmpint(ret1->ast->uint, ==, 'd');
@ -738,7 +740,7 @@ void register_parser_tests(void) {
g_test_add_func("/core/parser/whitespace", test_whitespace); g_test_add_func("/core/parser/whitespace", test_whitespace);
g_test_add_func("/core/parser/action", test_action); g_test_add_func("/core/parser/action", test_action);
g_test_add_func("/core/parser/left_factor_action", test_left_factor_action); g_test_add_func("/core/parser/left_factor_action", test_left_factor_action);
g_test_add_func("/core/parser/notin", test_notin); g_test_add_func("/core/parser/not_in", test_not_in);
g_test_add_func("/core/parser/end_p", test_end_p); g_test_add_func("/core/parser/end_p", test_end_p);
g_test_add_func("/core/parser/nothing_p", test_nothing_p); g_test_add_func("/core/parser/nothing_p", test_nothing_p);
g_test_add_func("/core/parser/sequence", test_sequence); g_test_add_func("/core/parser/sequence", test_sequence);

View file

@ -42,6 +42,7 @@ typedef struct input_stream {
size_t length; size_t length;
char bit_offset; char bit_offset;
char endianness; char endianness;
char overrun;
} input_stream_t; } input_stream_t;
typedef struct parse_state { typedef struct parse_state {
@ -138,7 +139,7 @@ const parser_t* whitespace(const parser_t* p);
const parser_t* left_factor_action(const parser_t* p); const parser_t* left_factor_action(const parser_t* p);
/* Parse a single character *NOT* in charset */ /* Parse a single character *NOT* in charset */
const parser_t* notin(const uint8_t *options, int count); const parser_t* not_in(const uint8_t *charset, int length);
/* A no-argument parser that succeeds if there is no more input to parse. */ /* A no-argument parser that succeeds if there is no more input to parse. */
const parser_t* end_p(); const parser_t* end_p();