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; ) {
|
||||
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);
|
||||
|
||||
// fork engine on conflicts
|
||||
|
|
@ -79,28 +93,13 @@ HParseResult *h_glr_parse(HAllocator* mm__, const HParser* parser, HInputStream*
|
|||
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) {
|
||||
// perform one step and add to list
|
||||
h_lrengine_step(eng, act);
|
||||
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
|
||||
HParseResult *res = h_lrengine_result(engine);
|
||||
if(res)
|
||||
result = res;
|
||||
}
|
||||
h_lrengine_step(engine, action);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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!
|
||||
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));
|
||||
|
||||
engine->table = table;
|
||||
engine->state = 0;
|
||||
engine->run = true;
|
||||
engine->left = h_slist_new(tarena);
|
||||
engine->right = h_slist_new(tarena);
|
||||
engine->state = 0;
|
||||
engine->arena = arena;
|
||||
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
|
||||
bool h_lrengine_step(HLREngine *engine, const HLRAction *action)
|
||||
static bool h_lrengine_step_(HLREngine *engine, const HLRAction *action)
|
||||
{
|
||||
// short-hand names
|
||||
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
|
||||
// follow a reduce. we can also assume no conflict follows for GLR if we
|
||||
// use LALR tables, because only terminal symbols (lookahead) get reduces.
|
||||
const HLRAction *next = h_lr_lookup(engine->table, engine->state, symbol);
|
||||
if(next) {
|
||||
assert(next->type == HLR_SHIFT);
|
||||
const HLRAction *shift = h_lr_lookup(engine->table, engine->state, symbol);
|
||||
if(shift == NULL)
|
||||
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, value);
|
||||
engine->state = next->nextstate;
|
||||
} else {
|
||||
// fallback
|
||||
h_slist_push(right, value);
|
||||
h_slist_push(right, symbol);
|
||||
}
|
||||
engine->state = shift->nextstate;
|
||||
|
||||
if(symbol == engine->table->start)
|
||||
return false; // reduced to start symbol; accept!
|
||||
} else {
|
||||
assert(action->type == HLR_SHIFT);
|
||||
h_slist_push(left, (void *)(uintptr_t)engine->state);
|
||||
|
|
@ -332,13 +332,18 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action)
|
|||
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)
|
||||
{
|
||||
// parsing was successful iff the start symbol is on top of the right stack
|
||||
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_drop(engine->right);
|
||||
// parsing was successful iff after a shift the engine is back in state 0
|
||||
if(engine->state == 0 && !h_slist_empty(engine->left)) {
|
||||
// on top of the stack is the start symbol's semantic value
|
||||
HParsedToken *tok = engine->left->head->elem;
|
||||
return make_result(engine->arena, tok);
|
||||
} else {
|
||||
return NULL;
|
||||
|
|
@ -356,7 +361,8 @@ HParseResult *h_lr_parse(HAllocator* mm__, const HParser* parser, HInputStream*
|
|||
HLREngine *engine = h_lrengine_new(arena, tarena, table);
|
||||
|
||||
// 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);
|
||||
if(!result)
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ typedef struct HLREnhGrammar_ {
|
|||
typedef struct HLREngine_ {
|
||||
const HLRTable *table;
|
||||
size_t state;
|
||||
bool run;
|
||||
|
||||
// stack layout:
|
||||
// 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_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_lr_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
|
||||
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
|
||||
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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue