From bf3e3c162e2bd199effd17412813d8271dba40ee Mon Sep 17 00:00:00 2001
From: "Sven M. Hallberg" <pesco@khjk.org>
Date: Fri, 21 Jun 2013 15:31:37 +0200
Subject: [PATCH] don't even touch the right stack on piggy-back shifts

---
 src/backends/lr.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/src/backends/lr.c b/src/backends/lr.c
index 03264b5c..33d597b8 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
-- 
GitLab