From b1e8e297740256e44233837c6aff309369608c23 Mon Sep 17 00:00:00 2001
From: "Sven M. Hallberg" <pesco@khjk.org>
Date: Thu, 20 Jun 2013 11:05:57 +0200
Subject: [PATCH] add engine forking

---
 src/backends/glr.c   | 55 ++++++++++++++++++++++++++++++++++++++++++--
 src/backends/lr.c    | 12 +++++-----
 src/backends/lr.h    |  2 +-
 src/datastructures.c | 10 ++++++++
 src/internal.h       |  1 +
 5 files changed, 71 insertions(+), 9 deletions(-)

diff --git a/src/backends/glr.c b/src/backends/glr.c
index 429d06b1..2b4b974b 100644
--- a/src/backends/glr.c
+++ b/src/backends/glr.c
@@ -1,3 +1,4 @@
+#include <assert.h>
 #include "lr.h"
 
 
@@ -23,6 +24,26 @@ void h_glr_free(HParser *parser)
 
 /* GLR driver */
 
+HLREngine *fork_engine(const HLREngine *engine)
+{
+  HLREngine *eng2 = h_arena_malloc(engine->tarena, sizeof(HLREngine));
+  eng2->table = engine->table;
+  eng2->state = engine->state;
+
+  // shallow-copy the stacks
+  // this works because h_slist_push and h_slist_pop never modify
+  // the underlying structure of HSlistNodes, only the head pointer.
+  // in fact, this gives us prefix sharing for free.
+  eng2->left = h_arena_malloc(engine->tarena, sizeof(HSlist));
+  eng2->right = h_arena_malloc(engine->tarena, sizeof(HSlist));
+  *eng2->left = *engine->left;
+  *eng2->right = *engine->right;
+
+  eng2->arena = engine->arena;
+  eng2->tarena = engine->tarena;
+  return eng2;
+}
+
 HParseResult *h_glr_parse(HAllocator* mm__, const HParser* parser, HInputStream* stream)
 {
   HLRTable *table = parser->backend_data;
@@ -41,14 +62,44 @@ HParseResult *h_glr_parse(HAllocator* mm__, const HParser* parser, HInputStream*
       HLREngine *engine = (*x)->elem;
 
       const HLRAction *action = h_lrengine_action(engine, stream);
-      // XXX handle conflicts -> fork engine
+
+      // fork engine on conflicts
+      if(action && action->type == HLR_CONFLICT) {
+        const HSlist *branches = action->branches;
+
+        // there should be at least two conflicting actions
+        assert(branches->head);
+        assert(branches->head->next);
+
+        // save first action for use with old engine below
+        action = branches->head->elem;
+
+        // fork a new engine for all the other actions
+        for(HSlistNode *x=branches->head->next; x; x=x->next) {
+          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;
+          }
+        } 
+      }
+
       bool running = h_lrengine_step(engine, action);
 
       if(running) {
         x = &(*x)->next;    // go to next
       } else {
         *x = (*x)->next;    // remove from list
-        result = h_lrengine_result(engine);
+        HParseResult *res = h_lrengine_result(engine);
+        if(res)
+          result = res;
       }
     }
   }
diff --git a/src/backends/lr.c b/src/backends/lr.c
index 4ab53bce..1ea6a395 100644
--- a/src/backends/lr.c
+++ b/src/backends/lr.c
@@ -270,8 +270,8 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action)
 
   if(action->type == HLR_SHIFT) {
     h_slist_push(left, (void *)(uintptr_t)engine->state);
-    h_slist_pop(right);                       // symbol (discard)
-    h_slist_push(left, h_slist_pop(right));   // semantic value
+    h_slist_drop(right);                      // symbol (discard)
+    h_slist_push(left, h_slist_drop(right));   // semantic value
     engine->state = action->nextstate;
   } else {
     assert(action->type == HLR_REDUCE);
@@ -286,8 +286,8 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action)
     // pull values off the left stack, rewinding state accordingly
     HParsedToken *v = NULL;
     for(size_t i=0; i<len; i++) {
-      v = h_slist_pop(left);
-      engine->state = (uintptr_t)h_slist_pop(left);
+      v = h_slist_drop(left);
+      engine->state = (uintptr_t)h_slist_drop(left);
 
       // collect values in result sequence
       value->seq->elements[len-1-i] = v;
@@ -322,10 +322,10 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action)
 HParseResult *h_lrengine_result(HLREngine *engine)
 {
   // parsing was successful iff the start symbol is on top of the right stack
-  if(h_slist_pop(engine->right) == engine->table->start) {
+  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_pop(engine->right);
+    HParsedToken *tok = h_slist_drop(engine->right);
     return make_result(engine->arena, tok);
   } else {
     return NULL;
diff --git a/src/backends/lr.h b/src/backends/lr.h
index f766d5b7..edf0871e 100644
--- a/src/backends/lr.h
+++ b/src/backends/lr.h
@@ -67,6 +67,7 @@ typedef struct HLREnhGrammar_ {
 
 typedef struct HLREngine_ {
   const HLRTable *table;
+  size_t state;
 
   // stack layout:
   // on the left stack, we put pairs:  (saved state, semantic value)
@@ -74,7 +75,6 @@ typedef struct HLREngine_ {
   HSlist *left;     // left stack; reductions happen here
   HSlist *right;    // right stack; input appears here
 
-  size_t state;
   HArena *arena;    // will hold the results
   HArena *tarena;   // tmp, deleted after parse
 } HLREngine;
diff --git a/src/datastructures.c b/src/datastructures.c
index 075b966b..94bc9015 100644
--- a/src/datastructures.c
+++ b/src/datastructures.c
@@ -62,6 +62,16 @@ HSlist* h_slist_copy(HSlist *slist) {
   return ret;
 }
 
+// like h_slist_pop, but does not deallocate the head node
+void* h_slist_drop(HSlist *slist) {
+  HSlistNode *head = slist->head;
+  if (!head)
+    return NULL;
+  void* ret = head->elem;
+  slist->head = head->next;
+  return ret;
+}
+
 void* h_slist_pop(HSlist *slist) {
   HSlistNode *head = slist->head;
   if (!head)
diff --git a/src/internal.h b/src/internal.h
index d8b221a7..a897e9fc 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -248,6 +248,7 @@ void h_carray_append(HCountedArray *array, void* item);
 HSlist* h_slist_new(HArena *arena);
 HSlist* h_slist_copy(HSlist *slist);
 void* h_slist_pop(HSlist *slist);
+void* h_slist_drop(HSlist *slist);
 void h_slist_push(HSlist *slist, void* item);
 bool h_slist_find(HSlist *slist, const void* item);
 HSlist* h_slist_remove_all(HSlist *slist, const void* item);
-- 
GitLab