diff --git a/extra/state-tables/authors.txt b/extra/state-tables/authors.txt
new file mode 100644
index 0000000000..7c1b2f2279
--- /dev/null
+++ b/extra/state-tables/authors.txt
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/extra/state-tables/state-tables-tests.factor b/extra/state-tables/state-tables-tests.factor
new file mode 100644
index 0000000000..b46cc94266
--- /dev/null
+++ b/extra/state-tables/state-tables-tests.factor
@@ -0,0 +1,49 @@
+USING: kernel tables tools.test ;
+IN: tables.tests
+
+: test-table
+
+ "a" "c" "z" over set-entry
+ "a" "o" "y" over set-entry
+ "a" "l" "x" over set-entry
+ "b" "o" "y" over set-entry
+ "b" "l" "x" over set-entry
+ "b" "s" "u" over set-entry ;
+
+[
+ T{ table f
+ H{
+ { "a" H{ { "l" "x" } { "c" "z" } { "o" "y" } } }
+ { "b" H{ { "l" "x" } { "s" "u" } { "o" "y" } } }
+ }
+ H{ { "l" t } { "s" t } { "c" t } { "o" t } } }
+] [ test-table ] unit-test
+
+[ "x" t ] [ "a" "l" test-table get-entry ] unit-test
+[ "har" t ] [
+ "a" "z" "har" test-table [ set-entry ] keep
+ >r "a" "z" r> get-entry
+] unit-test
+
+: vector-test-table
+
+ "a" "c" "z" over add-value
+ "a" "c" "r" over add-value
+ "a" "o" "y" over add-value
+ "a" "l" "x" over add-value
+ "b" "o" "y" over add-value
+ "b" "l" "x" over add-value
+ "b" "s" "u" over add-value ;
+
+[
+T{ vector-table f
+ H{
+ { "a"
+ H{ { "l" "x" } { "c" V{ "z" "r" } } { "o" "y" } } }
+ { "b"
+ H{ { "l" "x" } { "s" "u" } { "o" "y" } } }
+ }
+ H{ { "l" t } { "s" t } { "c" t } { "o" t } }
+}
+] [ vector-test-table ] unit-test
+
diff --git a/extra/state-tables/state-tables.factor b/extra/state-tables/state-tables.factor
new file mode 100644
index 0000000000..9a04a5b74a
--- /dev/null
+++ b/extra/state-tables/state-tables.factor
@@ -0,0 +1,123 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces sequences vectors assocs accessors ;
+IN: state-tables
+
+TUPLE: table rows columns start-state final-states ;
+TUPLE: entry row-key column-key value ;
+
+GENERIC: add-entry ( entry table -- )
+
+: make-table ( class -- obj )
+ new
+ H{ } clone >>rows
+ H{ } clone >>columns
+ H{ } clone >>final-states ;
+
+: ( -- obj )
+ table make-table ;
+
+C: entry
+
+: (add-row) ( row-key table -- row )
+ 2dup rows>> at* [
+ 2nip
+ ] [
+ drop H{ } clone [ -rot rows>> set-at ] keep
+ ] if ;
+
+: add-row ( row-key table -- )
+ (add-row) drop ;
+
+: add-column ( column-key table -- )
+ t -rot columns>> set-at ;
+
+: set-row ( row row-key table -- )
+ rows>> set-at ;
+
+: lookup-row ( row-key table -- row/f ? )
+ rows>> at* ;
+
+: row-exists? ( row-key table -- ? )
+ lookup-row nip ;
+
+: lookup-column ( column-key table -- column/f ? )
+ columns>> at* ;
+
+: column-exists? ( column-key table -- ? )
+ lookup-column nip ;
+
+ERROR: no-row key ;
+ERROR: no-column key ;
+
+: get-row ( row-key table -- row )
+ dupd lookup-row [
+ nip
+ ] [
+ drop no-row
+ ] if ;
+
+: get-column ( column-key table -- column )
+ dupd lookup-column [
+ nip
+ ] [
+ drop no-column
+ ] if ;
+
+: get-entry ( row-key column-key table -- obj ? )
+ swapd lookup-row [
+ at*
+ ] [
+ 2drop f f
+ ] if ;
+
+: (set-entry) ( entry table -- value column-key row )
+ [ >r column-key>> r> add-column ] 2keep
+ dupd >r row-key>> r> (add-row)
+ >r [ value>> ] keep column-key>> r> ;
+
+: set-entry ( entry table -- )
+ (set-entry) set-at ;
+
+: delete-entry ( entry table -- )
+ >r [ column-key>> ] [ row-key>> ] bi r>
+ lookup-row [ delete-at ] [ 2drop ] if ;
+
+: swap-rows ( row-key1 row-key2 table -- )
+ [ tuck get-row >r get-row r> ] 3keep
+ >r >r rot r> r> [ set-row ] keep set-row ;
+
+: member?* ( obj obj -- bool )
+ 2dup = [ 2drop t ] [ member? ] if ;
+
+: find-by-column ( column-key data table -- seq )
+ swapd 2dup lookup-column 2drop
+ [
+ rows>> [
+ pick swap at* [
+ >r pick r> member?* [ , ] [ drop ] if
+ ] [
+ 2drop
+ ] if
+ ] assoc-each
+ ] { } make 2nip ;
+
+
+TUPLE: vector-table < table ;
+: ( -- obj )
+ vector-table make-table ;
+
+: add-hash-vector ( value key hash -- )
+ 2dup at* [
+ dup vector? [
+ 2nip push
+ ] [
+ V{ } clone [ push ] keep
+ -rot >r >r [ push ] keep r> r> set-at
+ ] if
+ ] [
+ drop set-at
+ ] if ;
+
+M: vector-table add-entry ( entry table -- )
+ (set-entry) add-hash-vector ;