add engine forking
This commit is contained in:
parent
4f36fcd2c1
commit
b1e8e29774
5 changed files with 71 additions and 9 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <assert.h>
|
||||||
#include "lr.h"
|
#include "lr.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -23,6 +24,26 @@ void h_glr_free(HParser *parser)
|
||||||
|
|
||||||
/* GLR driver */
|
/* 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)
|
HParseResult *h_glr_parse(HAllocator* mm__, const HParser* parser, HInputStream* stream)
|
||||||
{
|
{
|
||||||
HLRTable *table = parser->backend_data;
|
HLRTable *table = parser->backend_data;
|
||||||
|
|
@ -41,14 +62,44 @@ HParseResult *h_glr_parse(HAllocator* mm__, const HParser* parser, HInputStream*
|
||||||
HLREngine *engine = (*x)->elem;
|
HLREngine *engine = (*x)->elem;
|
||||||
|
|
||||||
const HLRAction *action = h_lrengine_action(engine, stream);
|
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);
|
bool running = h_lrengine_step(engine, action);
|
||||||
|
|
||||||
if(running) {
|
if(running) {
|
||||||
x = &(*x)->next; // go to next
|
x = &(*x)->next; // go to next
|
||||||
} else {
|
} else {
|
||||||
*x = (*x)->next; // remove from list
|
*x = (*x)->next; // remove from list
|
||||||
result = h_lrengine_result(engine);
|
HParseResult *res = h_lrengine_result(engine);
|
||||||
|
if(res)
|
||||||
|
result = res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -270,8 +270,8 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action)
|
||||||
|
|
||||||
if(action->type == HLR_SHIFT) {
|
if(action->type == HLR_SHIFT) {
|
||||||
h_slist_push(left, (void *)(uintptr_t)engine->state);
|
h_slist_push(left, (void *)(uintptr_t)engine->state);
|
||||||
h_slist_pop(right); // symbol (discard)
|
h_slist_drop(right); // symbol (discard)
|
||||||
h_slist_push(left, h_slist_pop(right)); // semantic value
|
h_slist_push(left, h_slist_drop(right)); // semantic value
|
||||||
engine->state = action->nextstate;
|
engine->state = action->nextstate;
|
||||||
} else {
|
} else {
|
||||||
assert(action->type == HLR_REDUCE);
|
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
|
// pull values off the left stack, rewinding state accordingly
|
||||||
HParsedToken *v = NULL;
|
HParsedToken *v = NULL;
|
||||||
for(size_t i=0; i<len; i++) {
|
for(size_t i=0; i<len; i++) {
|
||||||
v = h_slist_pop(left);
|
v = h_slist_drop(left);
|
||||||
engine->state = (uintptr_t)h_slist_pop(left);
|
engine->state = (uintptr_t)h_slist_drop(left);
|
||||||
|
|
||||||
// collect values in result sequence
|
// collect values in result sequence
|
||||||
value->seq->elements[len-1-i] = v;
|
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)
|
HParseResult *h_lrengine_result(HLREngine *engine)
|
||||||
{
|
{
|
||||||
// parsing was successful iff the start symbol is on top of the right stack
|
// 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
|
// next on the right stack is the start symbol's semantic value
|
||||||
assert(!h_slist_empty(engine->right));
|
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);
|
return make_result(engine->arena, tok);
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@ typedef struct HLREnhGrammar_ {
|
||||||
|
|
||||||
typedef struct HLREngine_ {
|
typedef struct HLREngine_ {
|
||||||
const HLRTable *table;
|
const HLRTable *table;
|
||||||
|
size_t state;
|
||||||
|
|
||||||
// stack layout:
|
// stack layout:
|
||||||
// on the left stack, we put pairs: (saved state, semantic value)
|
// 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 *left; // left stack; reductions happen here
|
||||||
HSlist *right; // right stack; input appears here
|
HSlist *right; // right stack; input appears here
|
||||||
|
|
||||||
size_t state;
|
|
||||||
HArena *arena; // will hold the results
|
HArena *arena; // will hold the results
|
||||||
HArena *tarena; // tmp, deleted after parse
|
HArena *tarena; // tmp, deleted after parse
|
||||||
} HLREngine;
|
} HLREngine;
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,16 @@ HSlist* h_slist_copy(HSlist *slist) {
|
||||||
return ret;
|
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) {
|
void* h_slist_pop(HSlist *slist) {
|
||||||
HSlistNode *head = slist->head;
|
HSlistNode *head = slist->head;
|
||||||
if (!head)
|
if (!head)
|
||||||
|
|
|
||||||
|
|
@ -248,6 +248,7 @@ void h_carray_append(HCountedArray *array, void* item);
|
||||||
HSlist* h_slist_new(HArena *arena);
|
HSlist* h_slist_new(HArena *arena);
|
||||||
HSlist* h_slist_copy(HSlist *slist);
|
HSlist* h_slist_copy(HSlist *slist);
|
||||||
void* h_slist_pop(HSlist *slist);
|
void* h_slist_pop(HSlist *slist);
|
||||||
|
void* h_slist_drop(HSlist *slist);
|
||||||
void h_slist_push(HSlist *slist, void* item);
|
void h_slist_push(HSlist *slist, void* item);
|
||||||
bool h_slist_find(HSlist *slist, const void* item);
|
bool h_slist_find(HSlist *slist, const void* item);
|
||||||
HSlist* h_slist_remove_all(HSlist *slist, const void* item);
|
HSlist* h_slist_remove_all(HSlist *slist, const void* item);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue