make h_lrengine_step a void function again

This commit is contained in:
Sven M. Hallberg 2013-06-21 18:46:16 +02:00
parent bf3e3c162e
commit ec88580b22
4 changed files with 65 additions and 40 deletions

View file

@ -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) {
h_slist_push(engines, eng);
} else {
HParseResult *res = h_lrengine_result(eng);
if(res)
result = res;
}
// perform one step and add to list
h_lrengine_step(eng, act);
h_slist_push(engines, eng);
}
}
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)

View file

@ -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
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);
}
// 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 = 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)

View file

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

View file

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