From 571b51917e4bf9d19f679e7be232001f0883a1e5 Mon Sep 17 00:00:00 2001
From: "Meredith L. Patterson" <mlp@upstandinghackers.com>
Date: Sun, 7 Dec 2014 23:15:09 +0100
Subject: [PATCH] core library builds in VS2013, but test suite crashes in glib
 during h_put_value

---
 hammer.def                      |  79 ++++++++++++
 hammer.sln                      |  38 ++++++
 hammer.vcxproj                  | 210 +++++++++++++++++++++++++++++++
 hammer.vcxproj.filters          | 215 ++++++++++++++++++++++++++++++++
 src/allocator.h                 |  10 +-
 src/backends/contextfree.h      |  49 +++++++-
 src/backends/glr.c              |   4 +
 src/backends/lalr.c             |  14 ++-
 src/backends/lr.c               |   4 +
 src/backends/lr0.c              |   4 +
 src/backends/packrat.c          |  14 ++-
 src/backends/regex.c            |   2 +-
 src/benchmark.c                 |  85 ++++++++++++-
 src/bitreader.c                 |   1 -
 src/bitwriter.c                 |   1 -
 src/cfgrammar.c                 |   4 +
 src/cfgrammar.h                 |   9 ++
 src/datastructures.c            |   4 +
 src/hammer-test.sln             |  22 ++++
 src/hammer-test.vcxproj         |  88 +++++++++++++
 src/hammer-test.vcxproj.filters |  45 +++++++
 src/hammer.c                    |   1 -
 src/hammer.h                    |  21 +++-
 src/internal.h                  |  60 ++++++++-
 src/msvc/tsearch.c              | 114 +++++++++++++++++
 src/msvc/tsearch.h              |  14 +++
 src/parsers/choice.c            |   5 +
 src/parsers/many.c              |   2 +-
 src/parsers/nothing.c           |   2 +-
 src/parsers/parser_internal.h   |  12 ++
 src/pprint.c                    |  34 +++++
 src/registry.c                  |   4 +
 src/system_allocator.c          |  31 ++++-
 src/test_suite.h                |   1 +
 34 files changed, 1177 insertions(+), 26 deletions(-)
 create mode 100644 hammer.def
 create mode 100644 hammer.sln
 create mode 100644 hammer.vcxproj
 create mode 100644 hammer.vcxproj.filters
 create mode 100644 src/hammer-test.sln
 create mode 100644 src/hammer-test.vcxproj
 create mode 100644 src/hammer-test.vcxproj.filters
 create mode 100644 src/msvc/tsearch.c
 create mode 100644 src/msvc/tsearch.h

