diff --git a/cfg_utils.py b/cfg_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a8becb68483392a0dc1d152f90581fdd1dab1a8
--- /dev/null
+++ b/cfg_utils.py
@@ -0,0 +1,59 @@
+
+
+class TreeNode:
+    def __init__(self, language_element, subnodes):
+        self.language_element = language_element
+        self.subnodes = subnodes
+
+    def __str__(self):
+        return str(self.language_element) + str(self.subnodes)
+
+
+
+
+# We define a context-free grammar as:
+# 1. A list of nonterminal symbols
+# 2. A list of terminal symbols
+# 3. A list of production rules
+# 4. A start symbol.
+
+
+
+
+
+
+# Once we have a CFG's definition, we can use Boltzmann sampling in order to generate random strings
+# from that CFG.
+
+
+
+# Furthermore, we also note that the description of a context-free grammar is *itself* context-free
+# so if we take the CFG-description grammar (BNF or something isomorphic to it), and use Boltzmann
+# sampling on *it*, we will generate candidate grammars; which will be used to test the FPGA-based
+# parser generator against a reference LR parser generator implementation. Naturally, this procedure 
+# may not produce LR-parseable grammars or even deterministic context-free grammars; but if the grammar
+# is rejected by both the FPGA parser generator and reference parser generator; this is fine, we just
+# move on to the next one.
+
+
+# Once we randomly generate a CFG, we randomly generate strings that are valid strings, but also
+# generate exemplars that are potentially *invalid* strings (both by mutating valid strings but
+# also by generating random sequences ab initio from the terminal symbols). The potentially invalid
+# strings are tested against the reference parser, those that are accidentally valid are discarded,
+# and those that are invalid are used in the automatic equivalence testing.
+
+
+# We fail our candidate parser generator if:
+#
+# 1. During the generation phase, it rejects a grammar the reference generator doesn't reject, or
+#    accepts a grammar the reference generator rejects.
+
+# 2. During the execution phase, it rejects a string the reference generated parser doesn't reject,
+#    or accepts a string the reference generated parser rejects.
+
+# 3. During the execution phase, it accepts a string that the reference generated parser accepts; but
+#    the parse tree it generates is not identical to the parse tree that the reference generated parser
+#    produced.
+
+
+
diff --git a/gearbox.py b/gearbox.py
index b8096789e476ab3aa8b4db4dac8093e441f43891..8f03f8a23a707ba7b3552714d8fd4cab11dbd392 100644
--- a/gearbox.py
+++ b/gearbox.py
@@ -19,43 +19,6 @@ class ArbitraryGearbox(Elaboratable): # non-registered
             write_ptr = Signal(range(len_storage))
             read_ptr = Signal(range(len_storage))
 
-            # we signal ready to upstream if and only if the skid buffer is empty
-            m.d.comb += self.upstream_ready_out.eq(~skid_buffer_frozen)
-
-
-            # should we capture a value in the skid buffer?
-            # we should if upstream has data for us *and* downstream cannot accept
-
-            # If we want to fill our skid buffer, we need:
-            # 1. valid input data       (upstream_valid_in   == 1)
-            # 2. a buffer that is empty (skid_buffer_frozen  == 0)
-            # 3. stalled downstream     (downstream_ready_in == 0)
-
-            with m.If(self.upstream_valid_in & (~skid_buffer_frozen)  & (~self.downstream_ready_in)):
-                m.d.sync += skid_buffer_frozen.eq(1)
-
-            # if downstream is accepting data again, we will flush our skid buffer
-            with m.If(self.downstream_ready_in == 1):
-                m.d.sync += skid_buffer_frozen.eq(0)
-
-
-            m.d.comb += self.downstream_valid_out.eq(self.upstream_valid_in | skid_buffer_frozen)
-
-
-            # data path
-
-            # always clock data into the skid buffer as long as the buffer isn't frozen
-
-            with m.If(skid_buffer_frozen == 0):
-                m.d.sync += skid_buffer.eq(self.upstream_data_in)
-
-            with m.If(skid_buffer_frozen == 1):
-                m.d.comb += self.downstream_data_out.eq(skid_buffer)
-
-            # NON registered
-            with m.Elif(self.upstream_valid_in == 1):
-                m.d.comb += self.downstream_data_out.eq(self.upstream_data_in)
-
             return m
 
 
diff --git a/python_arborist.py b/python_arborist.py
index 937c616cd1b9bd3e835ae027a853784515cd3219..1a540a2ae4d9ea432069ec85c30ded7d2727121a 100644
--- a/python_arborist.py
+++ b/python_arborist.py
@@ -379,6 +379,11 @@ def deserializer(serialized_array):
 
 
 
+def string_generator(grammar):
+
+
+
+def treechecker(derivation, parse_tree):