From ec88580b22866a65cf874c8b313ec2336eb0a061 Mon Sep 17 00:00:00 2001 From: "Sven M. Hallberg" <pesco@khjk.org> Date: Fri, 21 Jun 2013 18:46:16 +0200 Subject: [PATCH] make h_lrengine_step a void function again --- src/backends/glr.c | 51 +++++++++++++++++++++++++++++----------------- src/backends/lr.c | 48 ++++++++++++++++++++++++------------------- src/backends/lr.h | 3 ++- src/backends/lr0.c | 5 +++++ 4 files changed, 66 insertions(+), 41 deletions(-) diff --git a/src/backends/glr.c b/src/backends/glr.c index 2b4b974b..d460e8af 100644 --- a/src/backends/glr.c +++ b/src/backends/glr.c @@ -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) diff --git a/src/backends/lr.c b/src/backends/lr.c index 33d597b8..2603ff2a 100644 --- a/src/backends/lr.c +++ b/src/backends/lr.c @@ -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); - - // 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); - } + 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 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) diff --git a/src/backends/lr.h b/src/backends/lr.h index edf0871e..5e2f0329 100644 --- a/src/backends/lr.h +++ b/src/backends/lr.h @@ -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); diff --git a/src/backends/lr0.c b/src/backends/lr0.c index 67cf2aa0..9f350b63 100644 --- a/src/backends/lr0.c +++ b/src/backends/lr0.c @@ -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) -- GitLab