diff --git a/hammer.def b/hammer.def
new file mode 100644
index 00000000..61b1b2e8
--- /dev/null
+++ b/hammer.def
@@ -0,0 +1,79 @@
+LIBRARY		HAMMER
+EXPORTS
+	h_parse
+	h_token
+	h_ch
+	h_ch_range
+	h_int_range
+	h_bits
+	h_int64
+	h_int32
+	h_int16
+	h_int8
+	h_uint64
+	h_uint32
+	h_uint16
+	h_uint8
+	h_whitespace
+	h_left
+	h_right
+	h_middle
+	h_action
+	h_in
+	h_not_in
+	h_end_p
+	h_nothing_p
+	h_sequence
+	h_choice
+	h_permutation
+	h_butnot
+	h_difference
+	h_xor
+	h_many
+	h_many1
+	h_repeat_n
+	h_optional
+	h_ignore
+	h_sepBy
+	h_sepBy1
+	h_epsilon_p
+	h_length_value
+	h_attr_bool
+	h_and
+	h_not
+	h_indirect
+	h_bind_indirect
+	h_with_endianness
+	h_put_value
+	h_get_value
+	h_parse_result_free
+	h_write_result_unamb
+	h_pprint
+	h_compile
+	h_bit_writer_new
+	h_bit_writer_put
+	h_bit_writer_get_buffer
+	h_bit_writer_free
+	h_act_first
+	h_act_second
+	h_act_last
+	h_act_flatten
+	h_act_ignore
+	h_benchmark
+	h_benchmark_report
+	h_allocate_token_type
+	h_get_token_type_number
+	h_get_token_type_name
+	h_read_bits			
+	system_allocator	DATA
+	h_desugar			
+	h_hashtable_present	
+	h_stringmap_present 
+	h_cfgrammar			
+	h_first				
+	h_follow			
+	h_arena_malloc		
+	h_delete_arena		
+	h_allocator_stats	
+	h_carray_new_sized	
+	h_carray_append
\ No newline at end of file
diff --git a/hammer.sln b/hammer.sln
new file mode 100644
index 00000000..db7dd754
--- /dev/null
+++ b/hammer.sln
@@ -0,0 +1,38 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30723.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hammer", "hammer.vcxproj", "{E615CCA5-FB3C-46B6-898E-6CCBF0114E33}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hammer-test", "..\hammer-test\hammer-test.vcxproj", "{0C6BD1ED-CA4C-40FD-BD46-0774C22A76ED}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Debug|x64 = Debug|x64
+		Release|Win32 = Release|Win32
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{E615CCA5-FB3C-46B6-898E-6CCBF0114E33}.Debug|Win32.ActiveCfg = Debug|Win32
+		{E615CCA5-FB3C-46B6-898E-6CCBF0114E33}.Debug|Win32.Build.0 = Debug|Win32
+		{E615CCA5-FB3C-46B6-898E-6CCBF0114E33}.Debug|x64.ActiveCfg = Debug|x64
+		{E615CCA5-FB3C-46B6-898E-6CCBF0114E33}.Debug|x64.Build.0 = Debug|x64
+		{E615CCA5-FB3C-46B6-898E-6CCBF0114E33}.Release|Win32.ActiveCfg = Release|Win32
+		{E615CCA5-FB3C-46B6-898E-6CCBF0114E33}.Release|Win32.Build.0 = Release|Win32
+		{E615CCA5-FB3C-46B6-898E-6CCBF0114E33}.Release|x64.ActiveCfg = Release|x64
+		{E615CCA5-FB3C-46B6-898E-6CCBF0114E33}.Release|x64.Build.0 = Release|x64
+		{0C6BD1ED-CA4C-40FD-BD46-0774C22A76ED}.Debug|Win32.ActiveCfg = Debug|Win32
+		{0C6BD1ED-CA4C-40FD-BD46-0774C22A76ED}.Debug|Win32.Build.0 = Debug|Win32
+		{0C6BD1ED-CA4C-40FD-BD46-0774C22A76ED}.Debug|x64.ActiveCfg = Debug|x64
+		{0C6BD1ED-CA4C-40FD-BD46-0774C22A76ED}.Debug|x64.Build.0 = Debug|x64
+		{0C6BD1ED-CA4C-40FD-BD46-0774C22A76ED}.Release|Win32.ActiveCfg = Release|Win32
+		{0C6BD1ED-CA4C-40FD-BD46-0774C22A76ED}.Release|Win32.Build.0 = Release|Win32
+		{0C6BD1ED-CA4C-40FD-BD46-0774C22A76ED}.Release|x64.ActiveCfg = Release|x64
+		{0C6BD1ED-CA4C-40FD-BD46-0774C22A76ED}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/hammer.vcxproj b/hammer.vcxproj
new file mode 100644
index 00000000..c000bcb6
--- /dev/null
+++ b/hammer.vcxproj
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{E615CCA5-FB3C-46B6-898E-6CCBF0114E33}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <TargetExt>.dll</TargetExt>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <TargetExt>.dll</TargetExt>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <TargetExt>.dll</TargetExt>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>NotSet</SubSystem>
+      <ModuleDefinitionFile>hammer.def</ModuleDefinitionFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;COMPILING_DLL=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>NotSet</SubSystem>
+      <ModuleDefinitionFile>hammer.def</ModuleDefinitionFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ModuleDefinitionFile>hammer.def</ModuleDefinitionFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;COMPILING_DLL=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ModuleDefinitionFile>hammer.def</ModuleDefinitionFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="src\allocator.c" />
+    <ClCompile Include="src\backends\glr.c" />
+    <ClCompile Include="src\backends\lalr.c" />
+    <ClCompile Include="src\backends\llk.c" />
+    <ClCompile Include="src\backends\lr.c" />
+    <ClCompile Include="src\backends\lr0.c" />
+    <ClCompile Include="src\backends\packrat.c" />
+    <ClCompile Include="src\backends\regex.c" />
+    <ClCompile Include="src\benchmark.c" />
+    <ClCompile Include="src\bitreader.c" />
+    <ClCompile Include="src\bitwriter.c" />
+    <ClCompile Include="src\cfgrammar.c" />
+    <ClCompile Include="src\datastructures.c" />
+    <ClCompile Include="src\desugar.c" />
+    <ClCompile Include="src\glue.c" />
+    <ClCompile Include="src\hammer.c" />
+    <ClCompile Include="src\msvc\tsearch.c" />
+    <ClCompile Include="src\parsers\action.c" />
+    <ClCompile Include="src\parsers\and.c" />
+    <ClCompile Include="src\parsers\attr_bool.c" />
+    <ClCompile Include="src\parsers\bits.c" />
+    <ClCompile Include="src\parsers\butnot.c" />
+    <ClCompile Include="src\parsers\ch.c" />
+    <ClCompile Include="src\parsers\charset.c" />
+    <ClCompile Include="src\parsers\choice.c" />
+    <ClCompile Include="src\parsers\difference.c" />
+    <ClCompile Include="src\parsers\end.c" />
+    <ClCompile Include="src\parsers\endianness.c" />
+    <ClCompile Include="src\parsers\epsilon.c" />
+    <ClCompile Include="src\parsers\ignore.c" />
+    <ClCompile Include="src\parsers\ignoreseq.c" />
+    <ClCompile Include="src\parsers\indirect.c" />
+    <ClCompile Include="src\parsers\int_range.c" />
+    <ClCompile Include="src\parsers\many.c" />
+    <ClCompile Include="src\parsers\not.c" />
+    <ClCompile Include="src\parsers\nothing.c" />
+    <ClCompile Include="src\parsers\optional.c" />
+    <ClCompile Include="src\parsers\permutation.c" />
+    <ClCompile Include="src\parsers\sequence.c" />
+    <ClCompile Include="src\parsers\token.c" />
+    <ClCompile Include="src\parsers\unimplemented.c" />
+    <ClCompile Include="src\parsers\value.c" />
+    <ClCompile Include="src\parsers\whitespace.c" />
+    <ClCompile Include="src\parsers\xor.c" />
+    <ClCompile Include="src\pprint.c" />
+    <ClCompile Include="src\registry.c" />
+    <ClCompile Include="src\system_allocator.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="examples\dns.h" />
+    <ClInclude Include="examples\dns_common.h" />
+    <ClInclude Include="jni\jhammer.h" />
+    <ClInclude Include="src\allocator.h" />
+    <ClInclude Include="src\backends\contextfree.h" />
+    <ClInclude Include="src\backends\lr.h" />
+    <ClInclude Include="src\backends\regex.h" />
+    <ClInclude Include="src\bindings\cpp\hammer\hammer.hpp" />
+    <ClInclude Include="src\bindings\cpp\hammer\hammer_test.hpp" />
+    <ClInclude Include="src\cfgrammar.h" />
+    <ClInclude Include="src\glue.h" />
+    <ClInclude Include="src\hammer.h" />
+    <ClInclude Include="src\internal.h" />
+    <ClInclude Include="src\msvc\tsearch.h" />
+    <ClInclude Include="src\parsers\parser_internal.h" />
+    <ClInclude Include="src\test_suite.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="hammer.def" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/hammer.vcxproj.filters b/hammer.vcxproj.filters
new file mode 100644
index 00000000..6870cac6
--- /dev/null
+++ b/hammer.vcxproj.filters
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="src\allocator.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\benchmark.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\bitreader.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\bitwriter.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\cfgrammar.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\datastructures.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\desugar.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\glue.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\hammer.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\pprint.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\registry.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\system_allocator.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\backends\glr.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\backends\lalr.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\backends\llk.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\backends\lr.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\backends\lr0.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\backends\packrat.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\backends\regex.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\action.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\and.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\attr_bool.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\bits.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\butnot.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\ch.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\charset.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\choice.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\difference.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\end.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\endianness.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\epsilon.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\ignore.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\ignoreseq.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\indirect.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\int_range.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\many.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\not.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\nothing.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\optional.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\permutation.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\sequence.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\token.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\unimplemented.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\value.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\whitespace.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\parsers\xor.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\msvc\tsearch.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="examples\dns.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="examples\dns_common.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="jni\jhammer.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\allocator.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\cfgrammar.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\glue.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\hammer.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\internal.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\test_suite.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\backends\contextfree.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\backends\lr.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\backends\regex.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\bindings\cpp\hammer\hammer.hpp">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\bindings\cpp\hammer\hammer_test.hpp">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\parsers\parser_internal.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="src\msvc\tsearch.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="hammer.def">
+      <Filter>Source Files</Filter>
+    </None>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/allocator.h b/src/allocator.h
index 803d89fe..592a1e5c 100644
--- a/src/allocator.h
+++ b/src/allocator.h
@@ -19,6 +19,12 @@
 #define HAMMER_ALLOCATOR__H__
 #include <sys/types.h>
 
