Left-recursion caching strategy about halfway implemented. Compiles, DOES NOT RUN.

This commit is contained in:
Meredith L. Patterson 2012-05-13 01:18:18 +01:00
parent 0164ddc98d
commit e6eb2efa88
3 changed files with 71 additions and 27 deletions

View file

@ -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.

View file

@ -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 {

View file

@ -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;