From e6eb2efa882d70c2511c9d76405e0437a51cd2ed Mon Sep 17 00:00:00 2001 From: "Meredith L. Patterson" <clonearmy@gmail.com> Date: Sun, 13 May 2012 01:18:18 +0100 Subject: [PATCH] Left-recursion caching strategy about halfway implemented. Compiles, DOES NOT RUN. --- src/hammer.c | 73 +++++++++++++++++++++++++++++++++++++------------- src/hammer.h | 1 + src/internal.h | 24 +++++++++++------ 3 files changed, 71 insertions(+), 27 deletions(-) diff --git a/src/hammer.c b/src/hammer.c index 0e48b85c..b3060737 100644 --- a/src/hammer.c +++ b/src/hammer.c @@ -35,36 +35,70 @@ guint djbhash(const uint8_t *buf, size_t len) { return hash; } +void setupLR(const parser_t *p, GQueue *stack, LR_t *recDetect) { + +} + +parse_result_t* lr_answer(const parser_t *p, parse_state_t *state, LR_t *growable) { + return NULL; +} + +parse_result_t* grow(const parser_t *p, parse_state_t *state, head_t *head) { + return NULL; +} + parse_result_t* do_parse(const parser_t* parser, parse_state_t *state) { // TODO(thequux): add caching here. - parser_cache_key_t key = { - .input_pos = state->input_stream, - .parser = parser - }; + parser_cache_key_t *key = a_new(parser_cache_key_t, 1); + key->input_pos = state->input_stream; + key->parser = parser; // check to see if there is already a result for this object... - if (g_hash_table_contains(state->cache, &key)) { - // it exists! - // TODO(thequux): handle left recursion case - return g_hash_table_lookup(state->cache, &key); - } else { - // It doesn't exist... run the - parse_result_t *res; + if (!g_hash_table_contains(state->cache, key)) { + // It doesn't exist, so create a dummy result to cache + LR_t *base = a_new(LR_t, 1); + base->seed = NULL; base->rule = parser; base->head = NULL; + g_queue_push_head(state->input_stream.lr_stack, base); + // cache it + parser_cache_value_t *dummy = a_new(parser_cache_value_t, 1); + dummy->value_type = PC_LEFT; dummy->left = base; + g_hash_table_replace(state->cache, key, dummy); + // parse the input + parse_result_t *tmp_res; if (parser) - res = parser->fn(parser->env, state); + tmp_res = parser->fn(parser->env, state); else - res = NULL; + tmp_res = NULL; if (state->input_stream.overrun) - res = NULL; // overrun is always failure. - // update the cache - g_hash_table_replace(state->cache, &key, res); + return NULL; // overrun is always failure. #ifdef CONSISTENCY_CHECK - if (!res) { + if (!tmp_res) { state->input_stream = INVALID; - state->input_stream.input = key.input_pos.input; + state->input_stream.input = key->input_pos.input; } #endif - return res; + // the base variable has passed equality tests with the cache + g_queue_pop_head(state->input_stream.lr_stack); + // setupLR, used below, mutates the LR to have a head if appropriate, so we check to see if we have one + if (NULL == base->head) { + parser_cache_value_t *right = a_new(parser_cache_value_t, 1); + right->value_type = PC_RIGHT; right->right = tmp_res; + g_hash_table_replace(state->cache, key, right); + return tmp_res; + } else { + base->seed = tmp_res; + parse_result_t *res = lr_answer(parser, state, base); + return res; + } + } else { + // it exists! + parser_cache_value_t *value = g_hash_table_lookup(state->cache, key); + if (PC_LEFT == value->value_type) { + setupLR(parser, state->input_stream.lr_stack, value->left); + return value->left->seed; // BUG: this might not be correct + } else { + return value->right; + } } } @@ -489,6 +523,7 @@ parse_result_t* parse(const parser_t* parser, const uint8_t* input, size_t lengt parse_state->input_stream.overrun = 0; parse_state->input_stream.endianness = BIT_BIG_ENDIAN | BYTE_BIG_ENDIAN; parse_state->input_stream.length = length; + g_queue_init(parse_state->input_stream.lr_stack); parse_state->arena = arena; parse_result_t *res = do_parse(parser, parse_state); // tear down the parse state. For now, leak like a sieve. diff --git a/src/hammer.h b/src/hammer.h index a3536414..421c9f33 100644 --- a/src/hammer.h +++ b/src/hammer.h @@ -43,6 +43,7 @@ typedef struct input_stream { char bit_offset; char endianness; char overrun; + GQueue *lr_stack; } input_stream_t; typedef struct parse_state { diff --git a/src/internal.h b/src/internal.h index 8a756c43..e08d5fcd 100644 --- a/src/internal.h +++ b/src/internal.h @@ -29,19 +29,27 @@ typedef struct parser_cache_key { } parser_cache_key_t; typedef enum parser_cache_value_type { - PC_BASE, - PC_IN_RECURSION, - PC_LRESULT, - PC_RESULT + PC_LEFT, + PC_RIGHT } parser_cache_value_type_t; +typedef struct head { + parser_t *head_parser; + GSList *involved_set; + GSList *eval_set; +} head_t; + +typedef struct LR { + parse_result_t *seed; + const parser_t *rule; + head_t *head; +} LR_t; + typedef struct parser_cache_value { parser_cache_value_type_t value_type; union { - int base; - parse_result_t *in_recursion; - parse_result_t *lresult; - parse_result_t *result; + LR_t *left; + parse_result_t *right; }; } parser_cache_value_t; -- GitLab