diff --git a/.travis.yml b/.travis.yml
index b533da3191e75912e6d34f8c0bdd4a1212e684f9..a7b78e3780c699cfe601bc92665139917a882cac 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -92,12 +92,12 @@ matrix:
       env: BINDINGS=cpp CC=clang
 before_install:
   - sudo apt-get update -qq
-  - sudo apt-get install lcov
+  - sudo apt-get install -y lcov
   - gem install coveralls-lcov
   - if [ "$BINDINGS" != "none" ]; then sudo apt-get install -qq swig; fi
   - if [ "$BINDINGS" == "perl" ]; then sudo add-apt-repository ppa:dns/irc -y; sudo apt-get update -qq; sudo apt-get install -qq swig=2.0.8-1irc1~12.04; fi
   - if [ "$BINDINGS" == "python" ]; then sudo apt-get install -qq python-dev; fi
-  - if [ "$BINDINGS" == "dotnet" ]; then sudo add-apt-repository ppa:directhex/monoxide -y; sudo apt-get update -qq; sudo apt-get install -qq mono-devel mono-mcs nunit nunit-console; mozroots --import --sync; fi
+  - if [ "$BINDINGS" == "dotnet" ]; then sudo add-apt-repository ppa:directhex/monoxide -y; sudo apt-get update -qq; sudo apt-get install -y -qq mono-devel mono-mcs nunit nunit-console; mozroots --import --sync; fi
 install: true
 before_script:
   - if [ "$BINDINGS" == "php" ]; then phpenv config-add src/bindings/php/hammer.ini; fi
diff --git a/appveyor.yml b/appveyor.yml
index 2aef9c9423e10b6671bbddb86c4f159335b69f26..b0d87a79e5da3885c61d060c2a615cf3092ee22e 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -14,6 +14,5 @@ build_script:
     }
 - call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" %VCVARS_PLATFORM%
 - call tools\windows\build.bat
-# FIXME(windows) TODO(uucidl): reactivate examples
-# - call tools\windows\build_examples.bat
+- call tools\windows\build_examples.bat
 - exit /b 0