+#ifdef _MSC_VER
+#define EXPORT __declspec(dllexport)
+#else
+#define EXPORT __attribute__ ((visibility ("default")))
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -33,7 +39,9 @@ typedef struct HAllocator_ {
 typedef struct HArena_ HArena ; // hidden implementation
 
 HArena *h_new_arena(HAllocator* allocator, size_t block_size); // pass 0 for default...
-#ifndef SWIG
+#ifdef _MSC_VER
+void* h_arena_malloc(HArena *arena, size_t count);
+#elif !defined(SWIG)
 void* h_arena_malloc(HArena *arena, size_t count) __attribute__(( malloc, alloc_size(2) ));
 #else
 void* h_arena_malloc(HArena *arena, size_t count);
diff --git a/src/backends/contextfree.h b/src/backends/contextfree.h
index ab04ab52..2c0006c3 100644
--- a/src/backends/contextfree.h
+++ b/src/backends/contextfree.h
@@ -21,11 +21,20 @@ struct HCFStack_ {
 };
 
 #ifndef UNUSED
+#ifndef _MSC_VER
 #define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
 #endif
 
+#ifndef _MSC_VER
 static inline HCFChoice* h_cfstack_new_choice_raw(HAllocator *mm__, HCFStack *stk__) UNUSED;
 static inline void h_cfstack_begin_choice(HAllocator *mm__, HCFStack *stk__) UNUSED;
+#else
+static __inline HCFChoice* h_cfstack_new_choice_raw(HAllocator *mm__, HCFStack *stk__) UNUSED;
+static __inline void h_cfstack_begin_choice(HAllocator *mm__, HCFStack *stk__) UNUSED;
+#endif
 static HCFStack* h_cfstack_new(HAllocator *mm__) UNUSED; 
 static HCFStack* h_cfstack_new(HAllocator *mm__) {
   HCFStack *stack = h_new(HCFStack, 1);
@@ -43,8 +52,13 @@ static void h_cfstack_free(HAllocator *mm__, HCFStack *stk__) {
   h_free(stk__);
 }
 
+#ifndef _MSC_VER
 static inline void h_cfstack_add_to_seq(HAllocator *mm__, HCFStack *stk__, HCFChoice *item) UNUSED;
 static inline void h_cfstack_add_to_seq(HAllocator *mm__, HCFStack *stk__, HCFChoice *item) {
+#else
+static __inline void h_cfstack_add_to_seq(HAllocator *mm__, HCFStack *stk__, HCFChoice *item) UNUSED;
+static __inline void h_cfstack_add_to_seq(HAllocator *mm__, HCFStack *stk__, HCFChoice *item) {
+#endif
   HCFChoice *cur_top = stk__->stack[stk__->count-1];
   assert(cur_top->type == HCF_CHOICE);
   assert(cur_top->seq[0] != NULL); // There must be at least one sequence...
@@ -64,7 +78,11 @@ static inline void h_cfstack_add_to_seq(HAllocator *mm__, HCFStack *stk__, HCFCh
   }
 }
 
+#ifndef _MSC_VER
 static inline HCFChoice* h_cfstack_new_choice_raw(HAllocator *mm__, HCFStack *stk__) {
+#else
+static __inline HCFChoice* h_cfstack_new_choice_raw(HAllocator *mm__, HCFStack *stk__) {
+#endif
   HCFChoice *ret = stk__->prealloc? stk__->prealloc : h_new(HCFChoice, 1);
   stk__->prealloc = NULL;
 
@@ -80,28 +98,43 @@ static inline HCFChoice* h_cfstack_new_choice_raw(HAllocator *mm__, HCFStack *st
   return ret;
 }
 
+#ifndef _MSC_VER
 static inline void h_cfstack_add_charset(HAllocator *mm__, HCFStack *stk__, HCharset charset) {
+#else
+static __inline void h_cfstack_add_charset(HAllocator *mm__, HCFStack *stk__, HCharset charset) {
+#endif
   HCFChoice *ni = h_cfstack_new_choice_raw(mm__, stk__);
   ni->type = HCF_CHARSET;
   ni->charset = charset;
   stk__->last_completed = ni;
 }
 
-
+#ifndef _MSC_VER
 static inline void h_cfstack_add_char(HAllocator *mm__, HCFStack *stk__, uint8_t chr) {
+#else
+static __inline void h_cfstack_add_char(HAllocator *mm__, HCFStack *stk__, uint8_t chr) {
+#endif
   HCFChoice *ni = h_cfstack_new_choice_raw(mm__, stk__);
   ni->type = HCF_CHAR;
   ni->chr = chr;
   stk__->last_completed = ni;
 }
 
+#ifndef _MSC_VER
 static inline void h_cfstack_add_end(HAllocator *mm__, HCFStack *stk__) {
+#else
+static __inline void h_cfstack_add_end(HAllocator *mm__, HCFStack *stk__) {
+#endif
   HCFChoice *ni = h_cfstack_new_choice_raw(mm__, stk__);
   ni->type = HCF_END;
   stk__->last_completed = ni;
 }
 
+#ifndef _MSC_VER
 static inline void h_cfstack_begin_choice(HAllocator *mm__, HCFStack *stk__) {
+#else
+static __inline void h_cfstack_begin_choice(HAllocator *mm__, HCFStack *stk__) {
+#endif
   HCFChoice *choice = h_cfstack_new_choice_raw(mm__, stk__);
   choice->type = HCF_CHOICE;
   choice->seq = h_new(HCFSequence*, 1);
@@ -116,7 +149,11 @@ static inline void h_cfstack_begin_choice(HAllocator *mm__, HCFStack *stk__) {
   stk__->stack[stk__->count++] = choice;
 }
 
+#ifndef _MSC_VER
 static inline void h_cfstack_begin_seq(HAllocator *mm__, HCFStack *stk__) {
+#else
+static __inline void h_cfstack_begin_seq(HAllocator *mm__, HCFStack *stk__) {
+#endif
   HCFChoice *top = stk__->stack[stk__->count-1];
   for (int i = 0;; i++) {
     if (top->seq[i] == NULL) {
@@ -130,13 +167,23 @@ static inline void h_cfstack_begin_seq(HAllocator *mm__, HCFStack *stk__) {
   }
 }
 
+#ifndef _MSC_VER
 static inline void h_cfstack_end_seq(HAllocator *mm__, HCFStack *stk__) UNUSED;
 static inline void h_cfstack_end_seq(HAllocator *mm__, HCFStack *stk__) {
+#else
+static __inline void h_cfstack_end_seq(HAllocator *mm__, HCFStack *stk__) UNUSED;
+static __inline void h_cfstack_end_seq(HAllocator *mm__, HCFStack *stk__) {
+#endif
   // do nothing. You should call this anyway.
 }
 
+#ifndef _MSC_VER
 static inline void h_cfstack_end_choice(HAllocator *mm__, HCFStack *stk__) UNUSED;
 static inline void h_cfstack_end_choice(HAllocator *mm__, HCFStack *stk__) {
+#else
+static __inline void h_cfstack_end_choice(HAllocator *mm__, HCFStack *stk__) UNUSED;
+static __inline void h_cfstack_end_choice(HAllocator *mm__, HCFStack *stk__) {
+#endif
   assert(stk__->count > 0);
   stk__->last_completed = stk__->stack[stk__->count-1];
   stk__->count--;
diff --git a/src/backends/glr.c b/src/backends/glr.c
index e753ea55..c46bb3f9 100644
--- a/src/backends/glr.c
+++ b/src/backends/glr.c
@@ -67,7 +67,11 @@ static HSlist *demerge_stack(HSlistNode *bottom, HSlist *stack)
   return ret;
 }
 
+#ifndef _MSC_VER
 static inline HLREngine *respawn(HLREngine *eng, HSlist *stack)
+#else
+static __inline HLREngine *respawn(HLREngine *eng, HSlist *stack)
+#endif
 {
   // NB: this can be a destructive update because an engine is not used for
   // anything after it is merged.
diff --git a/src/backends/lalr.c b/src/backends/lalr.c
index 14f64cd1..718d4bf3 100644
--- a/src/backends/lalr.c
+++ b/src/backends/lalr.c
@@ -5,8 +5,11 @@
 
 
 /* LALR-via-SLR grammar transformation */
-
+#ifndef _MSC_VER
 static inline size_t seqsize(void *p_)
+#else
+static __inline size_t seqsize(void *p_)
+#endif
 {
   size_t n=0;
   for(void **p=p_; *p; p++) n++;
@@ -35,7 +38,11 @@ static size_t follow_transition(const HLRTable *table, size_t x, HCFChoice *A)
   return action->nextstate;
 }
 
+#ifndef _MSC_VER
 static inline HLRTransition *transition(HArena *arena,
+#else
+static __inline HLRTransition *transition(HArena *arena,
+#endif
                                         size_t x, const HCFChoice *A, size_t y)
 {
   HLRTransition *t = h_arena_malloc(arena, sizeof(HLRTransition));
@@ -139,8 +146,11 @@ static HLREnhGrammar *enhance_grammar(const HCFGrammar *g, const HLRDFA *dfa,
 
 
 /* LALR table generation */
-
+#ifndef _MSC_VER
 static inline bool has_conflicts(HLRTable *table)
+#else
+static __inline bool has_conflicts(HLRTable *table)
+#endif
 {
   return !h_slist_empty(table->inadeq);
 }
diff --git a/src/backends/lr.c b/src/backends/lr.c
index e7f23775..94930aa2 100644
--- a/src/backends/lr.c
+++ b/src/backends/lr.c
@@ -44,7 +44,11 @@ static bool eq_lr_item(const void *p, const void *q)
 }
 
 // hash LALR items
+#ifndef _MSC_VER
 static inline HHashValue hash_lr_item(const void *p)
+#else
+static __inline HHashValue hash_lr_item(const void *p)
+#endif
 {
   const HLRItem *x = p;
   HHashValue hash = 0;
diff --git a/src/backends/lr0.c b/src/backends/lr0.c
index 1c86484e..57d0dcc4 100644
--- a/src/backends/lr0.c
+++ b/src/backends/lr0.c
@@ -161,7 +161,11 @@ HLRDFA *h_lr0_dfa(HCFGrammar *g)
 
 /* LR(0) table generation */
 
+#ifndef _MSC_VER
 static inline
+#else
+static __inline
+#endif
 void put_shift(HLRTable *table, size_t state, const HCFChoice *symbol,
                size_t nextstate)
 {
diff --git a/src/backends/packrat.c b/src/backends/packrat.c
index c1e422ed..b03d6a36 100644
--- a/src/backends/packrat.c
+++ b/src/backends/packrat.c
@@ -24,7 +24,11 @@ HParserCacheValue *cached_lr(HParseState *state, HLeftRec *lr) {
 }
 
 // Really library-internal tool to perform an uncached parse, and handle any common error-handling.
+#ifndef _MSC_VER
 static inline HParseResult* perform_lowlevel_parse(HParseState *state, const HParser *parser) {
+#else
+static __inline HParseResult* perform_lowlevel_parse(HParseState *state, const HParser *parser) {
+#endif
   // TODO(thequux): these nested conditions are ugly. Factor this appropriately, so that it is clear which codes is executed when.
   HParseResult *tmp_res;
   if (parser) {
@@ -110,7 +114,11 @@ void setupLR(const HParser *p, HParseState *state, HLeftRec *rec_detect) {
 }
 
 // helper: true iff pos1 is less than pos2
+#ifndef _MSC_VER
 static inline bool pos_lt(HInputStream pos1, HInputStream pos2) {
+#else
+static __inline bool pos_lt(HInputStream pos1, HInputStream pos2) {
+#endif
   return ((pos1.index < pos2.index) ||
 	  (pos1.index == pos2.index && pos1.bit_offset < pos2.bit_offset));
 }
@@ -124,7 +132,7 @@ HParseResult* grow(HParserCacheKey *k, HParseState *state, HRecursionHead *head)
   h_hashtable_put(state->recursion_heads, &k->input_pos, head);
   HParserCacheValue *old_cached = h_hashtable_get(state->cache, k);
   if (!old_cached || PC_LEFT == old_cached->value_type)
-    errx(1, "impossible match");
+    fprintf(stderr, "impossible match");
   HParseResult *old_res = old_cached->right;
 
   // rewind the input
@@ -146,7 +154,7 @@ HParseResult* grow(HParserCacheKey *k, HParseState *state, HRecursionHead *head)
         state->input_stream = cached->input_stream;
 	return cached->right;
       } else {
-	errx(1, "impossible match");
+	fprintf(stderr, "impossible match");
       }
     }
   } else {
@@ -171,7 +179,7 @@ HParseResult* lr_answer(HParserCacheKey *k, HParseState *state, HLeftRec *growab
 	return grow(k, state, growable->head);
     }
   } else {
-    errx(1, "lrAnswer with no head");
+    fprintf(stderr, "lrAnswer with no head");
   }
 }
 
diff --git a/src/backends/regex.c b/src/backends/regex.c
index c4f6a2bf..68cd8fe5 100644
--- a/src/backends/regex.c
+++ b/src/backends/regex.c
@@ -381,6 +381,6 @@ HParserBackendVTable h__regex_backend_vtable = {
   .free = h_regex_free
 };
 
-#ifndef NDEBUG
+#if !defined(NDEBUG) && !defined(_MSC_VER)
 #include "regex_debug.c"
 #endif
diff --git a/src/benchmark.c b/src/benchmark.c
index 408bfdb2..c2cc5b51 100644
--- a/src/benchmark.c
+++ b/src/benchmark.c
@@ -14,6 +14,77 @@
 #include <sys/resource.h>
 #endif
 
+#ifdef _WIN32
+#define CLOCK_THREAD_CPUTIME_ID 0
+#include <windows.h>
+#include <winnt.h>
+
+struct timespec {
+	LONGLONG tv_sec;
+	long tv_nsec;
+};
+
+LARGE_INTEGER getFILETIMEoffset()
+{
+	SYSTEMTIME s;
+	FILETIME f;
+	LARGE_INTEGER t;
+
+
+	s.wYear = 1970;
+	s.wMonth = 1;
+	s.wDay = 1;
+	s.wHour = 0;
+	s.wMinute = 0;
+	s.wSecond = 0;
+	s.wMilliseconds = 0;
+	SystemTimeToFileTime(&s, &f);
+	t.QuadPart = f.dwHighDateTime;
+	t.QuadPart <<= 32;
+	t.QuadPart |= f.dwLowDateTime;
+	return (t);
+}
+
+void clock_gettime(int X, struct timespec *tv)
+{
+	LARGE_INTEGER           t;
+	FILETIME                f;
+	double                  nanoseconds;
+	static LARGE_INTEGER    offset;
+	static double           frequencyToNanoseconds;
+	static int              initialized = 0;
+	static BOOL             usePerformanceCounter = 0;
+
+
+	if (!initialized) {
+		LARGE_INTEGER performanceFrequency;
+		initialized = 1;
+		usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
+		if (usePerformanceCounter) {
+			QueryPerformanceCounter(&offset);
+			frequencyToNanoseconds = (double)performanceFrequency.QuadPart / 1000.;
+		}
+		else {
+			offset = getFILETIMEoffset();
+			frequencyToNanoseconds = 0.010;
+		}
+	}
+	if (usePerformanceCounter) QueryPerformanceCounter(&t);
+	else {
+		GetSystemTimeAsFileTime(&f);
+		t.QuadPart = f.dwHighDateTime;
+		t.QuadPart <<= 32;
+		t.QuadPart |= f.dwLowDateTime;
+	}
+
+	t.QuadPart -= offset.QuadPart;
+	nanoseconds = (double)t.QuadPart / frequencyToNanoseconds;
+	t.QuadPart = (LONGLONG)nanoseconds;
+	tv->tv_sec = t.QuadPart / 1000000000;
+	tv->tv_nsec = t.QuadPart % 1000000000;
+}
+#endif
+
 void h_benchmark_clock_gettime(struct timespec *ts) {
   if (ts == NULL)
     return;
@@ -153,13 +224,21 @@ void h_benchmark_report(FILE* stream, HBenchmarkResults* result) {
     if (result->results[i].cases == NULL) {
       fprintf(stream, "Skipping %s because grammar did not compile for it\n", HParserBackendNames[i]);
     } else {
-      fprintf(stream, "Backend %zd (%s) ... \n", i, HParserBackendNames[i]);
+#ifndef _MSC_VER
+      errx(stream, "Backend %zd (%s) ... \n", i, HParserBackendNames[i]);
+#else
+	  fprintf(stream, "Backend %u (%s) ... \n", i, HParserBackendNames[i]);
+#endif
     }
     for (size_t j=0; j<result->results[i].n_testcases; ++j) {
       if (result->results[i].cases == NULL) {
         continue;
       }
-      fprintf(stream, "Case %zd: %zd ns/parse, %zd ns/byte\n", j,  result->results[i].cases[j].parse_time, result->results[i].cases[j].parse_time / result->results[i].cases[j].length);
-    }
+#ifndef _MSC_VER
+	  errx(stream, "Case %zd: %zd ns/parse, %zd ns/byte\n", j, result->results[i].cases[j].parse_time, result->results[i].cases[j].parse_time / result->results[i].cases[j].length);
+#else
+	  fprintf(stream, "Case %u: %u ns/parse, %u ns/byte\n", j, result->results[i].cases[j].parse_time, result->results[i].cases[j].parse_time / result->results[i].cases[j].length);
+#endif
+	}
   }
 }
diff --git a/src/bitreader.c b/src/bitreader.c
index df8c4c36..3f4c7427 100644
--- a/src/bitreader.c
+++ b/src/bitreader.c
@@ -19,7 +19,6 @@
 #include <stdio.h>
 #include "internal.h"
 #include "hammer.h"
-#include "test_suite.h"
 
 #define LSB(range) (0:range)
 #define MSB(range) (1:range)
diff --git a/src/bitwriter.c b/src/bitwriter.c
index 451815bd..ffd78c65 100644
--- a/src/bitwriter.c
+++ b/src/bitwriter.c
@@ -3,7 +3,6 @@
 #include <assert.h>
 #include "hammer.h"
 #include "internal.h"
-#include "test_suite.h"
 
 #define MIN(a,b) (((a)<(b))?(a):(b))
 #define MAX(a,b) (((a)>(b))?(a):(b))
diff --git a/src/cfgrammar.c b/src/cfgrammar.c
index a8761b8d..4023de70 100644
--- a/src/cfgrammar.c
+++ b/src/cfgrammar.c
@@ -541,7 +541,11 @@ static void remove_all_shorter(size_t k, HStringMap *m)
 }
 
 // h_follow adapted to the signature of StringSetFun
+#ifndef _MSC_VER
 static inline
+#else
+static __inline
+#endif
 const HStringMap *h_follow_(size_t k, HCFGrammar *g, HCFChoice **s)
 {
   return h_follow(k, g, *s);
diff --git a/src/cfgrammar.h b/src/cfgrammar.h
index 9cefc62e..b4dabe0c 100644
--- a/src/cfgrammar.h
+++ b/src/cfgrammar.h
@@ -24,8 +24,13 @@ typedef struct HCFGrammar_ {
  * To use these as keys, we must avoid 0 as because NULL means "not set".
  */
 typedef uintptr_t HCharKey;
+#ifndef _MSC_VER
 static inline HCharKey char_key(uint8_t c) { return (0x100 | c); }
 static inline uint8_t key_char(HCharKey k) { return (0xFF & k); }
+#else
+static __inline HCharKey char_key(uint8_t c) { return (0x100 | c); }
+static __inline uint8_t key_char(HCharKey k) { return (0xFF & k); }
+#endif
 
 /* Mapping strings of input tokens to arbitrary values (or serving as a set).
  * Common prefixes are folded into a tree of HHashTables, branches labeled with
@@ -53,7 +58,11 @@ bool h_stringmap_present(const HStringMap *m, const uint8_t *str, size_t n, bool
 bool h_stringmap_present_epsilon(const HStringMap *m);
 bool h_stringmap_empty(const HStringMap *m);
 
+#ifndef _MSC_VER
 static inline HStringMap *h_stringmap_get_char(const HStringMap *m, const uint8_t c)
+#else
+static __inline HStringMap *h_stringmap_get_char(const HStringMap *m, const uint8_t c)
+#endif
  { return h_hashtable_get(m->char_branches, (void *)char_key(c)); }
 
 
diff --git a/src/datastructures.c b/src/datastructures.c
index 0feeb217..e6def972 100644
--- a/src/datastructures.c
+++ b/src/datastructures.c
@@ -354,7 +354,11 @@ static bool hte_subset(HEqualFunc eq, HHashTableEntry *xs, HHashTableEntry *ys)
 }
 
 // compare two lists of HHashTableEntries
+#ifndef _MSC_VER
 static inline bool hte_equal(HEqualFunc eq, HHashTableEntry *xs, HHashTableEntry *ys) {
+#else
+static __inline bool hte_equal(HEqualFunc eq, HHashTableEntry *xs, HHashTableEntry *ys) {
+#endif
   return (hte_same_length(xs, ys) && hte_subset(eq, xs, ys));
 }
 
diff --git a/src/hammer-test.sln b/src/hammer-test.sln
new file mode 100644
index 00000000..5a9ae9b0
--- /dev/null
+++ b/src/hammer-test.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30723.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hammer-test", "hammer-test.vcxproj", "{D8EE4D7C-40FB-45A0-9C75-CEA586DCA66B}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D8EE4D7C-40FB-45A0-9C75-CEA586DCA66B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{D8EE4D7C-40FB-45A0-9C75-CEA586DCA66B}.Debug|Win32.Build.0 = Debug|Win32
+		{D8EE4D7C-40FB-45A0-9C75-CEA586DCA66B}.Release|Win32.ActiveCfg = Release|Win32
+		{D8EE4D7C-40FB-45A0-9C75-CEA586DCA66B}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/src/hammer-test.vcxproj b/src/hammer-test.vcxproj
new file mode 100644
index 00000000..b62e7fed
--- /dev/null
+++ b/src/hammer-test.vcxproj
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{D8EE4D7C-40FB-45A0-9C75-CEA586DCA66B}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="test_suite.c" />
+    <ClCompile Include="t_benchmark.c" />
+    <ClCompile Include="t_bitreader.c" />
+    <ClCompile Include="t_bitwriter.c" />
+    <ClCompile Include="t_grammar.c" />
+    <ClCompile Include="t_misc.c" />
+    <ClCompile Include="t_parser.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="test_suite.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/src/hammer-test.vcxproj.filters b/src/hammer-test.vcxproj.filters
new file mode 100644
index 00000000..701b3b59
--- /dev/null
+++ b/src/hammer-test.vcxproj.filters
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="test_suite.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="t_benchmark.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="t_bitreader.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="t_bitwriter.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="t_grammar.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="t_misc.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="t_parser.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="test_suite.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/hammer.c b/src/hammer.c
index 2456bdce..c9028e84 100644
--- a/src/hammer.c
+++ b/src/hammer.c
@@ -17,7 +17,6 @@
 
 #include <assert.h>
 #include <ctype.h>
-#include <err.h>
 #include <limits.h>
 #include <stdarg.h>
 #include <string.h>
diff --git a/src/hammer.h b/src/hammer.h
index 52058b5c..2ea1f273 100644
--- a/src/hammer.h
+++ b/src/hammer.h
@@ -25,6 +25,12 @@
 #include <stdio.h>
 #include "allocator.h"
 
+#ifdef _MSC_VER
+#define EXPORT __declspec(dllexport)
+#else
+#define EXPORT __attribute__ ((visibility ("default")))
+#endif
+
 #define BYTE_BIG_ENDIAN 0x1
 #define BIT_BIG_ENDIAN 0x2
 #define BIT_LITTLE_ENDIAN 0x0
@@ -216,7 +222,7 @@ typedef struct HBenchmarkResults_ {
   rtype_t name(__VA_ARGS__) attr;					\
   rtype_t name##__m(HAllocator* mm__, __VA_ARGS__) attr
 
-#ifndef SWIG
+#ifndef SWIG 
 #define HAMMER_FN_DECL_VARARGS(rtype_t, name, ...)			\
   rtype_t name(__VA_ARGS__, ...);					\
   rtype_t name##__m(HAllocator* mm__, __VA_ARGS__, ...);		\
@@ -226,6 +232,15 @@ typedef struct HBenchmarkResults_ {
   rtype_t name##__ma(HAllocator *mm__, void *args[])
 
 // Note: this drops the attributes on the floor for the __v versions
+#ifdef _MSC_VER
+#define HAMMER_FN_DECL_VARARGS_ATTR(attr, rtype_t, name, ...)		\
+  rtype_t name(__VA_ARGS__, ...);                                 \
+  rtype_t name##__m(HAllocator* mm__, __VA_ARGS__, ...);			\
+  rtype_t name##__mv(HAllocator* mm__, __VA_ARGS__, va_list ap);	\
+  rtype_t name##__v(__VA_ARGS__, va_list ap);				\
+  rtype_t name##__a(void *args[]);					\
+  rtype_t name##__ma(HAllocator *mm__, void *args[])
+#else
 #define HAMMER_FN_DECL_VARARGS_ATTR(attr, rtype_t, name, ...)		\
   rtype_t name(__VA_ARGS__, ...) attr;					\
   rtype_t name##__m(HAllocator* mm__, __VA_ARGS__, ...) attr;		\
@@ -233,6 +248,7 @@ typedef struct HBenchmarkResults_ {
   rtype_t name##__v(__VA_ARGS__, va_list ap);				\
   rtype_t name##__a(void *args[]);					\
   rtype_t name##__ma(HAllocator *mm__, void *args[])
+#endif
 #else
 #define HAMMER_FN_DECL_VARARGS(rtype_t, name, params...)  \
   rtype_t name(params, ...);				  \
@@ -249,6 +265,9 @@ typedef struct HBenchmarkResults_ {
 #endif // SWIG
 // }}}
 
+#ifdef _MSVC_VER
+#define __attribute__(x)
+#endif
 
 /**
  * Top-level function to call a parser that has been built over some
diff --git a/src/internal.h b/src/internal.h
index 6c721eb0..6ffc80d3 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -24,7 +24,6 @@
 #define HAMMER_INTERNAL__H
 #include <stdint.h>
 #include <assert.h>
-#include <err.h>
 #include <string.h>
 #include "hammer.h"
 
@@ -33,7 +32,7 @@
 #else
 #define assert_message(check, message) do {				\
     if (!(check))							\
-      errx(1, "Assertion failed (programmer error): %s", message);	\
+      fprintf(stderr, "Assertion failed (programmer error): %s", message);	\
   } while(0)
 #endif
 
@@ -56,11 +55,21 @@ extern "C" {
 #endif
 
 // This is going to be generally useful.
+#ifndef _MSC_VER
 static inline void h_generic_free(HAllocator *allocator, void* ptr) {
+#else
+static __inline void h_generic_free(HAllocator *allocator, void* ptr) {
+#endif
   allocator->free(allocator, ptr);
 }
 
-extern HAllocator system_allocator;
+#if COMPILING_DLL
+#define DLLEXPORT
+#else
+#define DLLEXPORT __declspec(dllimport)
+#endif
+
+extern DLLEXPORT HAllocator system_allocator;
 typedef struct HCFStack_ HCFStack;
 
 
@@ -103,18 +112,31 @@ typedef struct HSArray_ {
 
 HSArray *h_sarray_new(HAllocator *mm__, size_t size);
 void h_sarray_free(HSArray *arr);
+#ifndef _MSC_VER
 static inline bool h_sarray_isset(HSArray *arr, size_t n) {
+#else
+static __inline bool h_sarray_isset(HSArray *arr, size_t n) {
+#endif
   assert(n < arr->capacity);
   return (arr->nodes[n].index < arr->used && arr->nodes[arr->nodes[n].index].elem == n);
 }
+
+#ifndef _MSC_VER
 static inline void* h_sarray_get(HSArray *arr, size_t n) {
+#else
+static __inline void* h_sarray_get(HSArray *arr, size_t n) {
+#endif
   assert(n < arr->capacity);
   if (h_sarray_isset(arr, n))
     return arr->nodes[n].content;
   return NULL;
 }
 
+#ifndef _MSC_VER
 static inline void* h_sarray_set(HSArray *arr, size_t n, void* val) {
+#else
+static __inline void* h_sarray_set(HSArray *arr, size_t n, void* val) {
+#endif
   assert(n < arr->capacity);
   arr->nodes[n].content = val;
   if (h_sarray_isset(arr, n))
@@ -124,7 +146,11 @@ static inline void* h_sarray_set(HSArray *arr, size_t n, void* val) {
   return val;
 }
 
+#ifndef _MSC_VER
 static inline void h_sarray_clear(HSArray *arr) {
+#else
+static __inline void h_sarray_clear(HSArray *arr) {
+#endif
   arr->used = 0;
 }
 
@@ -145,17 +171,29 @@ static inline void h_sarray_clear(HSArray *arr) {
 
 typedef unsigned int *HCharset;
 
+#ifndef _MSC_VER
 static inline HCharset new_charset(HAllocator* mm__) {
+#else
+static __inline HCharset new_charset(HAllocator* mm__) {
+#endif
   HCharset cs = h_new(unsigned int, 256 / sizeof(unsigned int));
   memset(cs, 0, 256);
   return cs;
 }
 
+#ifndef _MSC_VER
 static inline int charset_isset(HCharset cs, uint8_t pos) {
+#else
+static __inline int charset_isset(HCharset cs, uint8_t pos) {
+#endif
   return !!(cs[pos / sizeof(*cs)] & (1 << (pos % sizeof(*cs))));
 }
 
+#ifndef _MSC_VER
 static inline void charset_set(HCharset cs, uint8_t pos, int val) {
+#else
+static __inline void charset_set(HCharset cs, uint8_t pos, int val) {
+#endif
   cs[pos / sizeof(*cs)] =
     val
     ? cs[pos / sizeof(*cs)] |  (1 << (pos % sizeof(*cs)))
@@ -299,7 +337,11 @@ int64_t h_read_bits(HInputStream* state, int count, char signed_p);
 HParseResult* h_do_parse(const HParser* parser, HParseState *state);
 void put_cached(HParseState *ps, const HParser *p, HParseResult *cached);
 
+#ifndef _MSC_VER
 static inline
+#else
+static __inline
+#endif
 HParser *h_new_parser(HAllocator *mm__, const HParserVtable *vt, void *env) {
   HParser *p = h_new(HParser, 1);
   memset(p, 0, sizeof(HParser));
@@ -318,12 +360,20 @@ HSlist* h_slist_new(HArena *arena);
 HSlist* h_slist_copy(HSlist *slist);
 void* h_slist_pop(HSlist *slist);
 void* h_slist_drop(HSlist *slist);
+#ifndef _MSC_VER
 static inline void* h_slist_top(HSlist *sl) { return sl->head->elem; }
+#else
+static __inline void* h_slist_top(HSlist *sl) { return sl->head->elem; }
+#endif
 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);
 void h_slist_free(HSlist *slist);
+#ifndef _MSC_VER
 static inline bool h_slist_empty(const HSlist *sl) { return (sl->head == NULL); }
+#else
+static __inline bool h_slist_empty(const HSlist *sl) { return (sl->head == NULL); }
+#endif
 
 HHashTable* h_hashtable_new(HArena *arena, HEqualFunc equalFunc, HHashFunc hashFunc);
 void* h_hashtable_get(const HHashTable* ht, const void* key);
@@ -334,7 +384,11 @@ void  h_hashtable_merge(void *(*combine)(void *v1, const void *v2),
 int   h_hashtable_present(const HHashTable* ht, const void* key);
 void  h_hashtable_del(HHashTable* ht, const void* key);
 void  h_hashtable_free(HHashTable* ht);
+#ifndef _MSC_VER
 static inline bool h_hashtable_empty(const HHashTable* ht) { return (ht->used == 0); }
+#else
+static __inline bool h_hashtable_empty(const HHashTable* ht) { return (ht->used == 0); }
+#endif
 
 typedef HHashTable HHashSet;
 #define h_hashset_new(a,eq,hash) h_hashtable_new(a,eq,hash)
diff --git a/src/msvc/tsearch.c b/src/msvc/tsearch.c
new file mode 100644
index 00000000..d99710a4
--- /dev/null
+++ b/src/msvc/tsearch.c
@@ -0,0 +1,114 @@
+/*
+* 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, lint doesn't grok it.
+*
+* Written by reading the System V Interface Definition, not the code.
+*
+* Totally public domain.
+*/
+/*LINTLIBRARY*/
+
+#include "tsearch.h"
+#include <stdlib.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 = (node *)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);
+}
+/* find datum in search tree */
+void *
+tfind(const void *vkey, void **vrootp,
+int(*compar)(const void *, const void *))
+{
+
+	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 */
+	}
+	return ((void *)0);	/* T5: key not found */
+}
+
+
+/* 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);
+}
\ No newline at end of file
diff --git a/src/msvc/tsearch.h b/src/msvc/tsearch.h
new file mode 100644
index 00000000..21801b60
--- /dev/null
+++ b/src/msvc/tsearch.h
@@ -0,0 +1,14 @@
+#ifndef TSEARCH_H
+#define TSEARCH_H
+
+void * tsearch(const void *vkey, void **vrootp,
+	int(*compar)(const void *, const void *));
+
+void * tfind(const void *vkey, void **vrootp,
+	int(*compar)(const void *, const void *));
+
+void * tdelete(const void *vkey, void **vrootp,
+	int(*compar)(const void *, const void *));
+
+
+#endif
\ No newline at end of file
diff --git a/src/parsers/choice.c b/src/parsers/choice.c
index bfc3f904..00e3137e 100644
--- a/src/parsers/choice.c
+++ b/src/parsers/choice.c
@@ -53,7 +53,12 @@ static void desugar_choice(HAllocator *mm__, HCFStack *stk__, void *env) {
 
 static bool choice_ctrvm(HRVMProg *prog, void* env) {
   HSequence *s = (HSequence*)env;
+#ifndef _MSC_VER
   uint16_t gotos[s->len];
+#else
+  HAllocator *mm__ = prog->allocator;
+  uint16_t *gotos = h_new(uint16_t, s->len);
+#endif
   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]))
diff --git a/src/parsers/many.c b/src/parsers/many.c
index 1e3b0221..38b71328 100644
--- a/src/parsers/many.c
+++ b/src/parsers/many.c
@@ -246,7 +246,7 @@ static HParseResult* parse_length_value(void *env, HParseState *state) {
   if (!len)
     return NULL;
   if (len->ast->token_type != TT_UINT)
-    errx(1, "Length parser must return an unsigned integer");
+    fprintf(stderr, "Length parser must return an unsigned integer");
   // TODO: allocate this using public functions
   HRepeat repeat = {
     .p = lv->value,
diff --git a/src/parsers/nothing.c b/src/parsers/nothing.c
index 120c1e01..77648947 100644
--- a/src/parsers/nothing.c
+++ b/src/parsers/nothing.c
@@ -1,6 +1,6 @@
 #include "parser_internal.h"
 
-static HParseResult* parse_nothing() {
+static HParseResult* parse_nothing(void* env, HParseState* state) {
   // not a mistake, this parser always fails
   return NULL;
 }
diff --git a/src/parsers/parser_internal.h b/src/parsers/parser_internal.h
index ec97dd1b..e6dec67c 100644
--- a/src/parsers/parser_internal.h
+++ b/src/parsers/parser_internal.h
@@ -14,7 +14,11 @@
 #define a_new(typ, count) a_new_(state->arena, typ, count)
 // we can create a_new0 if necessary. It would allocate some memory and immediately zero it out.
 
+#ifndef _MSC_VER
 static inline HParseResult* make_result(HArena *arena, HParsedToken *tok) {
+#else
+static __inline HParseResult* make_result(HArena *arena, HParsedToken *tok) {
+#endif
   HParseResult *ret = h_arena_malloc(arena, sizeof(HParseResult));
   ret->ast = tok;
   ret->arena = arena;
@@ -22,7 +26,11 @@ static inline HParseResult* make_result(HArena *arena, HParsedToken *tok) {
 }
 
 // return token size in bits...
+#ifndef _MSC_VER
 static inline size_t token_length(HParseResult *pr) {
+#else
+static __inline size_t token_length(HParseResult *pr) {
+#endif
   if (pr) {
     return pr->bit_length;
   } else {
@@ -31,7 +39,11 @@ static inline size_t token_length(HParseResult *pr) {
 }
 
 /* Epsilon rules happen during desugaring. This handles them. */
+#ifndef _MSC_VER
 static inline void desugar_epsilon(HAllocator *mm__, HCFStack *stk__, void *env) {
+#else
+static __inline void desugar_epsilon(HAllocator *mm__, HCFStack *stk__, void *env) {
+#endif
   HCFS_BEGIN_CHOICE() {
     HCFS_BEGIN_SEQ() {
     } HCFS_END_SEQ();
diff --git a/src/pprint.c b/src/pprint.c
index 8abbf5a7..b6f8ac05 100644
--- a/src/pprint.c
+++ b/src/pprint.c
@@ -23,6 +23,28 @@
 #include <stdlib.h>
 #include <inttypes.h>
 
+#ifdef _WIN32
+#include <stdarg.h>
+
+int vasprintf(char **sptr, char *fmt, va_list argv)
+{
+	int wanted = vsnprintf(*sptr = NULL, 0, fmt, argv);
+	if ((wanted > 0) && ((*sptr = malloc(1 + wanted)) != NULL))
+		return vsprintf(*sptr, fmt, argv);
+	return wanted;
+}
+
+int asprintf(char **sptr, char *fmt, ...)
+{
+	int retval;
+	va_list argv;
+	va_start(argv, fmt);
+	retval = vasprintf(sptr, fmt, argv);
+	va_end(argv);
+	return retval;
+}
+#endif
+
 typedef struct pp_state {
   int delta;
   int indent_amt;
@@ -85,18 +107,30 @@ struct result_buf {
   size_t capacity;
 };
 
+#ifndef _MSC_VER
 static inline void ensure_capacity(struct result_buf *buf, int amt) {
+#else
+static __inline void ensure_capacity(struct result_buf *buf, int amt) {
+#endif
   while (buf->len + amt >= buf->capacity)
     buf->output = realloc(buf->output, buf->capacity *= 2);
 }
 
+#ifndef _MSC_VER
 static inline void append_buf(struct result_buf *buf, const char* input, int len) {
+#else
+static __inline void append_buf(struct result_buf *buf, const char* input, int len) {
+#endif
   ensure_capacity(buf, len);
   memcpy(buf->output + buf->len, input, len);
   buf->len += len;
 }
 
+#ifndef _MSC_VER
 static inline void append_buf_c(struct result_buf *buf, char v) {
+#else
+static __inline void append_buf_c(struct result_buf *buf, char v) {
+#endif
   ensure_capacity(buf, 1);
   buf->output[buf->len++] = v;
 }
diff --git a/src/registry.c b/src/registry.c
index 60aa8863..ed6428a1 100644
--- a/src/registry.c
+++ b/src/registry.c
@@ -20,6 +20,10 @@
 #include "hammer.h"
 #include "internal.h"
 
+#ifdef _MSC_VER
+#include "msvc/tsearch.h"
+#endif
+
 typedef struct Entry_ {
   const char* name;
   HTokenType value;
diff --git a/src/system_allocator.c b/src/system_allocator.c
index b34810fa..c4f7db67 100644
--- a/src/system_allocator.c
+++ b/src/system_allocator.c
@@ -4,36 +4,55 @@
 
 //#define DEBUG__MEMFILL 0xFF
 
-static void* system_alloc(HAllocator *allocator, size_t size) {
+//static
+void* system_alloc(HAllocator *allocator, size_t size) {
   
   void* ptr = malloc(size + sizeof(size_t));
 #ifdef DEBUG__MEMFILL
   memset(ptr, DEBUG__MEMFILL, size + sizeof(size_t));
 #endif
   *(size_t*)ptr = size;
+#ifndef _MSC_VER
   return ptr + sizeof(size_t);
+#else
+  return (uint8_t*)ptr + sizeof(size_t);
+#endif
 }
 
-static void* system_realloc(HAllocator *allocator, void* ptr, size_t size) {
+//static 
+void* system_realloc(HAllocator *allocator, void* ptr, size_t size) {
   if (ptr == NULL)
     return system_alloc(allocator, size);
+#ifndef _MSC_VER
   ptr = realloc(ptr - sizeof(size_t), size + sizeof(size_t));
+#else
+  ptr = realloc((uint8_t*)ptr - sizeof(size_t), size + sizeof(size_t));
+#endif
   *(size_t*)ptr = size;
 #ifdef DEBUG__MEMFILL
   size_t old_size = *(size_t*)ptr;
   if (size > old_size)
     memset(ptr+sizeof(size_t)+old_size, DEBUG__MEMFILL, size - old_size);
 #endif
+#ifndef _MSC_VER
   return ptr + sizeof(size_t);
+#else
+  return (uint8_t*)ptr + sizeof(size_t);
+#endif
 }
 
-static void system_free(HAllocator *allocator, void* ptr) {
+//static 
+void system_free(HAllocator *allocator, void* ptr) {
   if (ptr != NULL)
+#ifndef _MSC_VER
     free(ptr - sizeof(size_t));
+#else
+	free((uint8_t*)ptr - sizeof(size_t));
+#endif
 }
 
 HAllocator system_allocator = {
-  .alloc = system_alloc,
-  .realloc = system_realloc,
-  .free = system_free,
+  .alloc = &system_alloc,
+  .realloc = &system_realloc,
+  .free = &system_free,
 };
diff --git a/src/test_suite.h b/src/test_suite.h
index 1f983c7f..4c71a3e0 100644
--- a/src/test_suite.h
+++ b/src/test_suite.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <inttypes.h>
+#include <glib.h>
 
 // Equivalent to g_assert_*, but not using g_assert...
 #define g_check_inttype(fmt, typ, n1, op, n2) do {				\
-- 
GitLab