diff --git a/src/backends/llk.c b/src/backends/llk.c
index 27258e62db9ee53c75a0f19a7b4e0917d3a3f266..59ec790a367e1ea72ed1a427de76a2827329c3db 100644
--- a/src/backends/llk.c
+++ b/src/backends/llk.c
@@ -148,7 +148,7 @@ static void stringmap_merge(HHashSet *workset, HCFStringMap *dst, HCFStringMap *
   }
 }
 
-/* Generate entries for the production "A" in the given table row. */
+/* Generate entries for the productions of A in the given table row. */
 static int fill_table_row(size_t kmax, HCFGrammar *g, HCFStringMap *row,
                           const HCFChoice *A)
 {
@@ -162,8 +162,6 @@ static int fill_table_row(size_t kmax, HCFGrammar *g, HCFStringMap *row,
   // run until workset exhausted or kmax hit
   size_t k;
   for(k=1; k<=kmax; k++) {
-    printf("k=%lu\n", k); // XXX debug
-
     // allocate a fresh workset for the next round
     HHashSet *nextset = h_hashset_new(g->arena, h_eq_ptr, h_hash_ptr);
 
@@ -182,27 +180,11 @@ static int fill_table_row(size_t kmax, HCFGrammar *g, HCFStringMap *row,
         HCFStringMap *pred = h_predict(k, g, A, rhs);
         h_stringmap_replace(pred, NULL, rhs);
 
-        // XXX debug
-        printf("predict(");
-        h_pprint_sequence(stdout, g, rhs);
-        printf(") = ");
-        h_pprint_stringset(stdout, pred, 0);
-
         // merge predict set into the row
         // accumulates conflicts in new workset
         stringmap_merge(nextset, row, pred);
       }
     }
-    // XXX debug
-    printf("row(");
-    h_pprint_symbol(stdout, g, A);
-    printf(") = ");
-    h_pprint_stringset(stdout, row, 0);
-    if(h_stringmap_get(row, (uint8_t *)"a", 1, false)) {
-      printf("  a -> ");
-      h_pprint_sequence(stdout, g, h_stringmap_get(row, (uint8_t *)"a", 1, false));
-      printf("\n");
-    }
 
     // switch to the updated workset
     h_hashset_free(workset);
@@ -343,6 +325,9 @@ HParseResult *h_llk_parse(HAllocator* mm__, const HParser* parser, HInputStream*
       if(p == NULL)
         goto no_parse;
 
+      // an infinite loop case that shouldn't happen
+      assert(!p->items[0] || p->items[0] != x);
+
       // push production's rhs onto the stack (in reverse order)
       HCFChoice **s;
       for(s = p->items; *s; s++);
@@ -457,9 +442,9 @@ int test_llk(void)
   */
 
   HParser *X = h_optional(h_ch('x'));
-  //HParser *Y = h_epsilon_p(); //h_sequence(h_ch('y'), NULL);
-  HParser *A = h_sequence(X, h_ch('a'), NULL);
-  HParser *B = h_sequence(h_ch('b'), NULL);
+  HParser *Y = h_sequence(h_ch('y'), h_ch('y'), NULL);
+  HParser *A = h_sequence(X, Y, h_ch('a'), NULL);
+  HParser *B = h_sequence(Y, h_ch('b'), NULL);
   HParser *p = h_choice(A, B, NULL);
 
   HCFGrammar *g = h_cfgrammar(&system_allocator, p);
@@ -477,12 +462,12 @@ int test_llk(void)
   //printf("follow(C) = ");
   //h_pprint_stringset(stdout, h_follow(3, g, h_desugar(&system_allocator, c)), 0);
 
-  if(h_compile(p, PB_LLk, (void *)2)) {
+  if(h_compile(p, PB_LLk, (void *)3)) {
     fprintf(stderr, "does not compile\n");
     return 2;
   }
 
-  HParseResult *res = h_parse(p, (uint8_t *)"ab", 2);
+  HParseResult *res = h_parse(p, (uint8_t *)"xyya", 4);
   if(res)
     h_pprint(stdout, res->ast, 0, 2);
   else
diff --git a/src/cfgrammar.c b/src/cfgrammar.c
index d774dd0938d2168b640089c094e17614e40d9380..0ce3cbf2ff8046d93b1a1f70ffa4379521e1489e 100644
--- a/src/cfgrammar.c
+++ b/src/cfgrammar.c
@@ -248,12 +248,18 @@ void h_stringmap_put_char(HCFStringMap *m, uint8_t c, void *v)
 }
 
 // helper for h_stringmap_update
-static void *combine_stringmap(void *v1, void *v2)
+static void *combine_stringmap(void *v1, const void *v2)
 {
-  h_stringmap_update((HCFStringMap *)v1, (HCFStringMap *)v2);
-  return v1;
+  HCFStringMap *m1 = v1;
+  const HCFStringMap *m2 = v2;
+  if(!m1)
+    m1 = h_stringmap_new(m2->arena);
+  h_stringmap_update(m1, m2);
+
+  return m1;
 }
 
+/* Note: Does *not* reuse submaps from n in building m. */
 void h_stringmap_update(HCFStringMap *m, const HCFStringMap *n)
 {
   if(n->epsilon_branch)
@@ -456,7 +462,8 @@ static void remove_all_shorter(size_t k, HCFStringMap *m)
 }
 
 // h_follow adapted to the signature of StringSetFun
-static inline const HCFStringMap *h_follow_(size_t k, HCFGrammar *g, HCFChoice **s)
+static inline
+const HCFStringMap *h_follow_(size_t k, HCFGrammar *g, HCFChoice **s)
 {
   return h_follow(k, g, *s);
 }
@@ -532,6 +539,10 @@ HCFStringMap *h_predict(size_t k, HCFGrammar *g,
   //   { ab | a <- first_k(rhs), b <- follow_k(A), |ab|=k }
   
   const HCFStringMap *first_rhs = h_first_seq(k, g, rhs->items);
+
+  // casting the const off of A below. note: stringset_extend does
+  // not touch this argument, only passes it through to h_follow
+  // in this case, which accepts it, once again, as const.
   stringset_extend(g, ret, k, first_rhs, h_follow_, (HCFChoice **)&A);
 
   // make sure there are only strings of length _exactly_ k
diff --git a/src/datastructures.c b/src/datastructures.c
index 99b4ca5736e72b2bb84689e154be79f0397e94f8..a12707ef9758db93ad79dc052533b40cdd4edcbb 100644
--- a/src/datastructures.c
+++ b/src/datastructures.c
@@ -201,7 +201,7 @@ void h_hashtable_update(HHashTable *dst, const HHashTable *src) {
   }
 }
 
-void h_hashtable_merge(void *(*combine)(void *v1, void *v2),
+void h_hashtable_merge(void *(*combine)(void *v1, const void *v2),
 	HHashTable *dst, const HHashTable *src) {
   size_t i;
   HHashTableEntry *hte;
@@ -209,13 +209,9 @@ void h_hashtable_merge(void *(*combine)(void *v1, void *v2),
     for(hte = &src->contents[i]; hte; hte = hte->next) {
       if(hte->key == NULL)
         continue;
-      void *oldvalue = h_hashtable_get(dst, hte->key);
-      void *newvalue;
-      if(oldvalue)
-        newvalue = combine(oldvalue, hte->value);
-      else
-        newvalue = hte->value;
-      h_hashtable_put(dst, hte->key, newvalue);
+      void *dstvalue = h_hashtable_get(dst, hte->key);
+      void *srcvalue = hte->value;
+      h_hashtable_put(dst, hte->key, combine(dstvalue, srcvalue));
     }
   }
 }
diff --git a/src/internal.h b/src/internal.h
index 889e5c3b1c377d567a0d79fcc632d3dc8e8b36f7..7655afa0a8fc62416f5fb771b55bac0f86d7be07 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -255,7 +255,7 @@ HHashTable* h_hashtable_new(HArena *arena, HEqualFunc equalFunc, HHashFunc hashF
 void* h_hashtable_get(const HHashTable* ht, const void* key);
 void  h_hashtable_put(HHashTable* ht, const void* key, void* value);
 void  h_hashtable_update(HHashTable* dst, const HHashTable *src);
-void  h_hashtable_merge(void *(*combine)(void *v1, void *v2),
+void  h_hashtable_merge(void *(*combine)(void *v1, const void *v2),
                         HHashTable *dst, const HHashTable *src);
 int   h_hashtable_present(const HHashTable* ht, const void* key);
 void  h_hashtable_del(HHashTable* ht, const void* key);