diff --git a/src/backends/lr.c b/src/backends/lr.c index 03264b5c3707a2179421b167a6ab435008ec6335..33d597b89a3a37e88735994c2567899083ab9a28 100644 --- a/src/backends/lr.c +++ b/src/backends/lr.c @@ -269,7 +269,6 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action) assert(action->type == HLR_SHIFT || action->type == HLR_REDUCE); if(action->type == HLR_REDUCE) { - assert(action->type == HLR_REDUCE); size_t len = action->production.length; HCFChoice *symbol = action->production.lhs; @@ -306,21 +305,24 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action) if(symbol->action) value = (HParsedToken *)symbol->action(make_result(arena, value)); - // push result (value, symbol) onto the right stack - h_slist_push(right, value); - h_slist_push(right, symbol); - // 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. - action = h_lr_lookup(engine->table, engine->state, symbol); - if(action == NULL) - return false; // no handle after reduce; terminate + 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); + } + } else { assert(action->type == HLR_SHIFT); - } - - // this could be the original action, or a shift piggy-backed onto reduce - if(action->type == HLR_SHIFT) { h_slist_push(left, (void *)(uintptr_t)engine->state); h_slist_drop(right); // symbol (discard) h_slist_push(left, h_slist_drop(right)); // semantic value