From 6a2f10df0c3abcb6daaa7b0aa5ffe135555c0ee7 Mon Sep 17 00:00:00 2001 From: Dan Hirsch Date: Sat, 26 May 2012 15:15:38 +0200 Subject: [PATCH 1/4] 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 34f413f..9ee458b 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 af9db6e..95da0ee 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; From f2def8fa05a0c6a2b21a840e80e7852798d69d30 Mon Sep 17 00:00:00 2001 From: Dan Hirsch Date: Sat, 26 May 2012 16:00:43 +0200 Subject: [PATCH 2/4] Refactor ALL the things! --- src/Makefile | 27 +- src/hammer.c | 858 +--------------------------------- src/internal.h | 1 + src/parsers/action.c | 31 ++ src/parsers/and.c | 22 + src/parsers/attr_bool.c | 32 ++ src/parsers/bits.c | 43 ++ src/parsers/butnot.c | 49 ++ src/parsers/ch.c | 23 + src/parsers/charset.c | 43 ++ src/parsers/choice.c | 53 +++ src/parsers/difference.c | 47 ++ src/parsers/end.c | 21 + src/parsers/epsilon.c | 20 + src/parsers/ignore.c | 22 + src/parsers/indirect.c | 20 + src/parsers/int_range.c | 51 ++ src/parsers/many.c | 145 ++++++ src/parsers/not.c | 22 + src/parsers/nothing.c | 17 + src/parsers/optional.c | 26 ++ src/parsers/parser_internal.h | 27 ++ src/parsers/sequence.c | 54 +++ src/parsers/template.c | 1 + src/parsers/token.c | 34 ++ src/parsers/unimplemented.c | 26 ++ src/parsers/whitespace.c | 26 ++ src/parsers/xor.c | 44 ++ 28 files changed, 930 insertions(+), 855 deletions(-) create mode 100644 src/parsers/action.c create mode 100644 src/parsers/and.c create mode 100644 src/parsers/attr_bool.c create mode 100644 src/parsers/bits.c create mode 100644 src/parsers/butnot.c create mode 100644 src/parsers/ch.c create mode 100644 src/parsers/charset.c create mode 100644 src/parsers/choice.c create mode 100644 src/parsers/difference.c create mode 100644 src/parsers/end.c create mode 100644 src/parsers/epsilon.c create mode 100644 src/parsers/ignore.c create mode 100644 src/parsers/indirect.c create mode 100644 src/parsers/int_range.c create mode 100644 src/parsers/many.c create mode 100644 src/parsers/not.c create mode 100644 src/parsers/nothing.c create mode 100644 src/parsers/optional.c create mode 100644 src/parsers/parser_internal.h create mode 100644 src/parsers/sequence.c create mode 100644 src/parsers/template.c create mode 100644 src/parsers/token.c create mode 100644 src/parsers/unimplemented.c create mode 100644 src/parsers/whitespace.c create mode 100644 src/parsers/xor.c diff --git a/src/Makefile b/src/Makefile index d362118..7f08439 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,11 +1,35 @@ +PARSERS := \ + unimplemented \ + bits \ + token \ + whitespace \ + ch \ + action \ + charset \ + int_range \ + sequence \ + choice \ + nothing \ + end \ + butnot \ + difference \ + many \ + xor \ + optional \ + ignore \ + epsilon \ + and \ + not + OUTPUTS := bitreader.o \ hammer.o \ libhammer.a \ pprint.o \ allocator.o \ datastructures.o \ - test_suite + test_suite \ + $(PARSERS:%=parsers/%.o) TOPLEVEL := ../ @@ -18,6 +42,7 @@ test_suite: test_suite.o libhammer.a $(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS) libhammer.a: bitreader.o hammer.o pprint.o allocator.o datastructures.o +libhammer.a: $(PARSERS:%=parsers/%.o) bitreader.o: test_suite.h hammer.o: hammer.h diff --git a/src/hammer.c b/src/hammer.c index 9ee458b..2e041da 100644 --- a/src/hammer.c +++ b/src/hammer.c @@ -15,19 +15,16 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "hammer.h" -#include "internal.h" -#include "allocator.h" #include #include #include #include #include #include - -#define a_new_(arena, typ, count) ((typ*)h_arena_malloc((arena), sizeof(typ)*(count))) -#define a_new(typ, count) a_new_(state->arena, typ, count) -// we can create a_new0 if necessary. It would allocate some memory and immediately zero it out. +#include "hammer.h" +#include "internal.h" +#include "allocator.h" +#include "parsers/parser_internal.h" static guint djbhash(const uint8_t *buf, size_t len) { guint hash = 5381; @@ -215,859 +212,12 @@ HParseResult* h_do_parse(const HParser* parser, HParseState *state) { } /* Helper function, since these lines appear in every parser */ -static HParseResult* make_result(HParseState *state, HParsedToken *tok) { - HParseResult *ret = a_new(HParseResult, 1); - ret->ast = tok; - ret->arena = state->arena; - return ret; -} - -typedef struct { - uint8_t *str; - uint8_t len; -} HToken; - - static HParseResult* parse_unimplemented(void* env, HParseState *state) { - (void) env; - (void) state; - static HParsedToken token = { - .token_type = TT_ERR - }; - static HParseResult result = { - .ast = &token - }; - return &result; -} - -static const HParserVtable unimplemented_vt = { - .parse = parse_unimplemented, -}; -static HParser unimplemented __attribute__((unused)) = { - .vtable = &unimplemented_vt, - .env = NULL -}; - -struct bits_env { - uint8_t length; - uint8_t signedp; -}; - -static HParseResult* parse_bits(void* env, HParseState *state) { - struct bits_env *env_ = env; - HParsedToken *result = a_new(HParsedToken, 1); - result->token_type = (env_->signedp ? TT_SINT : TT_UINT); - if (env_->signedp) - result->sint = h_read_bits(&state->input_stream, env_->length, true); - else - result->uint = h_read_bits(&state->input_stream, env_->length, false); - 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->vtable = &bits_vt; - res->env = env; - return res; -} - -#define SIZED_BITS(name_pre, len, signedp) \ - const HParser* h_##name_pre##len () { \ - return h_bits(len, signedp); \ - } -SIZED_BITS(int, 8, true) -SIZED_BITS(int, 16, true) -SIZED_BITS(int, 32, true) -SIZED_BITS(int, 64, true) -SIZED_BITS(uint, 8, false) -SIZED_BITS(uint, 16, false) -SIZED_BITS(uint, 32, false) -SIZED_BITS(uint, 64, false) - -static HParseResult* parse_token(void *env, HParseState *state) { - HToken *t = (HToken*)env; - for (int i=0; ilen; ++i) { - uint8_t chr = (uint8_t)h_read_bits(&state->input_stream, 8, false); - if (t->str[i] != chr) { - return NULL; - } - } - HParsedToken *tok = a_new(HParsedToken, 1); - tok->token_type = TT_BYTES; tok->bytes.token = t->str; tok->bytes.len = t->len; - 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->vtable = &token_vt; - ret->env = t; - return (const HParser*)ret; -} - -static HParseResult* parse_ch(void* env, HParseState *state) { - uint8_t c = (uint8_t)GPOINTER_TO_UINT(env); - uint8_t r = (uint8_t)h_read_bits(&state->input_stream, 8, false); - if (c == r) { - HParsedToken *tok = a_new(HParsedToken, 1); - tok->token_type = TT_UINT; tok->uint = r; - return make_result(state, tok); - } else { - return NULL; - } -} - -static const HParserVtable ch_vt = { - .parse = parse_ch, -}; -const HParser* h_ch(const uint8_t c) { - HParser *ret = g_new(HParser, 1); - ret->vtable = &ch_vt; - ret->env = GUINT_TO_POINTER(c); - return (const HParser*)ret; -} - -static HParseResult* parse_whitespace(void* env, HParseState *state) { - char c; - HInputStream bak; - do { - bak = state->input_stream; - c = h_read_bits(&state->input_stream, 8, false); - if (state->input_stream.overrun) - return NULL; - } while (isspace(c)); - state->input_stream = bak; - 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->vtable = &whitespace_vt; - ret->env = (void*)p; - return ret; -} - -typedef struct { - const HParser *p; - HAction action; -} HParseAction; - -static HParseResult* parse_action(void *env, HParseState *state) { - HParseAction *a = (HParseAction*)env; - if (a->p && a->action) { - HParseResult *tmp = h_do_parse(a->p, state); - //HParsedToken *tok = a->action(h_do_parse(a->p, state)); - const HParsedToken *tok = a->action(tmp); - return make_result(state, (HParsedToken*)tok); - } else // either the parser's missing or the action's missing - 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->vtable = &action_vt; - HParseAction *env = g_new(HParseAction, 1); - env->p = p; - env->action = a; - res->env = (void*)env; - return res; -} - -static HParseResult* parse_charset(void *env, HParseState *state) { - uint8_t in = h_read_bits(&state->input_stream, 8, false); - HCharset cs = (HCharset)env; - - if (charset_isset(cs, in)) { - HParsedToken *tok = a_new(HParsedToken, 1); - tok->token_type = TT_UINT; tok->uint = in; - return make_result(state, tok); - } else - 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->vtable = &charset_vt; - ret->env = (void*)cs; - return (const HParser*)ret; -} - -typedef struct { - const HParser *p; - int64_t lower; - int64_t upper; -} HRange; - -static HParseResult* parse_int_range(void *env, HParseState *state) { - HRange *r_env = (HRange*)env; - HParseResult *ret = h_do_parse(r_env->p, state); - if (!ret || !ret->ast) - return NULL; - switch(ret->ast->token_type) { - case TT_SINT: - if (r_env->lower <= ret->ast->sint && r_env->upper >= ret->ast->sint) - return ret; - else - return NULL; - case TT_UINT: - if ((uint64_t)r_env->lower <= ret->ast->uint && (uint64_t)r_env->upper >= ret->ast->uint) - return ret; - else - return NULL; - default: - return NULL; - } -} - -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->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 - switch(b_env->length) { - case 32: - if (b_env->signedp) - assert_message(lower >= INT_MIN && upper <= INT_MAX, "bounds for 32-bit signed integer exceeded"); - else - assert_message(lower >= 0 && upper <= UINT_MAX, "bounds for 32-bit unsigned integer exceeded"); - break; - case 16: - if (b_env->signedp) - assert_message(lower >= SHRT_MIN && upper <= SHRT_MAX, "bounds for 16-bit signed integer exceeded"); - else - assert_message(lower >= 0 && upper <= USHRT_MAX, "bounds for 16-bit unsigned integer exceeded"); - break; - case 8: - if (b_env->signedp) - assert_message(lower >= SCHAR_MIN && upper <= SCHAR_MAX, "bounds for 8-bit signed integer exceeded"); - else - assert_message(lower >= 0 && upper <= UCHAR_MAX, "bounds for 8-bit unsigned integer exceeded"); - break; - default: - // how'd that happen? if we got here, this parser is broken. - return NULL; - } - - HRange *r_env = g_new(HRange, 1); - r_env->p = p; - r_env->lower = lower; - r_env->upper = upper; - HParser *ret = g_new(HParser, 1); - ret->vtable = &int_range_vt; - ret->env = (void*)r_env; - return ret; -} - -const HParser* h_not_in(const uint8_t *options, int count) { - HParser *ret = g_new(HParser, 1); - HCharset cs = new_charset(); - for (int i = 0; i < 256; i++) - charset_set(cs, i, 1); - for (int i = 0; i < count; i++) - charset_set(cs, options[i], 0); - - ret->vtable = &charset_vt; - ret->env = (void*)cs; - return (const HParser*)ret; -} - -static HParseResult* parse_end(void *env, HParseState *state) { - if (state->input_stream.index == state->input_stream.length) { - HParseResult *ret = a_new(HParseResult, 1); - ret->ast = NULL; - return ret; - } else { - return NULL; - } -} - -static const HParserVtable end_vt = { - .parse = parse_end, -}; - -const HParser* h_end_p() { - HParser *ret = g_new(HParser, 1); - ret->vtable = &end_vt; ret->env = NULL; - return (const HParser*)ret; -} - -static HParseResult* parse_nothing() { - // not a mistake, this parser always fails - return NULL; -} - -static const HParserVtable nothing_vt = { - .parse = parse_nothing, -}; - -const HParser* h_nothing_p() { - HParser *ret = g_new(HParser, 1); - ret->vtable = ¬hing_vt; ret->env = NULL; - return (const HParser*)ret; -} - -typedef struct { - size_t len; - const HParser **p_array; -} HSequence; - -static HParseResult* parse_sequence(void *env, HParseState *state) { - HSequence *s = (HSequence*)env; - HCountedArray *seq = h_carray_new_sized(state->arena, (s->len > 0) ? s->len : 4); - for (size_t i=0; ilen; ++i) { - HParseResult *tmp = h_do_parse(s->p_array[i], state); - // if the interim parse fails, the whole thing fails - if (NULL == tmp) { - return NULL; - } else { - if (tmp->ast) - h_carray_append(seq, (void*)tmp->ast); - } - } - HParsedToken *tok = a_new(HParsedToken, 1); - tok->token_type = TT_SEQUENCE; tok->seq = seq; - 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; - const HParser *arg; - va_start(ap, p); - do { - len++; - arg = va_arg(ap, const HParser *); - } while (arg); - va_end(ap); - HSequence *s = g_new(HSequence, 1); - s->p_array = g_new(const HParser *, len); - - va_start(ap, p); - s->p_array[0] = p; - for (size_t i = 1; i < len; i++) { - s->p_array[i] = va_arg(ap, const HParser *); - } while (arg); - va_end(ap); - - s->len = len; - HParser *ret = g_new(HParser, 1); - ret->vtable = &sequence_vt; ret->env = (void*)s; - return ret; -} - -static HParseResult* parse_choice(void *env, HParseState *state) { - HSequence *s = (HSequence*)env; - HInputStream backup = state->input_stream; - for (size_t i=0; ilen; ++i) { - if (i != 0) - state->input_stream = backup; - HParseResult *tmp = h_do_parse(s->p_array[i], state); - if (NULL != tmp) - return tmp; - } - // nothing succeeded, so fail - return NULL; -} - -static const HParserVtable choice_vt = { - .parse = parse_choice, -}; - -const HParser* h_choice(const HParser* p, ...) { - va_list ap; - size_t len = 0; - HSequence *s = g_new(HSequence, 1); - - const HParser *arg; - va_start(ap, p); - do { - len++; - arg = va_arg(ap, const HParser *); - } while (arg); - va_end(ap); - s->p_array = g_new(const HParser *, len); - - va_start(ap, p); - s->p_array[0] = p; - for (size_t i = 1; i < len; i++) { - s->p_array[i] = va_arg(ap, const HParser *); - } while (arg); - va_end(ap); - - s->len = len; - HParser *ret = g_new(HParser, 1); - ret->vtable = &choice_vt; ret->env = (void*)s; - return ret; -} typedef struct { const HParser *p1; const HParser *p2; } HTwoParsers; -// return token size in bits... -size_t token_length(HParseResult *pr) { - if (pr) { - return pr->bit_length; - } else { - return 0; - } -} - -static HParseResult* parse_butnot(void *env, HParseState *state) { - HTwoParsers *parsers = (HTwoParsers*)env; - // cache the initial state of the input stream - HInputStream start_state = state->input_stream; - HParseResult *r1 = h_do_parse(parsers->p1, state); - // if p1 failed, bail out early - if (NULL == r1) { - return NULL; - } - // cache the state after parse #1, since we might have to back up to it - HInputStream after_p1_state = state->input_stream; - state->input_stream = start_state; - HParseResult *r2 = h_do_parse(parsers->p2, state); - // TODO(mlp): I'm pretty sure the input stream state should be the post-p1 state in all cases - state->input_stream = after_p1_state; - // if p2 failed, restore post-p1 state and bail out early - if (NULL == r2) { - return r1; - } - size_t r1len = token_length(r1); - size_t r2len = token_length(r2); - // if both match but p1's text is shorter than than p2's (or the same length), fail - if (r1len <= r2len) { - return NULL; - } else { - return r1; - } -} - -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->vtable = &butnot_vt; ret->env = (void*)env; - return ret; -} - -static HParseResult* parse_difference(void *env, HParseState *state) { - HTwoParsers *parsers = (HTwoParsers*)env; - // cache the initial state of the input stream - HInputStream start_state = state->input_stream; - HParseResult *r1 = h_do_parse(parsers->p1, state); - // if p1 failed, bail out early - if (NULL == r1) { - return NULL; - } - // cache the state after parse #1, since we might have to back up to it - HInputStream after_p1_state = state->input_stream; - state->input_stream = start_state; - HParseResult *r2 = h_do_parse(parsers->p2, state); - // TODO(mlp): I'm pretty sure the input stream state should be the post-p1 state in all cases - state->input_stream = after_p1_state; - // if p2 failed, restore post-p1 state and bail out early - if (NULL == r2) { - return r1; - } - size_t r1len = token_length(r1); - size_t r2len = token_length(r2); - // if both match but p1's text is shorter than p2's, fail - if (r1len < r2len) { - return NULL; - } else { - return r1; - } -} - -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->vtable = &difference_vt; ret->env = (void*)env; - return ret; -} - -static HParseResult* parse_xor(void *env, HParseState *state) { - HTwoParsers *parsers = (HTwoParsers*)env; - // cache the initial state of the input stream - HInputStream start_state = state->input_stream; - HParseResult *r1 = h_do_parse(parsers->p1, state); - HInputStream after_p1_state = state->input_stream; - // reset input stream, parse again - state->input_stream = start_state; - HParseResult *r2 = h_do_parse(parsers->p2, state); - if (NULL == r1) { - if (NULL != r2) { - return r2; - } else { - return NULL; - } - } else { - if (NULL == r2) { - state->input_stream = after_p1_state; - return r1; - } else { - return NULL; - } - } -} - -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->vtable = &xor_vt; ret->env = (void*)env; - return ret; -} - -typedef struct { - const HParser *p, *sep; - size_t count; - bool min_p; -} HRepeat; - -static HParseResult *parse_many(void* env, HParseState *state) { - HRepeat *env_ = (HRepeat*) env; - HCountedArray *seq = h_carray_new_sized(state->arena, (env_->count > 0 ? env_->count : 4)); - size_t count = 0; - HInputStream bak; - while (env_->min_p || env_->count > count) { - bak = state->input_stream; - if (count > 0) { - HParseResult *sep = h_do_parse(env_->sep, state); - if (!sep) - goto err0; - } - HParseResult *elem = h_do_parse(env_->p, state); - if (!elem) - goto err0; - if (elem->ast) - h_carray_append(seq, (void*)elem->ast); - count++; - } - if (count < env_->count) - goto err; - succ: - ; // necessary for the label to be here... - HParsedToken *res = a_new(HParsedToken, 1); - res->token_type = TT_SEQUENCE; - res->seq = seq; - return make_result(state, res); - err0: - if (count >= env_->count) { - state->input_stream = bak; - goto succ; - } - err: - state->input_stream = bak; - 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); - env->p = p; - env->sep = h_epsilon_p(); - env->count = 0; - env->min_p = true; - res->vtable = &many_vt; - res->env = env; - return res; -} - -const HParser* h_many1(const HParser* p) { - HParser *res = g_new(HParser, 1); - HRepeat *env = g_new(HRepeat, 1); - env->p = p; - env->sep = h_epsilon_p(); - env->count = 1; - env->min_p = true; - res->vtable = &many_vt; - res->env = env; - return res; -} - -const HParser* h_repeat_n(const HParser* p, const size_t n) { - HParser *res = g_new(HParser, 1); - HRepeat *env = g_new(HRepeat, 1); - env->p = p; - env->sep = h_epsilon_p(); - env->count = n; - env->min_p = false; - res->vtable = &many_vt; - res->env = env; - return res; -} - -static HParseResult* parse_ignore(void* env, HParseState* state) { - HParseResult *res0 = h_do_parse((HParser*)env, state); - if (!res0) - return NULL; - HParseResult *res = a_new(HParseResult, 1); - res->ast = NULL; - 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->vtable = &ignore_vt; - ret->env = (void*)p; - return ret; -} - -static HParseResult* parse_optional(void* env, HParseState* state) { - HInputStream bak = state->input_stream; - HParseResult *res0 = h_do_parse((HParser*)env, state); - if (res0) - return res0; - state->input_stream = bak; - HParsedToken *ast = a_new(HParsedToken, 1); - ast->token_type = TT_NONE; - return make_result(state, ast); -} - -static const HParserVtable optional_vt = { - .parse = parse_optional, -}; - -const HParser* h_optional(const HParser* p) { - assert_message(p->vtable != &ignore_vt, "Thou shalt ignore an option, rather than the other way 'round."); - HParser *ret = g_new(HParser, 1); - ret->vtable = &optional_vt; - ret->env = (void*)p; - return ret; -} - -const HParser* h_sepBy(const HParser* p, const HParser* sep) { - HParser *res = g_new(HParser, 1); - HRepeat *env = g_new(HRepeat, 1); - env->p = p; - env->sep = sep; - env->count = 0; - env->min_p = true; - res->vtable = &many_vt; - res->env = env; - return res; -} - -const HParser* h_sepBy1(const HParser* p, const HParser* sep) { - HParser *res = g_new(HParser, 1); - HRepeat *env = g_new(HRepeat, 1); - env->p = p; - env->sep = sep; - env->count = 1; - env->min_p = true; - res->vtable = &many_vt; - res->env = env; - return res; -} - -static HParseResult* parse_epsilon(void* env, HParseState* state) { - (void)env; - HParseResult* res = a_new(HParseResult, 1); - res->ast = NULL; - res->arena = state->arena; - return res; -} - -static const HParserVtable epsilon_vt = { - .parse = parse_epsilon, -}; - -const HParser* h_epsilon_p() { - HParser *res = g_new(HParser, 1); - res->vtable = &epsilon_vt; - res->env = NULL; - return res; -} - -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->vtable = &indirect_vt; - res->env = NULL; - return res; -} - -typedef struct { - const HParser *p; - HPredicate pred; -} HAttrBool; - -static HParseResult* parse_attr_bool(void *env, HParseState *state) { - HAttrBool *a = (HAttrBool*)env; - HParseResult *res = h_do_parse(a->p, state); - if (res && res->ast) { - if (a->pred(res)) - return res; - else - return NULL; - } else - 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->vtable = &attr_bool_vt; - HAttrBool *env = g_new(HAttrBool, 1); - env->p = p; - env->pred = pred; - res->env = (void*)env; - return res; -} - -typedef struct { - const HParser *length; - const HParser *value; -} HLenVal; - -static HParseResult* parse_length_value(void *env, HParseState *state) { - HLenVal *lv = (HLenVal*)env; - HParseResult *len = h_do_parse(lv->length, state); - if (!len) - return NULL; - if (len->ast->token_type != TT_UINT) - errx(1, "Length parser must return an unsigned integer"); - HParser epsilon_local = { - .vtable = &epsilon_vt, - .env = NULL - }; - HRepeat repeat = { - .p = lv->value, - .sep = &epsilon_local, - .count = len->ast->uint, - .min_p = false - }; - 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->vtable = &length_value_vt; - HLenVal *env = g_new(HLenVal, 1); - env->length = length; - env->value = value; - res->env = (void*)env; - return res; -} - -static HParseResult *parse_and(void* env, HParseState* state) { - HInputStream bak = state->input_stream; - HParseResult *res = h_do_parse((HParser*)env, state); - state->input_stream = bak; - if (res) - return make_result(state, NULL); - 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->vtable = &and_vt; - return res; -} - -static HParseResult* parse_not(void* env, HParseState* state) { - HInputStream bak = state->input_stream; - if (h_do_parse((HParser*)env, state)) - return NULL; - else { - state->input_stream = bak; - return make_result(state, NULL); - } -} - -static const HParserVtable not_vt = { - .parse = parse_not, -}; - -const HParser* h_not(const HParser* p) { - HParser *res = g_new(HParser, 1); - res->vtable = ¬_vt; - res->env = (void*)p; - return res; -} static guint cache_key_hash(gconstpointer key) { return djbhash(key, sizeof(HParserCacheKey)); diff --git a/src/internal.h b/src/internal.h index 300241f..7395632 100644 --- a/src/internal.h +++ b/src/internal.h @@ -148,6 +148,7 @@ HCountedArray *h_carray_new_sized(HArena * arena, size_t size); HCountedArray *h_carray_new(HArena * arena); void h_carray_append(HCountedArray *array, void* item); + #if 0 #include #define arena_malloc(a, s) malloc(s) diff --git a/src/parsers/action.c b/src/parsers/action.c new file mode 100644 index 0000000..c5b89f9 --- /dev/null +++ b/src/parsers/action.c @@ -0,0 +1,31 @@ +#include "parser_internal.h" + +typedef struct { + const HParser *p; + HAction action; +} HParseAction; + +static HParseResult* parse_action(void *env, HParseState *state) { + HParseAction *a = (HParseAction*)env; + if (a->p && a->action) { + HParseResult *tmp = h_do_parse(a->p, state); + //HParsedToken *tok = a->action(h_do_parse(a->p, state)); + const HParsedToken *tok = a->action(tmp); + return make_result(state, (HParsedToken*)tok); + } else // either the parser's missing or the action's missing + 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->vtable = &action_vt; + HParseAction *env = g_new(HParseAction, 1); + env->p = p; + env->action = a; + res->env = (void*)env; + return res; +} diff --git a/src/parsers/and.c b/src/parsers/and.c new file mode 100644 index 0000000..fb117fb --- /dev/null +++ b/src/parsers/and.c @@ -0,0 +1,22 @@ +#include "parser_internal.h" + +static HParseResult *parse_and(void* env, HParseState* state) { + HInputStream bak = state->input_stream; + HParseResult *res = h_do_parse((HParser*)env, state); + state->input_stream = bak; + if (res) + return make_result(state, NULL); + 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->vtable = &and_vt; + return res; +} diff --git a/src/parsers/attr_bool.c b/src/parsers/attr_bool.c new file mode 100644 index 0000000..bf9e6dc --- /dev/null +++ b/src/parsers/attr_bool.c @@ -0,0 +1,32 @@ +#include "parser_internal.h" + +typedef struct { + const HParser *p; + HPredicate pred; +} HAttrBool; + +static HParseResult* parse_attr_bool(void *env, HParseState *state) { + HAttrBool *a = (HAttrBool*)env; + HParseResult *res = h_do_parse(a->p, state); + if (res && res->ast) { + if (a->pred(res)) + return res; + else + return NULL; + } else + 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->vtable = &attr_bool_vt; + HAttrBool *env = g_new(HAttrBool, 1); + env->p = p; + env->pred = pred; + res->env = (void*)env; + return res; +} diff --git a/src/parsers/bits.c b/src/parsers/bits.c new file mode 100644 index 0000000..32b7a55 --- /dev/null +++ b/src/parsers/bits.c @@ -0,0 +1,43 @@ +#include "parser_internal.h" + +struct bits_env { + uint8_t length; + uint8_t signedp; +}; + +static HParseResult* parse_bits(void* env, HParseState *state) { + struct bits_env *env_ = env; + HParsedToken *result = a_new(HParsedToken, 1); + result->token_type = (env_->signedp ? TT_SINT : TT_UINT); + if (env_->signedp) + result->sint = h_read_bits(&state->input_stream, env_->length, true); + else + result->uint = h_read_bits(&state->input_stream, env_->length, false); + 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->vtable = &bits_vt; + res->env = env; + return res; +} + +#define SIZED_BITS(name_pre, len, signedp) \ + const HParser* h_##name_pre##len () { \ + return h_bits(len, signedp); \ + } +SIZED_BITS(int, 8, true) +SIZED_BITS(int, 16, true) +SIZED_BITS(int, 32, true) +SIZED_BITS(int, 64, true) +SIZED_BITS(uint, 8, false) +SIZED_BITS(uint, 16, false) +SIZED_BITS(uint, 32, false) +SIZED_BITS(uint, 64, false) diff --git a/src/parsers/butnot.c b/src/parsers/butnot.c new file mode 100644 index 0000000..5026d79 --- /dev/null +++ b/src/parsers/butnot.c @@ -0,0 +1,49 @@ +#include "parser_internal.h" + +typedef struct { + const HParser *p1; + const HParser *p2; +} HTwoParsers; + + +static HParseResult* parse_butnot(void *env, HParseState *state) { + HTwoParsers *parsers = (HTwoParsers*)env; + // cache the initial state of the input stream + HInputStream start_state = state->input_stream; + HParseResult *r1 = h_do_parse(parsers->p1, state); + // if p1 failed, bail out early + if (NULL == r1) { + return NULL; + } + // cache the state after parse #1, since we might have to back up to it + HInputStream after_p1_state = state->input_stream; + state->input_stream = start_state; + HParseResult *r2 = h_do_parse(parsers->p2, state); + // TODO(mlp): I'm pretty sure the input stream state should be the post-p1 state in all cases + state->input_stream = after_p1_state; + // if p2 failed, restore post-p1 state and bail out early + if (NULL == r2) { + return r1; + } + size_t r1len = token_length(r1); + size_t r2len = token_length(r2); + // if both match but p1's text is shorter than than p2's (or the same length), fail + if (r1len <= r2len) { + return NULL; + } else { + return r1; + } +} + +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->vtable = &butnot_vt; ret->env = (void*)env; + return ret; +} + diff --git a/src/parsers/ch.c b/src/parsers/ch.c new file mode 100644 index 0000000..fbfa57e --- /dev/null +++ b/src/parsers/ch.c @@ -0,0 +1,23 @@ +#include "parser_internal.h" + +static HParseResult* parse_ch(void* env, HParseState *state) { + uint8_t c = (uint8_t)GPOINTER_TO_UINT(env); + uint8_t r = (uint8_t)h_read_bits(&state->input_stream, 8, false); + if (c == r) { + HParsedToken *tok = a_new(HParsedToken, 1); + tok->token_type = TT_UINT; tok->uint = r; + return make_result(state, tok); + } else { + return NULL; + } +} + +static const HParserVtable ch_vt = { + .parse = parse_ch, +}; +const HParser* h_ch(const uint8_t c) { + HParser *ret = g_new(HParser, 1); + ret->vtable = &ch_vt; + ret->env = GUINT_TO_POINTER(c); + return (const HParser*)ret; +} diff --git a/src/parsers/charset.c b/src/parsers/charset.c new file mode 100644 index 0000000..09542fc --- /dev/null +++ b/src/parsers/charset.c @@ -0,0 +1,43 @@ +#include "parser_internal.h" + + +static HParseResult* parse_charset(void *env, HParseState *state) { + uint8_t in = h_read_bits(&state->input_stream, 8, false); + HCharset cs = (HCharset)env; + + if (charset_isset(cs, in)) { + HParsedToken *tok = a_new(HParsedToken, 1); + tok->token_type = TT_UINT; tok->uint = in; + return make_result(state, tok); + } else + 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->vtable = &charset_vt; + ret->env = (void*)cs; + return (const HParser*)ret; +} + + +const HParser* h_not_in(const uint8_t *options, int count) { + HParser *ret = g_new(HParser, 1); + HCharset cs = new_charset(); + for (int i = 0; i < 256; i++) + charset_set(cs, i, 1); + for (int i = 0; i < count; i++) + charset_set(cs, options[i], 0); + + ret->vtable = &charset_vt; + ret->env = (void*)cs; + return (const HParser*)ret; +} + diff --git a/src/parsers/choice.c b/src/parsers/choice.c new file mode 100644 index 0000000..082a2e1 --- /dev/null +++ b/src/parsers/choice.c @@ -0,0 +1,53 @@ +#include "parser_internal.h" + +typedef struct { + size_t len; + const HParser **p_array; +} HSequence; + + +static HParseResult* parse_choice(void *env, HParseState *state) { + HSequence *s = (HSequence*)env; + HInputStream backup = state->input_stream; + for (size_t i=0; ilen; ++i) { + if (i != 0) + state->input_stream = backup; + HParseResult *tmp = h_do_parse(s->p_array[i], state); + if (NULL != tmp) + return tmp; + } + // nothing succeeded, so fail + return NULL; +} + +static const HParserVtable choice_vt = { + .parse = parse_choice, +}; + +const HParser* h_choice(const HParser* p, ...) { + va_list ap; + size_t len = 0; + HSequence *s = g_new(HSequence, 1); + + const HParser *arg; + va_start(ap, p); + do { + len++; + arg = va_arg(ap, const HParser *); + } while (arg); + va_end(ap); + s->p_array = g_new(const HParser *, len); + + va_start(ap, p); + s->p_array[0] = p; + for (size_t i = 1; i < len; i++) { + s->p_array[i] = va_arg(ap, const HParser *); + } while (arg); + va_end(ap); + + s->len = len; + HParser *ret = g_new(HParser, 1); + ret->vtable = &choice_vt; ret->env = (void*)s; + return ret; +} + diff --git a/src/parsers/difference.c b/src/parsers/difference.c new file mode 100644 index 0000000..7f167a0 --- /dev/null +++ b/src/parsers/difference.c @@ -0,0 +1,47 @@ +#include "parser_internal.h" + +typedef struct { + const HParser *p1; + const HParser *p2; +} HTwoParsers; + +static HParseResult* parse_difference(void *env, HParseState *state) { + HTwoParsers *parsers = (HTwoParsers*)env; + // cache the initial state of the input stream + HInputStream start_state = state->input_stream; + HParseResult *r1 = h_do_parse(parsers->p1, state); + // if p1 failed, bail out early + if (NULL == r1) { + return NULL; + } + // cache the state after parse #1, since we might have to back up to it + HInputStream after_p1_state = state->input_stream; + state->input_stream = start_state; + HParseResult *r2 = h_do_parse(parsers->p2, state); + // TODO(mlp): I'm pretty sure the input stream state should be the post-p1 state in all cases + state->input_stream = after_p1_state; + // if p2 failed, restore post-p1 state and bail out early + if (NULL == r2) { + return r1; + } + size_t r1len = token_length(r1); + size_t r2len = token_length(r2); + // if both match but p1's text is shorter than p2's, fail + if (r1len < r2len) { + return NULL; + } else { + return r1; + } +} + +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->vtable = &difference_vt; ret->env = (void*)env; + return ret; +} diff --git a/src/parsers/end.c b/src/parsers/end.c new file mode 100644 index 0000000..8e427bd --- /dev/null +++ b/src/parsers/end.c @@ -0,0 +1,21 @@ +#include "parser_internal.h" + +static HParseResult* parse_end(void *env, HParseState *state) { + if (state->input_stream.index == state->input_stream.length) { + HParseResult *ret = a_new(HParseResult, 1); + ret->ast = NULL; + return ret; + } else { + return NULL; + } +} + +static const HParserVtable end_vt = { + .parse = parse_end, +}; + +const HParser* h_end_p() { + HParser *ret = g_new(HParser, 1); + ret->vtable = &end_vt; ret->env = NULL; + return (const HParser*)ret; +} diff --git a/src/parsers/epsilon.c b/src/parsers/epsilon.c new file mode 100644 index 0000000..b0b31c7 --- /dev/null +++ b/src/parsers/epsilon.c @@ -0,0 +1,20 @@ +#include "parser_internal.h" + +static HParseResult* parse_epsilon(void* env, HParseState* state) { + (void)env; + HParseResult* res = a_new(HParseResult, 1); + res->ast = NULL; + res->arena = state->arena; + return res; +} + +static const HParserVtable epsilon_vt = { + .parse = parse_epsilon, +}; + +const HParser* h_epsilon_p() { + HParser *res = g_new(HParser, 1); + res->vtable = &epsilon_vt; + res->env = NULL; + return res; +} diff --git a/src/parsers/ignore.c b/src/parsers/ignore.c new file mode 100644 index 0000000..5972548 --- /dev/null +++ b/src/parsers/ignore.c @@ -0,0 +1,22 @@ +#include "parser_internal.h" + +static HParseResult* parse_ignore(void* env, HParseState* state) { + HParseResult *res0 = h_do_parse((HParser*)env, state); + if (!res0) + return NULL; + HParseResult *res = a_new(HParseResult, 1); + res->ast = NULL; + 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->vtable = &ignore_vt; + ret->env = (void*)p; + return ret; +} diff --git a/src/parsers/indirect.c b/src/parsers/indirect.c new file mode 100644 index 0000000..43657c3 --- /dev/null +++ b/src/parsers/indirect.c @@ -0,0 +1,20 @@ +#include "parser_internal.h" + +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->vtable = &indirect_vt; + res->env = NULL; + return res; +} diff --git a/src/parsers/int_range.c b/src/parsers/int_range.c new file mode 100644 index 0000000..9fb1c7e --- /dev/null +++ b/src/parsers/int_range.c @@ -0,0 +1,51 @@ +#include "parser_internal.h" + + +typedef struct { + const HParser *p; + int64_t lower; + int64_t upper; +} HRange; + +static HParseResult* parse_int_range(void *env, HParseState *state) { + HRange *r_env = (HRange*)env; + HParseResult *ret = h_do_parse(r_env->p, state); + if (!ret || !ret->ast) + return NULL; + switch(ret->ast->token_type) { + case TT_SINT: + if (r_env->lower <= ret->ast->sint && r_env->upper >= ret->ast->sint) + return ret; + else + return NULL; + case TT_UINT: + if ((uint64_t)r_env->lower <= ret->ast->uint && (uint64_t)r_env->upper >= ret->ast->uint) + return ret; + else + return NULL; + default: + return NULL; + } +} + +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) { + // p must be an integer parser, which means it's using parse_bits + // TODO: re-add this check + //assert_message(p->vtable == &bits_vt, "int_range requires an integer parser"); + + // and regardless, the bounds need to fit in the parser in question + // TODO: check this as well. + + HRange *r_env = g_new(HRange, 1); + r_env->p = p; + r_env->lower = lower; + r_env->upper = upper; + HParser *ret = g_new(HParser, 1); + ret->vtable = &int_range_vt; + ret->env = (void*)r_env; + return ret; +} diff --git a/src/parsers/many.c b/src/parsers/many.c new file mode 100644 index 0000000..f18be26 --- /dev/null +++ b/src/parsers/many.c @@ -0,0 +1,145 @@ +#include "parser_internal.h" + +// TODO: split this up. +typedef struct { + const HParser *p, *sep; + size_t count; + bool min_p; +} HRepeat; + +static HParseResult *parse_many(void* env, HParseState *state) { + HRepeat *env_ = (HRepeat*) env; + HCountedArray *seq = h_carray_new_sized(state->arena, (env_->count > 0 ? env_->count : 4)); + size_t count = 0; + HInputStream bak; + while (env_->min_p || env_->count > count) { + bak = state->input_stream; + if (count > 0) { + HParseResult *sep = h_do_parse(env_->sep, state); + if (!sep) + goto err0; + } + HParseResult *elem = h_do_parse(env_->p, state); + if (!elem) + goto err0; + if (elem->ast) + h_carray_append(seq, (void*)elem->ast); + count++; + } + if (count < env_->count) + goto err; + succ: + ; // necessary for the label to be here... + HParsedToken *res = a_new(HParsedToken, 1); + res->token_type = TT_SEQUENCE; + res->seq = seq; + return make_result(state, res); + err0: + if (count >= env_->count) { + state->input_stream = bak; + goto succ; + } + err: + state->input_stream = bak; + 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); + env->p = p; + env->sep = h_epsilon_p(); + env->count = 0; + env->min_p = true; + res->vtable = &many_vt; + res->env = env; + return res; +} + +const HParser* h_many1(const HParser* p) { + HParser *res = g_new(HParser, 1); + HRepeat *env = g_new(HRepeat, 1); + env->p = p; + env->sep = h_epsilon_p(); + env->count = 1; + env->min_p = true; + res->vtable = &many_vt; + res->env = env; + return res; +} + +const HParser* h_repeat_n(const HParser* p, const size_t n) { + HParser *res = g_new(HParser, 1); + HRepeat *env = g_new(HRepeat, 1); + env->p = p; + env->sep = h_epsilon_p(); + env->count = n; + env->min_p = false; + res->vtable = &many_vt; + res->env = env; + return res; +} + +const HParser* h_sepBy(const HParser* p, const HParser* sep) { + HParser *res = g_new(HParser, 1); + HRepeat *env = g_new(HRepeat, 1); + env->p = p; + env->sep = sep; + env->count = 0; + env->min_p = true; + res->vtable = &many_vt; + res->env = env; + return res; +} + +const HParser* h_sepBy1(const HParser* p, const HParser* sep) { + HParser *res = g_new(HParser, 1); + HRepeat *env = g_new(HRepeat, 1); + env->p = p; + env->sep = sep; + env->count = 1; + env->min_p = true; + res->vtable = &many_vt; + res->env = env; + return res; +} + +typedef struct { + const HParser *length; + const HParser *value; +} HLenVal; + +static HParseResult* parse_length_value(void *env, HParseState *state) { + HLenVal *lv = (HLenVal*)env; + HParseResult *len = h_do_parse(lv->length, state); + if (!len) + return NULL; + if (len->ast->token_type != TT_UINT) + errx(1, "Length parser must return an unsigned integer"); + // TODO: allocate this using public functions + HRepeat repeat = { + .p = lv->value, + .sep = h_epsilon_p(), + .count = len->ast->uint, + .min_p = false + }; + 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->vtable = &length_value_vt; + HLenVal *env = g_new(HLenVal, 1); + env->length = length; + env->value = value; + res->env = (void*)env; + return res; +} diff --git a/src/parsers/not.c b/src/parsers/not.c new file mode 100644 index 0000000..1c46b6d --- /dev/null +++ b/src/parsers/not.c @@ -0,0 +1,22 @@ +#include "parser_internal.h" + +static HParseResult* parse_not(void* env, HParseState* state) { + HInputStream bak = state->input_stream; + if (h_do_parse((HParser*)env, state)) + return NULL; + else { + state->input_stream = bak; + return make_result(state, NULL); + } +} + +static const HParserVtable not_vt = { + .parse = parse_not, +}; + +const HParser* h_not(const HParser* p) { + HParser *res = g_new(HParser, 1); + res->vtable = ¬_vt; + res->env = (void*)p; + return res; +} diff --git a/src/parsers/nothing.c b/src/parsers/nothing.c new file mode 100644 index 0000000..9f81c02 --- /dev/null +++ b/src/parsers/nothing.c @@ -0,0 +1,17 @@ +#include "parser_internal.h" + + +static HParseResult* parse_nothing() { + // not a mistake, this parser always fails + return NULL; +} + +static const HParserVtable nothing_vt = { + .parse = parse_nothing, +}; + +const HParser* h_nothing_p() { + HParser *ret = g_new(HParser, 1); + ret->vtable = ¬hing_vt; ret->env = NULL; + return (const HParser*)ret; +} diff --git a/src/parsers/optional.c b/src/parsers/optional.c new file mode 100644 index 0000000..c084576 --- /dev/null +++ b/src/parsers/optional.c @@ -0,0 +1,26 @@ +#include "parser_internal.h" + +static HParseResult* parse_optional(void* env, HParseState* state) { + HInputStream bak = state->input_stream; + HParseResult *res0 = h_do_parse((HParser*)env, state); + if (res0) + return res0; + state->input_stream = bak; + HParsedToken *ast = a_new(HParsedToken, 1); + ast->token_type = TT_NONE; + return make_result(state, ast); +} + +static const HParserVtable optional_vt = { + .parse = parse_optional, +}; + +const HParser* h_optional(const HParser* p) { + // TODO: re-add this + //assert_message(p->vtable != &ignore_vt, "Thou shalt ignore an option, rather than the other way 'round."); + HParser *ret = g_new(HParser, 1); + ret->vtable = &optional_vt; + ret->env = (void*)p; + return ret; +} + diff --git a/src/parsers/parser_internal.h b/src/parsers/parser_internal.h new file mode 100644 index 0000000..d8b3651 --- /dev/null +++ b/src/parsers/parser_internal.h @@ -0,0 +1,27 @@ +#ifndef HAMMER_PARSE_INTERNAL__H +#define HAMMER_PARSE_INTERNAL__H +#include "../hammer.h" +#include "../internal.h" + +#define a_new_(arena, typ, count) ((typ*)h_arena_malloc((arena), sizeof(typ)*(count))) +#define a_new(typ, count) a_new_(state->arena, typ, count) +// we can create a_new0 if necessary. It would allocate some memory and immediately zero it out. + +static inline HParseResult* make_result(HParseState *state, HParsedToken *tok) { + HParseResult *ret = a_new(HParseResult, 1); + ret->ast = tok; + ret->arena = state->arena; + return ret; +} + +// return token size in bits... +static inline size_t token_length(HParseResult *pr) { + if (pr) { + return pr->bit_length; + } else { + return 0; + } +} + + +#endif // HAMMER_PARSE_INTERNAL__H diff --git a/src/parsers/sequence.c b/src/parsers/sequence.c new file mode 100644 index 0000000..54196da --- /dev/null +++ b/src/parsers/sequence.c @@ -0,0 +1,54 @@ +#include "parser_internal.h" + +typedef struct { + size_t len; + const HParser **p_array; +} HSequence; + +static HParseResult* parse_sequence(void *env, HParseState *state) { + HSequence *s = (HSequence*)env; + HCountedArray *seq = h_carray_new_sized(state->arena, (s->len > 0) ? s->len : 4); + for (size_t i=0; ilen; ++i) { + HParseResult *tmp = h_do_parse(s->p_array[i], state); + // if the interim parse fails, the whole thing fails + if (NULL == tmp) { + return NULL; + } else { + if (tmp->ast) + h_carray_append(seq, (void*)tmp->ast); + } + } + HParsedToken *tok = a_new(HParsedToken, 1); + tok->token_type = TT_SEQUENCE; tok->seq = seq; + 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; + const HParser *arg; + va_start(ap, p); + do { + len++; + arg = va_arg(ap, const HParser *); + } while (arg); + va_end(ap); + HSequence *s = g_new(HSequence, 1); + s->p_array = g_new(const HParser *, len); + + va_start(ap, p); + s->p_array[0] = p; + for (size_t i = 1; i < len; i++) { + s->p_array[i] = va_arg(ap, const HParser *); + } while (arg); + va_end(ap); + + s->len = len; + HParser *ret = g_new(HParser, 1); + ret->vtable = &sequence_vt; ret->env = (void*)s; + return ret; +} diff --git a/src/parsers/template.c b/src/parsers/template.c new file mode 100644 index 0000000..bfe45bc --- /dev/null +++ b/src/parsers/template.c @@ -0,0 +1 @@ +#include "parser_internal.h" diff --git a/src/parsers/token.c b/src/parsers/token.c new file mode 100644 index 0000000..b3be207 --- /dev/null +++ b/src/parsers/token.c @@ -0,0 +1,34 @@ +#include "parser_internal.h" + +typedef struct { + uint8_t *str; + uint8_t len; +} HToken; + + + +static HParseResult* parse_token(void *env, HParseState *state) { + HToken *t = (HToken*)env; + for (int i=0; ilen; ++i) { + uint8_t chr = (uint8_t)h_read_bits(&state->input_stream, 8, false); + if (t->str[i] != chr) { + return NULL; + } + } + HParsedToken *tok = a_new(HParsedToken, 1); + tok->token_type = TT_BYTES; tok->bytes.token = t->str; tok->bytes.len = t->len; + 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->vtable = &token_vt; + ret->env = t; + return (const HParser*)ret; +} diff --git a/src/parsers/unimplemented.c b/src/parsers/unimplemented.c new file mode 100644 index 0000000..99d153b --- /dev/null +++ b/src/parsers/unimplemented.c @@ -0,0 +1,26 @@ +#include "parser_internal.h" + +static HParseResult* parse_unimplemented(void* env, HParseState *state) { + (void) env; + (void) state; + static HParsedToken token = { + .token_type = TT_ERR + }; + static HParseResult result = { + .ast = &token + }; + return &result; +} + +static const HParserVtable unimplemented_vt = { + .parse = parse_unimplemented, +}; + +static HParser unimplemented = { + .vtable = &unimplemented_vt, + .env = NULL +}; + +const HParser* h_unimplemented() { + return &unimplemented; +} diff --git a/src/parsers/whitespace.c b/src/parsers/whitespace.c new file mode 100644 index 0000000..4d2ec17 --- /dev/null +++ b/src/parsers/whitespace.c @@ -0,0 +1,26 @@ +#include +#include "parser_internal.h" + +static HParseResult* parse_whitespace(void* env, HParseState *state) { + char c; + HInputStream bak; + do { + bak = state->input_stream; + c = h_read_bits(&state->input_stream, 8, false); + if (state->input_stream.overrun) + return NULL; + } while (isspace(c)); + state->input_stream = bak; + 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->vtable = &whitespace_vt; + ret->env = (void*)p; + return ret; +} diff --git a/src/parsers/xor.c b/src/parsers/xor.c new file mode 100644 index 0000000..9ffd51e --- /dev/null +++ b/src/parsers/xor.c @@ -0,0 +1,44 @@ +#include "parser_internal.h" + +typedef struct { + const HParser *p1; + const HParser *p2; +} HTwoParsers; + + +static HParseResult* parse_xor(void *env, HParseState *state) { + HTwoParsers *parsers = (HTwoParsers*)env; + // cache the initial state of the input stream + HInputStream start_state = state->input_stream; + HParseResult *r1 = h_do_parse(parsers->p1, state); + HInputStream after_p1_state = state->input_stream; + // reset input stream, parse again + state->input_stream = start_state; + HParseResult *r2 = h_do_parse(parsers->p2, state); + if (NULL == r1) { + if (NULL != r2) { + return r2; + } else { + return NULL; + } + } else { + if (NULL == r2) { + state->input_stream = after_p1_state; + return r1; + } else { + return NULL; + } + } +} + +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->vtable = &xor_vt; ret->env = (void*)env; + return ret; +} From 783be52ad9e6c7e9d26adc6f2a97dee8feb31cf9 Mon Sep 17 00:00:00 2001 From: Dan Hirsch Date: Sat, 26 May 2012 16:02:50 +0200 Subject: [PATCH 3/4] Epsilon is now static --- src/parsers/epsilon.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/parsers/epsilon.c b/src/parsers/epsilon.c index b0b31c7..dc6d7a6 100644 --- a/src/parsers/epsilon.c +++ b/src/parsers/epsilon.c @@ -12,9 +12,11 @@ static const HParserVtable epsilon_vt = { .parse = parse_epsilon, }; +static const HParser epsilon_p = { + .vtable = &epsilon_vt, + .env = NULL +}; + const HParser* h_epsilon_p() { - HParser *res = g_new(HParser, 1); - res->vtable = &epsilon_vt; - res->env = NULL; - return res; + return &epsilon_p; } From c43b6d2f4c12704cf4ad9c17f99af2d1db295b45 Mon Sep 17 00:00:00 2001 From: Dan Hirsch Date: Sat, 26 May 2012 16:05:01 +0200 Subject: [PATCH 4/4] Forgot attr_bool --- src/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Makefile b/src/Makefile index 7f08439..9c69124 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,7 +20,8 @@ PARSERS := \ ignore \ epsilon \ and \ - not + not \ + attr_bool OUTPUTS := bitreader.o \ hammer.o \ @@ -41,8 +42,8 @@ all: libhammer.a test_suite test_suite: test_suite.o libhammer.a $(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS) -libhammer.a: bitreader.o hammer.o pprint.o allocator.o datastructures.o -libhammer.a: $(PARSERS:%=parsers/%.o) +libhammer.a: bitreader.o hammer.o pprint.o allocator.o datastructures.o \ + $(PARSERS:%=parsers/%.o) bitreader.o: test_suite.h hammer.o: hammer.h