From b1e8e297740256e44233837c6aff309369608c23 Mon Sep 17 00:00:00 2001 From: "Sven M. Hallberg" <pesco@khjk.org> Date: Thu, 20 Jun 2013 11:05:57 +0200 Subject: [PATCH] add engine forking --- src/backends/glr.c | 55 ++++++++++++++++++++++++++++++++++++++++++-- src/backends/lr.c | 12 +++++----- src/backends/lr.h | 2 +- src/datastructures.c | 10 ++++++++ src/internal.h | 1 + 5 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/backends/glr.c b/src/backends/glr.c index 429d06b1..2b4b974b 100644 --- a/src/backends/glr.c +++ b/src/backends/glr.c @@ -1,3 +1,4 @@ +#include <assert.h> #include "lr.h" @@ -23,6 +24,26 @@ void h_glr_free(HParser *parser) /* GLR driver */ +HLREngine *fork_engine(const HLREngine *engine) +{ + HLREngine *eng2 = h_arena_malloc(engine->tarena, sizeof(HLREngine)); + eng2->table = engine->table; + eng2->state = engine->state; + + // shallow-copy the stacks + // this works because h_slist_push and h_slist_pop never modify + // the underlying structure of HSlistNodes, only the head pointer. + // in fact, this gives us prefix sharing for free. + eng2->left = h_arena_malloc(engine->tarena, sizeof(HSlist)); + eng2->right = h_arena_malloc(engine->tarena, sizeof(HSlist)); + *eng2->left = *engine->left; + *eng2->right = *engine->right; + + eng2->arena = engine->arena; + eng2->tarena = engine->tarena; + return eng2; +} + HParseResult *h_glr_parse(HAllocator* mm__, const HParser* parser, HInputStream* stream) { HLRTable *table = parser->backend_data; @@ -41,14 +62,44 @@ HParseResult *h_glr_parse(HAllocator* mm__, const HParser* parser, HInputStream* HLREngine *engine = (*x)->elem; const HLRAction *action = h_lrengine_action(engine, stream); - // XXX handle conflicts -> fork engine + + // fork engine on conflicts + if(action && action->type == HLR_CONFLICT) { + const HSlist *branches = action->branches; + + // there should be at least two conflicting actions + assert(branches->head); + assert(branches->head->next); + + // save first action for use with old engine below + action = branches->head->elem; + + // fork a new engine for all the other actions + for(HSlistNode *x=branches->head->next; x; x=x->next) { + HLRAction *act = x->elem; + HLREngine *eng = fork_engine(engine); + + // perform one step; add engine to list if it wants to keep running + bool run = h_lrengine_step(eng, act); + if(run) { + h_slist_push(engines, eng); + } else { + HParseResult *res = h_lrengine_result(eng); + if(res) + result = res; + } + } + } + bool running = h_lrengine_step(engine, action); if(running) { x = &(*x)->next; // go to next } else { *x = (*x)->next; // remove from list - result = h_lrengine_result(engine); + HParseResult *res = h_lrengine_result(engine); + if(res) + result = res; } } } diff --git a/src/backends/lr.c b/src/backends/lr.c index 4ab53bce..1ea6a395 100644 --- a/src/backends/lr.c +++ b/src/backends/lr.c @@ -270,8 +270,8 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action) if(action->type == HLR_SHIFT) { h_slist_push(left, (void *)(uintptr_t)engine->state); - h_slist_pop(right); // symbol (discard) - h_slist_push(left, h_slist_pop(right)); // semantic value + h_slist_drop(right); // symbol (discard) + h_slist_push(left, h_slist_drop(right)); // semantic value engine->state = action->nextstate; } else { assert(action->type == HLR_REDUCE); @@ -286,8 +286,8 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action) // pull values off the left stack, rewinding state accordingly HParsedToken *v = NULL; for(size_t i=0; i<len; i++) { - v = h_slist_pop(left); - engine->state = (uintptr_t)h_slist_pop(left); + v = h_slist_drop(left); + engine->state = (uintptr_t)h_slist_drop(left); // collect values in result sequence value->seq->elements[len-1-i] = v; @@ -322,10 +322,10 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action) HParseResult *h_lrengine_result(HLREngine *engine) { // parsing was successful iff the start symbol is on top of the right stack - if(h_slist_pop(engine->right) == engine->table->start) { + if(h_slist_drop(engine->right) == engine->table->start) { // next on the right stack is the start symbol's semantic value assert(!h_slist_empty(engine->right)); - HParsedToken *tok = h_slist_pop(engine->right); + HParsedToken *tok = h_slist_drop(engine->right); return make_result(engine->arena, tok); } else { return NULL; diff --git a/src/backends/lr.h b/src/backends/lr.h index f766d5b7..edf0871e 100644 --- a/src/backends/lr.h +++ b/src/backends/lr.h @@ -67,6 +67,7 @@ typedef struct HLREnhGrammar_ { typedef struct HLREngine_ { const HLRTable *table; + size_t state; // stack layout: // on the left stack, we put pairs: (saved state, semantic value) @@ -74,7 +75,6 @@ typedef struct HLREngine_ { HSlist *left; // left stack; reductions happen here HSlist *right; // right stack; input appears here - size_t state; HArena *arena; // will hold the results HArena *tarena; // tmp, deleted after parse } HLREngine; diff --git a/src/datastructures.c b/src/datastructures.c index 075b966b..94bc9015 100644 --- a/src/datastructures.c +++ b/src/datastructures.c @@ -62,6 +62,16 @@ HSlist* h_slist_copy(HSlist *slist) { return ret; } +// like h_slist_pop, but does not deallocate the head node +void* h_slist_drop(HSlist *slist) { + HSlistNode *head = slist->head; + if (!head) + return NULL; + void* ret = head->elem; + slist->head = head->next; + return ret; +} + void* h_slist_pop(HSlist *slist) { HSlistNode *head = slist->head; if (!head) diff --git a/src/internal.h b/src/internal.h index d8b221a7..a897e9fc 100644 --- a/src/internal.h +++ b/src/internal.h @@ -248,6 +248,7 @@ void h_carray_append(HCountedArray *array, void* item); HSlist* h_slist_new(HArena *arena); HSlist* h_slist_copy(HSlist *slist); void* h_slist_pop(HSlist *slist); +void* h_slist_drop(HSlist *slist); void h_slist_push(HSlist *slist, void* item); bool h_slist_find(HSlist *slist, const void* item); HSlist* h_slist_remove_all(HSlist *slist, const void* item); -- GitLab