From 6a2f10df0c3abcb6daaa7b0aa5ffe135555c0ee7 Mon Sep 17 00:00:00 2001 From: Dan Hirsch <thequux@thequux.com> Date: Sat, 26 May 2012 15:15:38 +0200 Subject: [PATCH] Changed parsers to use vtables instead of just a function pointer --- src/hammer.c | 169 ++++++++++++++++++++++++++++++++++++++++----------- src/hammer.h | 6 +- 2 files changed, 139 insertions(+), 36 deletions(-) diff --git a/src/hammer.c b/src/hammer.c index 34f413f8..9ee458ba 100644 --- a/src/hammer.c +++ b/src/hammer.c @@ -54,7 +54,7 @@ HParserCacheValue* recall(HParserCacheKey *k, HParseState *state) { if (g_slist_find(head->eval_set, k->parser)) { // Something is in the cache, and the key parser is in the eval set. Remove the key parser from the eval set of the head. head->eval_set = g_slist_remove_all(head->eval_set, k->parser); - HParseResult *tmp_res = k->parser->fn(k->parser->env, state); + HParseResult *tmp_res = k->parser->vtable->parse(k->parser->env, state); if (tmp_res) tmp_res->arena = state->arena; // we know that cached has an entry here, modify it @@ -100,7 +100,7 @@ HParseResult* grow(HParserCacheKey *k, HParseState *state, HRecursionHead *head) head->eval_set = head->involved_set; HParseResult *tmp_res; if (k->parser) { - tmp_res = k->parser->fn(k->parser->env, state); + tmp_res = k->parser->vtable->parse(k->parser->env, state); if (tmp_res) tmp_res->arena = state->arena; } else @@ -168,7 +168,7 @@ HParseResult* h_do_parse(const HParser* parser, HParseState *state) { HParseResult *tmp_res; if (parser) { HInputStream bak = state->input_stream; - tmp_res = parser->fn(parser->env, state); + tmp_res = parser->vtable->parse(parser->env, state); if (tmp_res) { tmp_res->arena = state->arena; if (!state->input_stream.overrun) { @@ -239,8 +239,11 @@ typedef struct { return &result; } +static const HParserVtable unimplemented_vt = { + .parse = parse_unimplemented, +}; static HParser unimplemented __attribute__((unused)) = { - .fn = parse_unimplemented, + .vtable = &unimplemented_vt, .env = NULL }; @@ -260,12 +263,15 @@ static HParseResult* parse_bits(void* env, HParseState *state) { return make_result(state, result); } +static const HParserVtable bits_vt = { + .parse = parse_bits, +}; const HParser* h_bits(size_t len, bool sign) { struct bits_env *env = g_new(struct bits_env, 1); env->length = len; env->signedp = sign; HParser *res = g_new(HParser, 1); - res->fn = parse_bits; + res->vtable = &bits_vt; res->env = env; return res; } @@ -296,11 +302,16 @@ static HParseResult* parse_token(void *env, HParseState *state) { return make_result(state, tok); } +const const HParserVtable token_vt = { + .parse = parse_token, +}; + const HParser* h_token(const uint8_t *str, const size_t len) { HToken *t = g_new(HToken, 1); t->str = (uint8_t*)str, t->len = len; HParser *ret = g_new(HParser, 1); - ret->fn = parse_token; ret->env = t; + ret->vtable = &token_vt; + ret->env = t; return (const HParser*)ret; } @@ -316,9 +327,13 @@ static HParseResult* parse_ch(void* env, HParseState *state) { } } +static const HParserVtable ch_vt = { + .parse = parse_ch, +}; const HParser* h_ch(const uint8_t c) { HParser *ret = g_new(HParser, 1); - ret->fn = parse_ch; ret->env = GUINT_TO_POINTER(c); + ret->vtable = &ch_vt; + ret->env = GUINT_TO_POINTER(c); return (const HParser*)ret; } @@ -335,9 +350,13 @@ static HParseResult* parse_whitespace(void* env, HParseState *state) { return h_do_parse((HParser*)env, state); } +static const HParserVtable whitespace_vt = { + .parse = parse_whitespace, +}; + const HParser* h_whitespace(const HParser* p) { HParser *ret = g_new(HParser, 1); - ret->fn = parse_whitespace; + ret->vtable = &whitespace_vt; ret->env = (void*)p; return ret; } @@ -358,9 +377,13 @@ static HParseResult* parse_action(void *env, HParseState *state) { return NULL; } +static const HParserVtable action_vt = { + .parse = parse_action, +}; + const HParser* h_action(const HParser* p, const HAction a) { HParser *res = g_new(HParser, 1); - res->fn = parse_action; + res->vtable = &action_vt; HParseAction *env = g_new(HParseAction, 1); env->p = p; env->action = a; @@ -380,12 +403,17 @@ static HParseResult* parse_charset(void *env, HParseState *state) { return NULL; } +static const HParserVtable charset_vt = { + .parse = parse_charset, +}; + const HParser* h_ch_range(const uint8_t lower, const uint8_t upper) { HParser *ret = g_new(HParser, 1); HCharset cs = new_charset(); for (int i = 0; i < 256; i++) charset_set(cs, i, (lower <= i) && (i <= upper)); - ret->fn = parse_charset; ret->env = (void*)cs; + ret->vtable = &charset_vt; + ret->env = (void*)cs; return (const HParser*)ret; } @@ -416,10 +444,14 @@ static HParseResult* parse_int_range(void *env, HParseState *state) { } } +static const HParserVtable int_range_vt = { + .parse = parse_int_range, +}; + const HParser* h_int_range(const HParser *p, const int64_t lower, const int64_t upper) { struct bits_env *b_env = p->env; // p must be an integer parser, which means it's using parse_bits - assert_message(p->fn == parse_bits, "int_range requires an integer parser"); + assert_message(p->vtable == &bits_vt, "int_range requires an integer parser"); // if it's a uint parser, it can't be uint64 assert_message(!(b_env->signedp) ? (b_env->length < 64) : true, "int_range can't use a uint64 parser"); // and regardless, the bounds need to fit in the parser in question @@ -452,7 +484,7 @@ const HParser* h_int_range(const HParser *p, const int64_t lower, const int64_t r_env->lower = lower; r_env->upper = upper; HParser *ret = g_new(HParser, 1); - ret->fn = parse_int_range; + ret->vtable = &int_range_vt; ret->env = (void*)r_env; return ret; } @@ -465,7 +497,8 @@ const HParser* h_not_in(const uint8_t *options, int count) { for (int i = 0; i < count; i++) charset_set(cs, options[i], 0); - ret->fn = parse_charset; ret->env = (void*)cs; + ret->vtable = &charset_vt; + ret->env = (void*)cs; return (const HParser*)ret; } @@ -479,9 +512,13 @@ static HParseResult* parse_end(void *env, HParseState *state) { } } +static const HParserVtable end_vt = { + .parse = parse_end, +}; + const HParser* h_end_p() { HParser *ret = g_new(HParser, 1); - ret->fn = parse_end; ret->env = NULL; + ret->vtable = &end_vt; ret->env = NULL; return (const HParser*)ret; } @@ -490,9 +527,13 @@ static HParseResult* parse_nothing() { return NULL; } +static const HParserVtable nothing_vt = { + .parse = parse_nothing, +}; + const HParser* h_nothing_p() { HParser *ret = g_new(HParser, 1); - ret->fn = parse_nothing; ret->env = NULL; + ret->vtable = ¬hing_vt; ret->env = NULL; return (const HParser*)ret; } @@ -519,6 +560,10 @@ static HParseResult* parse_sequence(void *env, HParseState *state) { return make_result(state, tok); } +static const HParserVtable sequence_vt = { + .parse = parse_sequence, +}; + const HParser* h_sequence(const HParser *p, ...) { va_list ap; size_t len = 0; @@ -541,7 +586,7 @@ const HParser* h_sequence(const HParser *p, ...) { s->len = len; HParser *ret = g_new(HParser, 1); - ret->fn = parse_sequence; ret->env = (void*)s; + ret->vtable = &sequence_vt; ret->env = (void*)s; return ret; } @@ -559,6 +604,10 @@ static HParseResult* parse_choice(void *env, HParseState *state) { return NULL; } +static const HParserVtable choice_vt = { + .parse = parse_choice, +}; + const HParser* h_choice(const HParser* p, ...) { va_list ap; size_t len = 0; @@ -582,7 +631,7 @@ const HParser* h_choice(const HParser* p, ...) { s->len = len; HParser *ret = g_new(HParser, 1); - ret->fn = parse_choice; ret->env = (void*)s; + ret->vtable = &choice_vt; ret->env = (void*)s; return ret; } @@ -629,11 +678,15 @@ static HParseResult* parse_butnot(void *env, HParseState *state) { } } +static const HParserVtable butnot_vt = { + .parse = parse_butnot, +}; + const HParser* h_butnot(const HParser* p1, const HParser* p2) { HTwoParsers *env = g_new(HTwoParsers, 1); env->p1 = p1; env->p2 = p2; HParser *ret = g_new(HParser, 1); - ret->fn = parse_butnot; ret->env = (void*)env; + ret->vtable = &butnot_vt; ret->env = (void*)env; return ret; } @@ -666,11 +719,15 @@ static HParseResult* parse_difference(void *env, HParseState *state) { } } +static HParserVtable difference_vt = { + .parse = parse_difference, +}; + const HParser* h_difference(const HParser* p1, const HParser* p2) { HTwoParsers *env = g_new(HTwoParsers, 1); env->p1 = p1; env->p2 = p2; HParser *ret = g_new(HParser, 1); - ret->fn = parse_difference; ret->env = (void*)env; + ret->vtable = &difference_vt; ret->env = (void*)env; return ret; } @@ -699,11 +756,15 @@ static HParseResult* parse_xor(void *env, HParseState *state) { } } +static const HParserVtable xor_vt = { + .parse = parse_xor, +}; + const HParser* h_xor(const HParser* p1, const HParser* p2) { HTwoParsers *env = g_new(HTwoParsers, 1); env->p1 = p1; env->p2 = p2; HParser *ret = g_new(HParser, 1); - ret->fn = parse_xor; ret->env = (void*)env; + ret->vtable = &xor_vt; ret->env = (void*)env; return ret; } @@ -750,6 +811,10 @@ static HParseResult *parse_many(void* env, HParseState *state) { return NULL; } +static const HParserVtable many_vt = { + .parse = parse_many, +}; + const HParser* h_many(const HParser* p) { HParser *res = g_new(HParser, 1); HRepeat *env = g_new(HRepeat, 1); @@ -757,7 +822,7 @@ const HParser* h_many(const HParser* p) { env->sep = h_epsilon_p(); env->count = 0; env->min_p = true; - res->fn = parse_many; + res->vtable = &many_vt; res->env = env; return res; } @@ -769,7 +834,7 @@ const HParser* h_many1(const HParser* p) { env->sep = h_epsilon_p(); env->count = 1; env->min_p = true; - res->fn = parse_many; + res->vtable = &many_vt; res->env = env; return res; } @@ -781,7 +846,7 @@ const HParser* h_repeat_n(const HParser* p, const size_t n) { env->sep = h_epsilon_p(); env->count = n; env->min_p = false; - res->fn = parse_many; + res->vtable = &many_vt; res->env = env; return res; } @@ -795,9 +860,14 @@ static HParseResult* parse_ignore(void* env, HParseState* state) { res->arena = state->arena; return res; } + +static const HParserVtable ignore_vt = { + .parse = parse_ignore, +}; + const HParser* h_ignore(const HParser* p) { HParser* ret = g_new(HParser, 1); - ret->fn = parse_ignore; + ret->vtable = &ignore_vt; ret->env = (void*)p; return ret; } @@ -813,10 +883,14 @@ static HParseResult* parse_optional(void* env, HParseState* state) { return make_result(state, ast); } +static const HParserVtable optional_vt = { + .parse = parse_optional, +}; + const HParser* h_optional(const HParser* p) { - assert_message(p->fn != parse_ignore, "Thou shalt ignore an option, rather than the other way 'round."); + assert_message(p->vtable != &ignore_vt, "Thou shalt ignore an option, rather than the other way 'round."); HParser *ret = g_new(HParser, 1); - ret->fn = parse_optional; + ret->vtable = &optional_vt; ret->env = (void*)p; return ret; } @@ -828,7 +902,7 @@ const HParser* h_sepBy(const HParser* p, const HParser* sep) { env->sep = sep; env->count = 0; env->min_p = true; - res->fn = parse_many; + res->vtable = &many_vt; res->env = env; return res; } @@ -840,7 +914,7 @@ const HParser* h_sepBy1(const HParser* p, const HParser* sep) { env->sep = sep; env->count = 1; env->min_p = true; - res->fn = parse_many; + res->vtable = &many_vt; res->env = env; return res; } @@ -853,9 +927,13 @@ static HParseResult* parse_epsilon(void* env, HParseState* state) { return res; } +static const HParserVtable epsilon_vt = { + .parse = parse_epsilon, +}; + const HParser* h_epsilon_p() { HParser *res = g_new(HParser, 1); - res->fn = parse_epsilon; + res->vtable = &epsilon_vt; res->env = NULL; return res; } @@ -863,13 +941,18 @@ const HParser* h_epsilon_p() { static HParseResult* parse_indirect(void* env, HParseState* state) { return h_do_parse(env, state); } +static const HParserVtable indirect_vt = { + .parse = parse_indirect, +}; + void h_bind_indirect(HParser* indirect, HParser* inner) { + assert_message(indirect->vtable == &indirect_vt, "You can only bind an indirect parser"); indirect->env = inner; } HParser* h_indirect() { HParser *res = g_new(HParser, 1); - res->fn = parse_indirect; + res->vtable = &indirect_vt; res->env = NULL; return res; } @@ -891,9 +974,13 @@ static HParseResult* parse_attr_bool(void *env, HParseState *state) { return NULL; } +static const HParserVtable attr_bool_vt = { + .parse = parse_attr_bool, +}; + const HParser* h_attr_bool(const HParser* p, HPredicate pred) { HParser *res = g_new(HParser, 1); - res->fn = parse_attr_bool; + res->vtable = &attr_bool_vt; HAttrBool *env = g_new(HAttrBool, 1); env->p = p; env->pred = pred; @@ -914,7 +1001,7 @@ static HParseResult* parse_length_value(void *env, HParseState *state) { if (len->ast->token_type != TT_UINT) errx(1, "Length parser must return an unsigned integer"); HParser epsilon_local = { - .fn = parse_epsilon, + .vtable = &epsilon_vt, .env = NULL }; HRepeat repeat = { @@ -926,9 +1013,13 @@ static HParseResult* parse_length_value(void *env, HParseState *state) { return parse_many(&repeat, state); } +static const HParserVtable length_value_vt = { + .parse = parse_length_value, +}; + const HParser* h_length_value(const HParser* length, const HParser* value) { HParser *res = g_new(HParser, 1); - res->fn = parse_length_value; + res->vtable = &length_value_vt; HLenVal *env = g_new(HLenVal, 1); env->length = length; env->value = value; @@ -945,11 +1036,15 @@ static HParseResult *parse_and(void* env, HParseState* state) { return NULL; } +static const HParserVtable and_vt = { + .parse = parse_and, +}; + const HParser* h_and(const HParser* p) { // zero-width postive lookahead HParser *res = g_new(HParser, 1); res->env = (void*)p; - res->fn = parse_and; + res->vtable = &and_vt; return res; } @@ -963,9 +1058,13 @@ static HParseResult* parse_not(void* env, HParseState* state) { } } +static const HParserVtable not_vt = { + .parse = parse_not, +}; + const HParser* h_not(const HParser* p) { HParser *res = g_new(HParser, 1); - res->fn = parse_not; + res->vtable = ¬_vt; res->env = (void*)p; return res; } diff --git a/src/hammer.h b/src/hammer.h index af9db6e3..95da0eed 100644 --- a/src/hammer.h +++ b/src/hammer.h @@ -98,8 +98,12 @@ typedef const HParsedToken* (*HAction)(const HParseResult *p); */ typedef bool (*HPredicate)(HParseResult *p); +typedef struct HParserVtable_ { + HParseResult* (*parse)(void *env, HParseState *state); +} HParserVtable; + typedef struct HParser_ { - HParseResult* (*fn)(void *env, HParseState *state); + const HParserVtable *vtable; void *env; } HParser; -- GitLab