diff --git a/examples/grammar.c b/examples/grammar.c
index 7638fe99558149d9e2d47e5d1dc7f0299da189c1..a768060b3dd2ed1c751076427c8bd6459918f914 100644
--- a/examples/grammar.c
+++ b/examples/grammar.c
@@ -22,11 +22,12 @@
 const char *nonterminal_name(const HCFGrammar *g, const HCFChoice *nt) {
   // if user_data exists and is printable:
   if(nt->user_data != NULL && *(char*)(nt->user_data) > ' ' && *(char*)(nt->user_data) < 127) {
-    if(*(char*)(nt->user_data) != '0') {
+    char* user_str = (char*)(nt->user_data);
+    if(*user_str != '\0') {
       // user_data is a non-empty string
-      return nt->user_data;
+      return user_str;
     } else {
-      return nt->user_data+1;
+      return user_str+1;
     }
   }
   
diff --git a/src/datastructures.c b/src/datastructures.c
index af8477be36123a53506871827d4dae13d8c9002b..451afb94ec39932dfe1f8c58aa82c0777f73b011 100644
--- a/src/datastructures.c
+++ b/src/datastructures.c
@@ -52,14 +52,14 @@ HSlist* h_slist_copy(HSlist *slist) {
     h_slist_push(ret, head->elem);
     tail = ret->head;
     head = head->next;
-  }
-  while (head != NULL) {
-    // append head item to tail in a new node
-    HSlistNode *node = h_arena_malloc(slist->arena, sizeof(HSlistNode));
-    node->elem = head->elem;
-    node->next = NULL;
-    tail = tail->next = node;
-    head = head->next;
+    while (head != NULL) {
+      // append head item to tail in a new node
+      HSlistNode *node = h_arena_malloc(slist->arena, sizeof(HSlistNode));
+      node->elem = head->elem;
+      node->next = NULL;
+      tail = tail->next = node;
+      head = head->next;
+    }
   }
   return ret;
 }
diff --git a/src/parsers/choice.c b/src/parsers/choice.c
index dd3908ce93168f468ba6e1ff531a59476e404411..90c3662b515babe4a69b0e24dc146ebe1d0a647d 100644
--- a/src/parsers/choice.c
+++ b/src/parsers/choice.c
@@ -1,6 +1,20 @@
 #include <stdarg.h>
 #include "parser_internal.h"
 
+#if defined(__STDC_VERSION__) && (                                  \
+      (__STDC_VERSION__ >= 201112L && !defined(__STDC_NO_VLA__)) ||   \
+      (__STDC_VERSION__ >= 199901L) \
+    )
+#  define STACK_VLA(type,name,size) type name[size]
+#else
+#  if defined(_MSC_VER)
+#    include <malloc.h> // for _alloca
+#    define STACK_VLA(type,name,size) type* name = _alloca(size)
+#  else
+#    error "Missing VLA implementation for this compiler"
+#  endif
+#endif
+
 typedef struct {
   size_t len;
   HParser **p_array;
@@ -53,11 +67,14 @@ static void desugar_choice(HAllocator *mm__, HCFStack *stk__, void *env) {
 
 static bool choice_ctrvm(HRVMProg *prog, void* env) {
   HSequence *s = (HSequence*)env;
-  uint16_t gotos[s->len];
+  // NOTE(uucidl): stack allocation since this backend uses
+  // setjmp/longjmp for error handling.
+  STACK_VLA(uint16_t, gotos, s->len);
   for (size_t i=0; i<s->len; ++i) {
     uint16_t insn = h_rvm_insert_insn(prog, RVM_FORK, 0);
-    if (!h_compile_regex(prog, s->p_array[i]))
+    if (!h_compile_regex(prog, s->p_array[i])) {
       return false;
+    }
     gotos[i] = h_rvm_insert_insn(prog, RVM_GOTO, 65535);
     h_rvm_patch_arg(prog, insn, h_rvm_get_ip(prog));
   }
diff --git a/src/parsers/nothing.c b/src/parsers/nothing.c
index 0a60108bcc2c0fe69a656fb1cfb4f067ff290922..398432ef460897e7cbd254e9f4f28a86ccecd9d3 100644
--- a/src/parsers/nothing.c
+++ b/src/parsers/nothing.c
@@ -1,6 +1,8 @@
 #include "parser_internal.h"
 
-static HParseResult* parse_nothing() {
+static HParseResult* parse_nothing(void* x,HParseState* y) {
+  (void)(x);
+  (void)(y);
   // not a mistake, this parser always fails
   return NULL;
 }
diff --git a/src/registry.c b/src/registry.c
index d905320bbdf6131e5ab449c525086e4b1205a28b..8a079b5200f7415f878fa7f74fdaa181ee313669 100644
--- a/src/registry.c
+++ b/src/registry.c
@@ -15,10 +15,16 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-#include <search.h>
 #include <stdlib.h>
 #include "hammer.h"
 #include "internal.h"
+#include "tsearch.h"
+
+#if defined(_MSC_VER)
+#define h_strdup _strdup
+#else
+#define h_strdup strdup
+#endif
 
 typedef struct Entry_ {
   const char* name;
@@ -58,7 +64,7 @@ HTokenType h_allocate_token_type(const char* name) {
     return probe->value;
   } else {
     // new value
-    probe->name = strdup(probe->name); // drop ownership of name
+    probe->name = h_strdup(probe->name); // drop ownership of name
     probe->value = tt_next++;
     if ((probe->value - TT_START) >= tt_by_id_sz) {
       if (tt_by_id_sz == 0) {
diff --git a/src/search.h b/src/search.h
new file mode 100644
index 0000000000000000000000000000000000000000..8a94ab83d556944a0d0f022bac3d0c3f1f80c884
--- /dev/null
+++ b/src/search.h
@@ -0,0 +1,15 @@
+#if defined(_MSC_VER)
+/* find or insert datum into search tree */
+void *tsearch(const void *vkey, void **vrootp,
+              int (*compar)(const void *, const void *));
+
+/* delete node with given key */
+void * tdelete(const void *vkey, void **vrootp,
+               int (*compar)(const void *, const void *));
+
+/* Walk the nodes of a tree */
+void twalk(const void *vroot, void (*action)(const void *, VISIT, int));
+
+#else
+#include <search.h>
+#endif
diff --git a/src/tsearch.c b/src/tsearch.c
new file mode 100644
index 0000000000000000000000000000000000000000..154f87c43e0371ef9f8b623c757e39389c1d7829
--- /dev/null
+++ b/src/tsearch.c
@@ -0,0 +1,141 @@
+/*	$OpenBSD: tsearch.c,v 1.9 2015/08/20 21:49:29 deraadt Exp $	*/
+
+/*
+ * Tree search generalized from Knuth (6.2.2) Algorithm T just like
+ * the AT&T man page says.
+ *
+ * The node_t structure is for internal use only
+ *
+ * Written by reading the System V Interface Definition, not the code.
+ *
+ * Totally public domain.
+ */
+
+#include <stdlib.h>
+#include "tsearch.h"
+
+typedef struct node_t {
+    char	  *key;
+    struct node_t *left, *right;
+} node;
+
+/* find or insert datum into search tree */
+void *
+tsearch(const void *vkey, void **vrootp,
+    int (*compar)(const void *, const void *))
+{
+    node *q;
+    char *key = (char *)vkey;
+    node **rootp = (node **)vrootp;
+
+    if (rootp == (struct node_t **)0)
+	return ((void *)0);
+    while (*rootp != (struct node_t *)0) {	/* Knuth's T1: */
+	int r;
+
+	if ((r = (*compar)(key, (*rootp)->key)) == 0)	/* T2: */
+	    return ((void *)*rootp);		/* we found it! */
+	rootp = (r < 0) ?
+	    &(*rootp)->left :		/* T3: follow left branch */
+	    &(*rootp)->right;		/* T4: follow right branch */
+    }
+    q = malloc(sizeof(node));	/* T5: key not found */
+    if (q != (struct node_t *)0) {	/* make new node */
+	*rootp = q;			/* link new node to old */
+	q->key = key;			/* initialize new node */
+	q->left = q->right = (struct node_t *)0;
+    }
+    return ((void *)q);
+}
+
+/* delete node with given key */
+void *
+tdelete(const void *vkey, void **vrootp,
+    int (*compar)(const void *, const void *))
+{
+    node **rootp = (node **)vrootp;
+    char *key = (char *)vkey;
+    node *p = (node *)1;
+    node *q;
+    node *r;
+    int cmp;
+
+    if (rootp == (struct node_t **)0 || *rootp == (struct node_t *)0)
+	return ((struct node_t *)0);
+    while ((cmp = (*compar)(key, (*rootp)->key)) != 0) {
+	p = *rootp;
+	rootp = (cmp < 0) ?
+	    &(*rootp)->left :		/* follow left branch */
+	    &(*rootp)->right;		/* follow right branch */
+	if (*rootp == (struct node_t *)0)
+	    return ((void *)0);		/* key not found */
+    }
+    r = (*rootp)->right;			/* D1: */
+    if ((q = (*rootp)->left) == (struct node_t *)0)	/* Left (struct node_t *)0? */
+	q = r;
+    else if (r != (struct node_t *)0) {		/* Right link is null? */
+	if (r->left == (struct node_t *)0) {	/* D2: Find successor */
+	    r->left = q;
+	    q = r;
+	} else {			/* D3: Find (struct node_t *)0 link */
+	    for (q = r->left; q->left != (struct node_t *)0; q = r->left)
+		r = q;
+	    r->left = q->right;
+	    q->left = (*rootp)->left;
+	    q->right = (*rootp)->right;
+	}
+    }
+    free((struct node_t *) *rootp);	/* D4: Free node */
+    *rootp = q;				/* link parent to new node */
+    return(p);
+}
+
+/* Walk the nodes of a tree */
+static void
+trecurse(node *root, void (*action)(const void *, VISIT, int), int level)
+{
+    if (root->left == (struct node_t *)0 && root->right == (struct node_t *)0)
+	(*action)(root, leaf, level);
+    else {
+	(*action)(root, preorder, level);
+	if (root->left != (struct node_t *)0)
+	    trecurse(root->left, action, level + 1);
+	(*action)(root, postorder, level);
+	if (root->right != (struct node_t *)0)
+	    trecurse(root->right, action, level + 1);
+	(*action)(root, endorder, level);
+    }
+}
+
+/* Walk the nodes of a tree */
+void
+twalk(const void *vroot, void (*action)(const void *, VISIT, int))
+{
+    node *root = (node *)vroot;
+
+    if (root != (node *)0 && action != (void (*)(const void *, VISIT, int))0)
+	trecurse(root, action, 0);
+}
+
+/*	$OpenBSD: tfind.c,v 1.6 2014/03/16 18:38:30 guenther Exp $	*/
+
+/* find a node, or return 0 */
+void *
+tfind(const void *vkey, void * const *vrootp,
+    int (*compar)(const void *, const void *))
+{
+    char *key = (char *)vkey;
+    node **rootp = (node **)vrootp;
+
+    if (rootp == (struct node_t **)0)
+	return ((struct node_t *)0);
+    while (*rootp != (struct node_t *)0) {	/* T1: */
+	int r;
+	if ((r = (*compar)(key, (*rootp)->key)) == 0)	/* T2: */
+	    return (*rootp);		/* key found */
+	rootp = (r < 0) ?
+	    &(*rootp)->left :		/* T3: follow left branch */
+	    &(*rootp)->right;		/* T4: follow right branch */
+    }
+    return (node *)0;
+}
diff --git a/src/tsearch.h b/src/tsearch.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b297db7c7ea425f350f0d2c3350d55a630fb97b
--- /dev/null
+++ b/src/tsearch.h
@@ -0,0 +1,26 @@
+#ifndef HAMMER_TSEARCH__H
+#define HAMMER_TSEARCH__H
+
+#if defined(_MSC_VER)
+typedef enum { preorder, postorder, endorder, leaf } VISIT;
+
+/* find or insert datum into search tree */
+void *tsearch(const void *vkey, void **vrootp,
+              int (*compar)(const void *, const void *));
+
+/* delete node with given key */
+void * tdelete(const void *vkey, void **vrootp,
+               int (*compar)(const void *, const void *));
+
+/* Walk the nodes of a tree */
+void twalk(const void *vroot, void (*action)(const void *, VISIT, int));
+
+/* find a node, or return 0 */
+void *tfind(const void *vkey, void * const *vrootp,
+            int (*compar)(const void *, const void *));
+
+#else
+#include <search.h>
+#endif
+
+#endif /* HAMMER_TSEARCH__H */
diff --git a/tools/windows/clvars.bat b/tools/windows/clvars.bat
index 6e338b78f33a3b7c03538511c6af9005bca42133..23772f6b9547a6131d762d284e6211351f9bcbc0 100644
--- a/tools/windows/clvars.bat
+++ b/tools/windows/clvars.bat
@@ -7,6 +7,16 @@ set WARNINGS=-W4 -Wall -WX
 REM c4464 (relative include path contains '..')
 set WARNINGS=%WARNINGS% -wd4464
 
+REM c4189 (local variable is initialized but not referenced)
+set WARNINGS=%WARNINGS% -wd4189
+
+REM c4018/c4388 (signed/unsigned mismatch)
+REM basically useless. Complains about obviously correct code like:
+REM     uint8_t x = 60;
+REM     size_t i = 9;
+REM     i < x/8
+set WARNINGS=%WARNINGS% -wd4018 -wd4388
+
 REM c4457 (declaration shadowing function parameter)
 REM FIXME(windows) TODO(uucidl): remove occurence of c4457 and reactivate
 REM FIXME(windows) TODO(uucidl): remove occurence of c4456 and reactivate
diff --git a/tools/windows/hammer_lib_src_list b/tools/windows/hammer_lib_src_list
index a8a4dc4790e73ed6b64544c196416eaebc1e3db3..3602a4d525efef5a0c8745917f6b57684a971b9e 100644
--- a/tools/windows/hammer_lib_src_list
+++ b/tools/windows/hammer_lib_src_list
@@ -3,18 +3,24 @@ allocator.c
 benchmark.c
 bitreader.c 
 bitwriter.c 
-cfgrammar.c 
+cfgrammar.c
+datastructures.c
 desugar.c 
 glue.c 
 hammer.c 
 pprint.c
+registry.c
 system_allocator.c
+tsearch.c
 parsers/action.c 
 parsers/and.c 
 parsers/attr_bool.c 
+parsers/bind.c
+parsers/bits.c
 parsers/butnot.c 
 parsers/ch.c 
 parsers/charset.c 
+parsers/choice.c
 parsers/difference.c 
 parsers/end.c 
 parsers/endianness.c 
@@ -25,6 +31,7 @@ parsers/indirect.c
 parsers/int_range.c 
 parsers/many.c 
 parsers/not.c 
+parsers/nothing.c
 parsers/optional.c 
 parsers/permutation.c 	
 parsers/sequence.c