make h_lrengine_step a void function again
This commit is contained in:
parent
bf3e3c162e
commit
ec88580b22
4 changed files with 65 additions and 40 deletions
|
|
@ -61,6 +61,20 @@ HParseResult *h_glr_parse(HAllocator* mm__, const HParser* parser, HInputStream*
|
||||||
for(HSlistNode **x = &engines->head; *x; ) {
|
for(HSlistNode **x = &engines->head; *x; ) {
|
||||||
HLREngine *engine = (*x)->elem;
|
HLREngine *engine = (*x)->elem;
|
||||||
|
|
||||||
|
// check for terminated engines
|
||||||
|
if(engine->run) {
|
||||||
|
x = &(*x)->next; // advance x with no change
|
||||||
|
} else {
|
||||||
|
*x = (*x)->next; // advance x, removing the current element
|
||||||
|
|
||||||
|
// check for parse success
|
||||||
|
HParseResult *res = h_lrengine_result(engine);
|
||||||
|
if(res)
|
||||||
|
result = res;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const HLRAction *action = h_lrengine_action(engine, stream);
|
const HLRAction *action = h_lrengine_action(engine, stream);
|
||||||
|
|
||||||
// fork engine on conflicts
|
// fork engine on conflicts
|
||||||
|
|
@ -79,28 +93,13 @@ HParseResult *h_glr_parse(HAllocator* mm__, const HParser* parser, HInputStream*
|
||||||
HLRAction *act = x->elem;
|
HLRAction *act = x->elem;
|
||||||
HLREngine *eng = fork_engine(engine);
|
HLREngine *eng = fork_engine(engine);
|
||||||
|
|
||||||
// perform one step; add engine to list if it wants to keep running
|
// perform one step and add to list
|
||||||
bool run = h_lrengine_step(eng, act);
|
h_lrengine_step(eng, act);
|
||||||
if(run) {
|
h_slist_push(engines, eng);
|
||||||
h_slist_push(engines, eng);
|
|
||||||
} else {
|
|
||||||
HParseResult *res = h_lrengine_result(eng);
|
|
||||||
if(res)
|
|
||||||
result = res;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool running = h_lrengine_step(engine, action);
|
h_lrengine_step(engine, action);
|
||||||
|
|
||||||
if(running) {
|
|
||||||
x = &(*x)->next; // go to next
|
|
||||||
} else {
|
|
||||||
*x = (*x)->next; // remove from list
|
|
||||||
HParseResult *res = h_lrengine_result(engine);
|
|
||||||
if(res)
|
|
||||||
result = res;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,6 +119,20 @@ HParserBackendVTable h__glr_backend_vtable = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// XXX TODO
|
||||||
|
// - eliminate right stack by always doing a shift after reduce
|
||||||
|
// (shift should always follow reduce because rightmost)
|
||||||
|
// - split tables into
|
||||||
|
// - one mapping input bytes to actions (shift or reduce or conflict)
|
||||||
|
// - one mapping reduced-to lhs nonterminals to shift states
|
||||||
|
// - can there still be conflicts here?
|
||||||
|
// - use HStringMap to represent lookahead sets and the "piggyback" table
|
||||||
|
// - implement engine merging
|
||||||
|
// - triggered when two enter the same state
|
||||||
|
// - old stacks (/engines?) saved
|
||||||
|
// - new common suffix stack created
|
||||||
|
// - when rewinding (during reduce), watch for empty stack -> demerge
|
||||||
|
|
||||||
|
|
||||||
// dummy!
|
// dummy!
|
||||||
int test_glr(void)
|
int test_glr(void)
|
||||||
|
|
|
||||||
|
|
@ -207,9 +207,10 @@ HLREngine *h_lrengine_new(HArena *arena, HArena *tarena, const HLRTable *table)
|
||||||
HLREngine *engine = h_arena_malloc(tarena, sizeof(HLREngine));
|
HLREngine *engine = h_arena_malloc(tarena, sizeof(HLREngine));
|
||||||
|
|
||||||
engine->table = table;
|
engine->table = table;
|
||||||
|
engine->state = 0;
|
||||||
|
engine->run = true;
|
||||||
engine->left = h_slist_new(tarena);
|
engine->left = h_slist_new(tarena);
|
||||||
engine->right = h_slist_new(tarena);
|
engine->right = h_slist_new(tarena);
|
||||||
engine->state = 0;
|
|
||||||
engine->arena = arena;
|
engine->arena = arena;
|
||||||
engine->tarena = tarena;
|
engine->tarena = tarena;
|
||||||
|
|
||||||
|
|
@ -255,7 +256,7 @@ const HLRAction *h_lrengine_action(HLREngine *engine, HInputStream *stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
// run LR parser for one round; returns false when finished
|
// run LR parser for one round; returns false when finished
|
||||||
bool h_lrengine_step(HLREngine *engine, const HLRAction *action)
|
static bool h_lrengine_step_(HLREngine *engine, const HLRAction *action)
|
||||||
{
|
{
|
||||||
// short-hand names
|
// short-hand names
|
||||||
HSlist *left = engine->left;
|
HSlist *left = engine->left;
|
||||||
|
|
@ -308,19 +309,18 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action)
|
||||||
// this is LR, building a right-most derivation bottom-up, so no reduce can
|
// this is LR, building a right-most derivation bottom-up, so no reduce can
|
||||||
// follow a reduce. we can also assume no conflict follows for GLR if we
|
// follow a reduce. we can also assume no conflict follows for GLR if we
|
||||||
// use LALR tables, because only terminal symbols (lookahead) get reduces.
|
// use LALR tables, because only terminal symbols (lookahead) get reduces.
|
||||||
const HLRAction *next = h_lr_lookup(engine->table, engine->state, symbol);
|
const HLRAction *shift = h_lr_lookup(engine->table, engine->state, symbol);
|
||||||
if(next) {
|
if(shift == NULL)
|
||||||
assert(next->type == HLR_SHIFT);
|
return false; // parse error
|
||||||
|
assert(shift->type == HLR_SHIFT);
|
||||||
|
|
||||||
// piggy-back the shift onto here, never touching the right stack
|
// piggy-back the shift right here, never touching the input
|
||||||
h_slist_push(left, (void *)(uintptr_t)engine->state);
|
h_slist_push(left, (void *)(uintptr_t)engine->state);
|
||||||
h_slist_push(left, value);
|
h_slist_push(left, value);
|
||||||
engine->state = next->nextstate;
|
engine->state = shift->nextstate;
|
||||||
} else {
|
|
||||||
// fallback
|
if(symbol == engine->table->start)
|
||||||
h_slist_push(right, value);
|
return false; // reduced to start symbol; accept!
|
||||||
h_slist_push(right, symbol);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
assert(action->type == HLR_SHIFT);
|
assert(action->type == HLR_SHIFT);
|
||||||
h_slist_push(left, (void *)(uintptr_t)engine->state);
|
h_slist_push(left, (void *)(uintptr_t)engine->state);
|
||||||
|
|
@ -332,13 +332,18 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run LR parser for one round; sets engine->run
|
||||||
|
void h_lrengine_step(HLREngine *engine, const HLRAction *action)
|
||||||
|
{
|
||||||
|
engine->run = h_lrengine_step_(engine, 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 after a shift the engine is back in state 0
|
||||||
if(h_slist_drop(engine->right) == engine->table->start) {
|
if(engine->state == 0 && !h_slist_empty(engine->left)) {
|
||||||
// next on the right stack is the start symbol's semantic value
|
// on top of the stack is the start symbol's semantic value
|
||||||
assert(!h_slist_empty(engine->right));
|
HParsedToken *tok = engine->left->head->elem;
|
||||||
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;
|
||||||
|
|
@ -356,7 +361,8 @@ HParseResult *h_lr_parse(HAllocator* mm__, const HParser* parser, HInputStream*
|
||||||
HLREngine *engine = h_lrengine_new(arena, tarena, table);
|
HLREngine *engine = h_lrengine_new(arena, tarena, table);
|
||||||
|
|
||||||
// iterate engine to completion
|
// iterate engine to completion
|
||||||
while(h_lrengine_step(engine, h_lrengine_action(engine, stream)));
|
while(engine->run)
|
||||||
|
h_lrengine_step(engine, h_lrengine_action(engine, stream));
|
||||||
|
|
||||||
HParseResult *result = h_lrengine_result(engine);
|
HParseResult *result = h_lrengine_result(engine);
|
||||||
if(!result)
|
if(!result)
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ typedef struct HLREnhGrammar_ {
|
||||||
typedef struct HLREngine_ {
|
typedef struct HLREngine_ {
|
||||||
const HLRTable *table;
|
const HLRTable *table;
|
||||||
size_t state;
|
size_t state;
|
||||||
|
bool run;
|
||||||
|
|
||||||
// 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)
|
||||||
|
|
@ -128,7 +129,7 @@ void h_lalr_free(HParser *parser);
|
||||||
|
|
||||||
const HLRAction *h_lr_lookup(const HLRTable *table, size_t state, const HCFChoice *symbol);
|
const HLRAction *h_lr_lookup(const HLRTable *table, size_t state, const HCFChoice *symbol);
|
||||||
const HLRAction *h_lrengine_action(HLREngine *engine, HInputStream *stream);
|
const HLRAction *h_lrengine_action(HLREngine *engine, HInputStream *stream);
|
||||||
bool h_lrengine_step(HLREngine *engine, const HLRAction *action);
|
void h_lrengine_step(HLREngine *engine, const HLRAction *action);
|
||||||
HParseResult *h_lrengine_result(HLREngine *engine);
|
HParseResult *h_lrengine_result(HLREngine *engine);
|
||||||
HParseResult *h_lr_parse(HAllocator* mm__, const HParser* parser, HInputStream* stream);
|
HParseResult *h_lr_parse(HAllocator* mm__, const HParser* parser, HInputStream* stream);
|
||||||
HParseResult *h_glr_parse(HAllocator* mm__, const HParser* parser, HInputStream* stream);
|
HParseResult *h_glr_parse(HAllocator* mm__, const HParser* parser, HInputStream* stream);
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,11 @@ HLRTable *h_lr0_table(HCFGrammar *g, const HLRDFA *dfa)
|
||||||
// remember start symbol
|
// remember start symbol
|
||||||
table->start = g->start;
|
table->start = g->start;
|
||||||
|
|
||||||
|
// add dummy shift entry for the start symbol so h_lrengine_step can always
|
||||||
|
// find a shift.
|
||||||
|
// NB: nextstate=0 is used for the "victory condition" by h_lrengine_result.
|
||||||
|
h_hashtable_put(table->rows[0], g->start, h_shift_action(arena, 0));
|
||||||
|
|
||||||
// add shift entries
|
// add shift entries
|
||||||
for(HSlistNode *x = dfa->transitions->head; x; x = x->next) {
|
for(HSlistNode *x = dfa->transitions->head; x; x = x->next) {
|
||||||
// for each transition x-A->y, add "shift, goto y" to table entry (x,A)
|
// for each transition x-A->y, add "shift, goto y" to table entry (x,A)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue