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