diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000000000000000000000000000000000000..869c327574673b97402e235c576bc756740fa1dd
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,12 @@
+Privileged arguments
+====================
+
+As a matter of convenience, there are several identifiers that
+internal macros use. Chances are that if you use these names for other
+things, you're gonna have a bad time.
+
+In particular, these names, and the macros that use them, are:
+- state:
+    Used by a_new and company. Should be an HParseState*
+- mm__:
+    Used by h_new and h_free. Should be an HAllocator*
diff --git a/src/Makefile b/src/Makefile
index faae8a7d4bedad4b1900b930abe2cafd05f9ab92..e4d70d127b2dd07093cb21bdd566d74a0e18129f 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -32,6 +32,8 @@ OUTPUTS := bitreader.o \
 	   pprint.o \
 	   allocator.o \
 	   datastructures.o \
+	   system_allocator.o \
+	   test_suite.o \
 	   test_suite \
 	   $(PARSERS:%=parsers/%.o)
 
@@ -45,7 +47,7 @@ all: libhammer.a test_suite
 test_suite: test_suite.o libhammer.a
 	$(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS)
 
-libhammer.a: bitreader.o hammer.o pprint.o allocator.o datastructures.o bitwriter.o \
+libhammer.a: bitreader.o hammer.o pprint.o allocator.o datastructures.o bitwriter.o system_allocator.o \
 	$(PARSERS:%=parsers/%.o)
 
 bitreader.o: test_suite.h
diff --git a/src/allocator.c b/src/allocator.c
index 59c6e5097f67443b933c168f58e791ab2684301b..e345c875317716da362e5b8ca9ed35298dc32e59 100644
--- a/src/allocator.c
+++ b/src/allocator.c
@@ -15,11 +15,13 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-#include <glib.h>
+#include <string.h>
 #include <stdint.h>
 #include <sys/types.h>
 
-#include "allocator.h"
+#include "hammer.h"
+#include "internal.h"
+
 
 struct arena_link {
   // TODO:
@@ -36,22 +38,25 @@ struct arena_link {
 
 struct HArena_ {
   struct arena_link *head;
+  struct HAllocator_ *mm__;
   size_t block_size;
   size_t used;
   size_t wasted;
 };
 
-HArena *h_new_arena(size_t block_size) {
+HArena *h_new_arena(HAllocator* mm__, size_t block_size) {
   if (block_size == 0)
     block_size = 4096;
-  struct HArena_ *ret = g_new(struct HArena_, 1);
-  struct arena_link *link = (struct arena_link*)g_malloc0(sizeof(struct arena_link) + block_size);
+  struct HArena_ *ret = h_new(struct HArena_, 1);
+  struct arena_link *link = (struct arena_link*)mm__->alloc(mm__, sizeof(struct arena_link) + block_size);
+  memset(link, 0, sizeof(struct arena_link) + block_size);
   link->free = block_size;
   link->used = 0;
   link->next = NULL;
   ret->head = link;
   ret->block_size = block_size;
   ret->used = 0;
+  ret->mm__ = mm__;
   ret->wasted = sizeof(struct arena_link) + sizeof(struct HArena_) + block_size;
   return ret;
 }
@@ -70,13 +75,15 @@ void* h_arena_malloc(HArena *arena, size_t size) {
     // This involves some annoying casting...
     arena->used += size;
     arena->wasted += sizeof(struct arena_link*);
-    void* link = g_malloc(size + sizeof(struct arena_link*));
+    void* link = arena->mm__->alloc(arena->mm__, size + sizeof(struct arena_link*));
+    memset(link, 0, size + sizeof(struct arena_link*));
     *(struct arena_link**)link = arena->head->next;
     arena->head->next = (struct arena_link*)link;
     return (void*)(((uint8_t*)link) + sizeof(struct arena_link*));
   } else {
     // we just need to allocate an ordinary new block.
-    struct arena_link *link = (struct arena_link*)g_malloc0(sizeof(struct arena_link) + arena->block_size);
+    struct arena_link *link = (struct arena_link*)arena->mm__->alloc(arena->mm__, sizeof(struct arena_link) + arena->block_size);
+    memset(link, 0, sizeof(struct arena_link) + arena->block_size);
     link->free = arena->block_size - size;
     link->used = size;
     link->next = arena->head;
@@ -92,16 +99,17 @@ void h_arena_free(HArena *arena, void* ptr) {
 }
 
 void h_delete_arena(HArena *arena) {
+  HAllocator *mm__ = arena->mm__;
   struct arena_link *link = arena->head;
   while (link) {
     struct arena_link *next = link->next; 
     // Even in the case of a special block, without the full arena
     // header, this is correct, because the next pointer is the first
     // in the structure.
-    g_free(link);
+    h_free(link);
     link = next;
   }
-  g_free(arena);
+  h_free(arena);
 }
 
 void h_allocator_stats(HArena *arena, HArenaStats *stats) {
diff --git a/src/allocator.h b/src/allocator.h
index 3af22d04ed19c2e6043d5b1af3d73c7685f9d8d4..e83cae7cbfecebc58dd810671385b1d63f72d9fb 100644
--- a/src/allocator.h
+++ b/src/allocator.h
@@ -19,9 +19,15 @@
 #define HAMMER_ALLOCATOR__H__
 #include <sys/types.h>
 
+typedef struct HAllocator_ {
+  void* (*alloc)(struct HAllocator_* allocator, size_t size);
+  void* (*realloc)(struct HAllocator_* allocator, void* ptr, size_t size);
+  void (*free)(struct HAllocator_* allocator, void* ptr);
+} HAllocator;
+
 typedef struct HArena_ HArena ; // hidden implementation
 
-HArena *h_new_arena(size_t block_size); // pass 0 for default...
+HArena *h_new_arena(HAllocator* allocator, size_t block_size); // pass 0 for default...
 void* h_arena_malloc(HArena *arena, size_t count) __attribute__(( malloc, alloc_size(2) ));
 void h_arena_free(HArena *arena, void* ptr); // For future expansion, with alternate memory managers.
 void h_delete_arena(HArena *arena);
diff --git a/src/bitwriter.c b/src/bitwriter.c
index 9a72e22459c8ecedc066ba5ed4327db3f81ade39..e716f0946d6c5ebc60d5182bccaf6234d1222c3d 100644
--- a/src/bitwriter.c
+++ b/src/bitwriter.c
@@ -7,6 +7,7 @@
 // This file provides the logical inverse of bitreader.c
 struct HBitWriter_ {
   uint8_t* buf;
+  HAllocator *mm__;
   size_t index;
   size_t capacity;
   char bit_offset; // unlike in bit_reader, this is always the number
@@ -16,10 +17,12 @@ struct HBitWriter_ {
 };
 
 // h_bit_writer_
-HBitWriter *h_bit_writer_new() {
-  HBitWriter *writer = g_new0(HBitWriter, 1);
-  writer->buf = g_malloc0(writer->capacity = 8);
-
+HBitWriter *h_bit_writer_new(HAllocator* mm__) {
+  HBitWriter *writer = h_new(HBitWriter, 1);
+  memset(writer, 0, sizeof(*writer));
+  writer->buf = mm__->alloc(mm__, writer->capacity = 8);
+  memset(writer->buf, 0, writer->capacity);
+  writer->mm__ = mm__;
   writer->flags = BYTE_BIG_ENDIAN | BIT_BIG_ENDIAN;
 
   return writer;
@@ -41,7 +44,7 @@ static void h_bit_writer_reserve(HBitWriter* w, size_t nbits) {
   int nbytes = (nbits + 7) / 8 + ((w->bit_offset != 0) ? 1 : 0);
   size_t old_capacity = w->capacity;
   while (w->index + nbytes >= w->capacity) {
-    w->buf = g_realloc(w->buf, w->capacity *= 2);
+    w->buf = w->mm__->realloc(w->mm__, w->buf, w->capacity *= 2);
   }
 
   if (old_capacity != w->capacity)
@@ -100,8 +103,9 @@ const uint8_t *h_bit_writer_get_buffer(HBitWriter* w, size_t *len) {
 }
 
 void h_bit_writer_free(HBitWriter* w) {
-  g_free(w->buf);
-  g_free(w);
+  HAllocator *mm__ = w->mm__;
+  h_free(w->buf);
+  h_free(w);
 }
 
 #ifdef INCLUDE_TESTS
@@ -114,7 +118,7 @@ typedef struct {
 void run_bitwriter_test(bitwriter_test_elem data[], char flags) {
   size_t len;
   const uint8_t *buf;
-  HBitWriter *w = h_bit_writer_new();
+  HBitWriter *w = h_bit_writer_new(&system_allocator);
   int i;
   w->flags = flags;
   for (i = 0; data[i].nbits; i++) {
diff --git a/src/hammer.c b/src/hammer.c
index 3eab2d722266f8ce52a7e219c3dddb77d19c2d30..52881ec653609ddf6957670fba8654908a96d3ae 100644
--- a/src/hammer.c
+++ b/src/hammer.c
@@ -238,9 +238,12 @@ static gboolean cache_key_equal(gconstpointer key1, gconstpointer key2) {
 }
 
 
-HParseResult* h_parse(const HParser* parser, const uint8_t* input, size_t length) { 
+HParseResult* h_parse(const HParser* parser, const uint8_t* input, size_t length) {
+  return h_parse__m(&system_allocator, parser, input, length);
+}
+HParseResult* h_parse__m(HAllocator* mm__, const HParser* parser, const uint8_t* input, size_t length) { 
   // Set up a parse state...
-  HArena * arena = h_new_arena(0);
+  HArena * arena = h_new_arena(mm__, 0);
   HParseState *parse_state = a_new_(arena, HParseState, 1);
   parse_state->cache = h_hashtable_new(arena, cache_key_equal, // key_equal_func
 					      cache_key_hash); // hash_func
diff --git a/src/hammer.h b/src/hammer.h
index a219dfe2024d4b112a1cac9b20cc2a2a611a3765..2c5a5cf2d0a4a26c55222d93fa2b3131ff020b5e 100644
--- a/src/hammer.h
+++ b/src/hammer.h
@@ -113,18 +113,47 @@ typedef struct HParser_ {
   void *env;
 } HParser;
 
+// {{{ Preprocessor definitions
+#define HAMMER_FN_DECL_NOARG(rtype_t, name)		\
+  rtype_t name(void);					\
+  rtype_t name##__m(HAllocator* mm__)
+
+#define HAMMER_FN_DECL(rtype_t, name, ...)		\
+  rtype_t name(__VA_ARGS__);				\
+  rtype_t name##__m(HAllocator* mm__, __VA_ARGS__)
+
+#define HAMMER_FN_DECL_ATTR(attr, rtype_t, name, ...)			\
+  rtype_t name(__VA_ARGS__) attr;					\
+  rtype_t name##__m(HAllocator* mm__, __VA_ARGS__) attr
+
+#define HAMMER_FN_DECL_VARARGS(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)
+
+// Note: this drops the attributes on the floor for the __v versions
+#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;		\
+  rtype_t name##__mv(HAllocator* mm__, __VA_ARGS__, va_list ap);	\
+  rtype_t name##__v(__VA_ARGS__, va_list ap)
+
+// }}}
+
+
 /**
  * Top-level function to call a parser that has been built over some
  * piece of input (of known size).
  */
-HParseResult* h_parse(const HParser* parser, const uint8_t* input, size_t length);
+HAMMER_FN_DECL(HParseResult*, h_parse, const HParser* parser, const uint8_t* input, size_t length);
 
 /**
  * Given a string, returns a parser that parses that string value. 
  * 
  * Result token type: TT_BYTES
  */
-const HParser* h_token(const uint8_t *str, const size_t len);
+HAMMER_FN_DECL(const HParser*, h_token, const uint8_t *str, const size_t len);
 
 /**
  * Given a single character, returns a parser that parses that 
@@ -132,7 +161,7 @@ const HParser* h_token(const uint8_t *str, const size_t len);
  * 
  * Result token type: TT_UINT
  */
-const HParser* h_ch(const uint8_t c);
+HAMMER_FN_DECL(const HParser*, h_ch, const uint8_t c);
 
 /**
  * Given two single-character bounds, lower and upper, returns a parser
@@ -141,14 +170,14 @@ const HParser* h_ch(const uint8_t c);
  * 
  * Result token type: TT_UINT
  */
-const HParser* h_ch_range(const uint8_t lower, const uint8_t upper);
+HAMMER_FN_DECL(const HParser*, h_ch_range, const uint8_t lower, const uint8_t upper);
 
 /**
  * Given an integer parser, p, and two integer bounds, lower and upper,
  * returns a parser that parses an integral value within the range 
  * [lower, upper] (inclusive).
  */
-const HParser* h_int_range(const HParser *p, const int64_t lower, const int64_t upper);
+HAMMER_FN_DECL(const HParser*, h_int_range, const HParser *p, const int64_t lower, const int64_t upper);
 
 /**
  * Returns a parser that parses the specified number of bits. sign == 
@@ -156,63 +185,63 @@ const HParser* h_int_range(const HParser *p, const int64_t lower, const int64_t
  *
  * Result token type: TT_SINT if sign == true, TT_UINT if sign == false
  */
-const HParser* h_bits(size_t len, bool sign);
+HAMMER_FN_DECL(const HParser*, h_bits, size_t len, bool sign);
 
 /**
  * Returns a parser that parses a signed 8-byte integer value. 
  *
  * Result token type: TT_SINT
  */
-const HParser* h_int64();
+HAMMER_FN_DECL_NOARG(const HParser*, h_int64);
 
 /**
  * Returns a parser that parses a signed 4-byte integer value. 
  *
  * Result token type: TT_SINT
  */
-const HParser* h_int32();
+HAMMER_FN_DECL_NOARG(const HParser*, h_int32);
 
 /**
  * Returns a parser that parses a signed 2-byte integer value. 
  *
  * Result token type: TT_SINT
  */
-const HParser* h_int16();
+HAMMER_FN_DECL_NOARG(const HParser*, h_int16);
 
 /**
  * Returns a parser that parses a signed 1-byte integer value. 
  *
  * Result token type: TT_SINT
  */
-const HParser* h_int8();
+HAMMER_FN_DECL_NOARG(const HParser*, h_int8);
 
 /**
  * Returns a parser that parses an unsigned 8-byte integer value. 
  *
  * Result token type: TT_UINT
  */
-const HParser* h_uint64();
+HAMMER_FN_DECL_NOARG(const HParser*, h_uint64);
 
 /**
  * Returns a parser that parses an unsigned 4-byte integer value. 
  *
  * Result token type: TT_UINT
  */
-const HParser* h_uint32();
+HAMMER_FN_DECL_NOARG(const HParser*, h_uint32);
 
 /**
  * Returns a parser that parses an unsigned 2-byte integer value. 
  *
  * Result token type: TT_UINT
  */
-const HParser* h_uint16();
+HAMMER_FN_DECL_NOARG(const HParser*, h_uint16);
 
 /**
  * Returns a parser that parses an unsigned 1-byte integer value. 
  *
  * Result token type: TT_UINT
  */
-const HParser* h_uint8();
+HAMMER_FN_DECL_NOARG(const HParser*, h_uint8);
 
 /**
  * Given another parser, p, returns a parser that skips any whitespace 
@@ -220,7 +249,7 @@ const HParser* h_uint8();
  *
  * Result token type: p's result type
  */
-const HParser* h_whitespace(const HParser* p);
+HAMMER_FN_DECL(const HParser*, h_whitespace, const HParser* p);
 
 /**
  * Given two parsers, p and q, returns a parser that parses them in
@@ -228,7 +257,7 @@ const HParser* h_whitespace(const HParser* p);
  *
  * Result token type: p's result type
  */
-const HParser* h_left(const HParser* p, const HParser* q);
+HAMMER_FN_DECL(const HParser*, h_left, const HParser* p, const HParser* q);
 
 /**
  * Given two parsers, p and q, returns a parser that parses them in
@@ -236,7 +265,7 @@ const HParser* h_left(const HParser* p, const HParser* q);
  *
  * Result token type: q's result type
  */
-const HParser* h_right(const HParser* p, const HParser* q);
+HAMMER_FN_DECL(const HParser*, h_right, const HParser* p, const HParser* q);
 
 /**
  * Given three parsers, p, x, and q, returns a parser that parses them in
@@ -244,7 +273,7 @@ const HParser* h_right(const HParser* p, const HParser* q);
  *
  * Result token type: x's result type
  */
-const HParser* h_middle(const HParser* p, const HParser* x, const HParser* q);
+HAMMER_FN_DECL(const HParser*, h_middle, const HParser* p, const HParser* x, const HParser* q);
 
 /**
  * Given another parser, p, and a function f, returns a parser that 
@@ -252,21 +281,21 @@ const HParser* h_middle(const HParser* p, const HParser* x, const HParser* q);
  *
  * Result token type: any
  */
-const HParser* h_action(const HParser* p, const HAction a);
+HAMMER_FN_DECL(const HParser*, h_action, const HParser* p, const HAction a);
 
 /**
  * Parse a single character in the given charset. 
  *
  * Result token type: TT_UINT
  */
-const HParser* h_in(const uint8_t *charset, size_t length);
+HAMMER_FN_DECL(const HParser*, h_in, const uint8_t *charset, size_t length);
 
 /**
  * Parse a single character *NOT* in the given charset. 
  *
  * Result token type: TT_UINT
  */
-const HParser* h_not_in(const uint8_t *charset, size_t length);
+HAMMER_FN_DECL(const HParser*, h_not_in, const uint8_t *charset, size_t length);
 
 /**
  * A no-argument parser that succeeds if there is no more input to 
@@ -274,14 +303,14 @@ const HParser* h_not_in(const uint8_t *charset, size_t length);
  *
  * Result token type: None. The HParseResult exists but its AST is NULL.
  */
-const HParser* h_end_p();
+HAMMER_FN_DECL_NOARG(const HParser*, h_end_p);
 
 /**
  * This parser always fails. 
  *
  * Result token type: NULL. Always.
  */
-const HParser* h_nothing_p();
+HAMMER_FN_DECL_NOARG(const HParser*, h_nothing_p);
 
 /**
  * Given a null-terminated list of parsers, apply each parser in order.
@@ -289,7 +318,7 @@ const HParser* h_nothing_p();
  *
  * Result token type: TT_SEQUENCE
  */
-const HParser* h_sequence(const HParser* p, ...) __attribute__((sentinel));
+HAMMER_FN_DECL_VARARGS_ATTR(__attribute__((sentinel)), const HParser*, h_sequence, const HParser* p);
 
 /**
  * Given an array of parsers, p_array, apply each parser in order. The 
@@ -298,7 +327,7 @@ const HParser* h_sequence(const HParser* p, ...) __attribute__((sentinel));
  *
  * Result token type: The type of the first successful parser's result.
  */
-const HParser* h_choice(const HParser* p, ...) __attribute__((sentinel));
+HAMMER_FN_DECL_VARARGS_ATTR(__attribute__((sentinel)), const HParser*, h_choice, const HParser* p);
 
 /**
  * Given two parsers, p1 and p2, this parser succeeds in the following 
@@ -308,7 +337,7 @@ const HParser* h_choice(const HParser* p, ...) __attribute__((sentinel));
  *
  * Result token type: p1's result type.
  */
-const HParser* h_butnot(const HParser* p1, const HParser* p2);
+HAMMER_FN_DECL(const HParser*, h_butnot, const HParser* p1, const HParser* p2);
 
 /**
  * Given two parsers, p1 and p2, this parser succeeds in the following 
@@ -318,7 +347,7 @@ const HParser* h_butnot(const HParser* p1, const HParser* p2);
  *
  * Result token type: p1's result type.
  */
-const HParser* h_difference(const HParser* p1, const HParser* p2);
+HAMMER_FN_DECL(const HParser*, h_difference, const HParser* p1, const HParser* p2);
 
 /**
  * Given two parsers, p1 and p2, this parser succeeds if *either* p1 or
@@ -326,7 +355,7 @@ const HParser* h_difference(const HParser* p1, const HParser* p2);
  *
  * Result token type: The type of the result of whichever parser succeeded.
  */
-const HParser* h_xor(const HParser* p1, const HParser* p2);
+HAMMER_FN_DECL(const HParser*, h_xor, const HParser* p1, const HParser* p2);
 
 /**
  * Given a parser, p, this parser succeeds for zero or more repetitions
@@ -334,7 +363,7 @@ const HParser* h_xor(const HParser* p1, const HParser* p2);
  *
  * Result token type: TT_SEQUENCE
  */
-const HParser* h_many(const HParser* p);
+HAMMER_FN_DECL(const HParser*, h_many, const HParser* p);
 
 /**
  * Given a parser, p, this parser succeeds for one or more repetitions 
@@ -342,7 +371,7 @@ const HParser* h_many(const HParser* p);
  *
  * Result token type: TT_SEQUENCE
  */
-const HParser* h_many1(const HParser* p);
+HAMMER_FN_DECL(const HParser*, h_many1, const HParser* p);
 
 /**
  * Given a parser, p, this parser succeeds for exactly N repetitions 
@@ -350,7 +379,7 @@ const HParser* h_many1(const HParser* p);
  *
  * Result token type: TT_SEQUENCE
  */
-const HParser* h_repeat_n(const HParser* p, const size_t n);
+HAMMER_FN_DECL(const HParser*, h_repeat_n, const HParser* p, const size_t n);
 
 /**
  * Given a parser, p, this parser succeeds with the value p parsed or 
@@ -358,7 +387,7 @@ const HParser* h_repeat_n(const HParser* p, const size_t n);
  *
  * Result token type: If p succeeded, the type of its result; if not, TT_NONE.
  */
-const HParser* h_optional(const HParser* p);
+HAMMER_FN_DECL(const HParser*, h_optional, const HParser* p);
 
 /**
  * Given a parser, p, this parser succeeds if p succeeds, but doesn't 
@@ -366,7 +395,7 @@ const HParser* h_optional(const HParser* p);
  *
  * Result token type: None. The HParseResult exists but its AST is NULL.
  */
-const HParser* h_ignore(const HParser* p);
+HAMMER_FN_DECL(const HParser*, h_ignore, const HParser* p);
 
 /**
  * Given a parser, p, and a parser for a separator, sep, this parser 
@@ -377,7 +406,7 @@ const HParser* h_ignore(const HParser* p);
  *
  * Result token type: TT_SEQUENCE
  */
-const HParser* h_sepBy(const HParser* p, const HParser* sep);
+HAMMER_FN_DECL(const HParser*, h_sepBy, const HParser* p, const HParser* sep);
 
 /**
  * Given a parser, p, and a parser for a separator, sep, this parser matches a list of things that p can parse, separated by sep. Unlike sepBy, this ensures that the result has at least one element.
@@ -385,14 +414,14 @@ const HParser* h_sepBy(const HParser* p, const HParser* sep);
  *
  * Result token type: TT_SEQUENCE
  */
-const HParser* h_sepBy1(const HParser* p, const HParser* sep);
+HAMMER_FN_DECL(const HParser*, h_sepBy1, const HParser* p, const HParser* sep);
 
 /**
  * This parser always returns a zero length match, i.e., empty string. 
  *
  * Result token type: None. The HParseResult exists but its AST is NULL.
  */
-const HParser* h_epsilon_p();
+HAMMER_FN_DECL_NOARG(const HParser*, h_epsilon_p);
 
 /**
  * This parser applies its first argument to read an unsigned integer
@@ -403,7 +432,7 @@ const HParser* h_epsilon_p();
  *
  * Result token type: TT_SEQUENCE
  */
-const HParser* h_length_value(const HParser* length, const HParser* value);
+HAMMER_FN_DECL(const HParser*, h_length_value, const HParser* length, const HParser* value);
 
 /**
  * This parser attaches a predicate function, which returns true or 
@@ -418,7 +447,7 @@ const HParser* h_length_value(const HParser* length, const HParser* value);
  * 
  * Result token type: p's result type if pred succeeded, NULL otherwise.
  */
-const HParser* h_attr_bool(const HParser* p, HPredicate pred);
+HAMMER_FN_DECL(const HParser*, h_attr_bool, const HParser* p, HPredicate pred);
 
 /**
  * The 'and' parser asserts that a conditional syntax is satisfied, 
@@ -435,7 +464,7 @@ const HParser* h_attr_bool(const HParser* p, HPredicate pred);
  *
  * Result token type: None. The HParseResult exists but its AST is NULL.
  */
-const HParser* h_and(const HParser* p);
+HAMMER_FN_DECL(const HParser*, h_and, const HParser* p);
 
 /**
  * The 'not' parser asserts that a conditional syntax is *not* 
@@ -455,7 +484,7 @@ const HParser* h_and(const HParser* p);
  * 
  * Result token type: None. The HParseResult exists but its AST is NULL.
  */
-const HParser* h_not(const HParser* p);
+HAMMER_FN_DECL(const HParser*, h_not, const HParser* p);
 
 /**
  * Create a parser that just calls out to another, as yet unknown, 
@@ -466,35 +495,35 @@ const HParser* h_not(const HParser* p);
  * Result token type: the type of whatever parser is bound to it with
  * bind_indirect().
  */
-HParser *h_indirect();
+HAMMER_FN_DECL_NOARG(HParser*, h_indirect);
 
 /**
  * Set the inner parser of an indirect. See comments on indirect for 
  * details.
  */
-void h_bind_indirect(HParser* indirect, const HParser* inner);
+HAMMER_FN_DECL(void, h_bind_indirect, HParser* indirect, const HParser* inner);
 
 /**
  * Free the memory allocated to an HParseResult when it is no longer needed.
  */
-void h_parse_result_free(HParseResult *result);
+HAMMER_FN_DECL(void, h_parse_result_free, HParseResult *result);
 
 // Some debugging aids
 /**
  * Format token into a compact unambiguous form. Useful for parser test cases.
  * Caller is responsible for freeing the result.
  */
-char* h_write_result_unamb(const HParsedToken* tok);
+HAMMER_FN_DECL(char*, h_write_result_unamb, const HParsedToken* tok);
 /**
  * Format token to the given output stream. Indent starting at
  * [indent] spaces, with [delta] spaces between levels.
  */
-void h_pprint(FILE* stream, const HParsedToken* tok, int indent, int delta);
+HAMMER_FN_DECL(void, h_pprint, FILE* stream, const HParsedToken* tok, int indent, int delta);
 
 /**
  * TODO: Document me
  */
-HBitWriter *h_bit_writer_new(void);
+HBitWriter *h_bit_writer_new(HAllocator* mm__);
 
 /**
  * TODO: Document me
@@ -506,7 +535,7 @@ void h_bit_writer_put(HBitWriter* w, unsigned long long data, size_t nbits);
  * Must not free [w] until you're done with the result.
  * [len] is in bytes.
  */
-const uint8_t *h_bit_writer_get_buffer(HBitWriter* w, size_t *len);
+const uint8_t* h_bit_writer_get_buffer(HBitWriter* w, size_t *len);
 
 /**
  * TODO: Document me
diff --git a/src/internal.h b/src/internal.h
index e8a3f9147a9c213f10acccc66ca5a927f66ef168..b7f56b6004c16cd7b52a4dd62198f016b55945ef 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -29,9 +29,28 @@
       errx(1, "Assertion failed (programmer error): %s", message);	\
   } while(0)
 #endif
+
+#define HAMMER_FN_IMPL_NOARGS(rtype_t, name) \
+  rtype_t name(void) {			     \
+    return name##__m(system_allocator);	     \
+  }					     \
+  rtype_t name##__m(HAllocator* mm__)
+// Functions with arguments are difficult to forward cleanly. Alas, we will need to forward them manually.
+
+#define h_new(type, count) ((type*)(mm__->alloc(mm__, sizeof(type)*(count))))
+#define h_free(addr) (mm__->free(mm__, (addr)))
+
 #define false 0
 #define true 1
 
+// This is going to be generally useful.
+static inline void h_generic_free(HAllocator *allocator, void* ptr) {
+  allocator->free(allocator, ptr);
+}
+
+HAllocator system_allocator;
+
+
 typedef struct HInputStream_ {
   // This should be considered to be a really big value type.
   const uint8_t *input;
@@ -155,24 +174,6 @@ typedef struct HParserCacheValue_t {
   };
 } HParserCacheValue;
 
-typedef unsigned int *HCharset;
-
-static inline HCharset new_charset() {
-  HCharset cs = g_new0(unsigned int, 256 / sizeof(unsigned int));
-  return cs;
-}
-
-static inline int charset_isset(HCharset cs, uint8_t pos) {
-  return !!(cs[pos / sizeof(*cs)] & (1 << (pos % sizeof(*cs))));
-}
-
-static inline void charset_set(HCharset cs, uint8_t pos, int val) {
-  cs[pos / sizeof(*cs)] =
-    val
-    ? cs[pos / sizeof(*cs)] |  (1 << (pos % sizeof(*cs)))
-    : cs[pos / sizeof(*cs)] & ~(1 << (pos % sizeof(*cs)));
-}
-
 // TODO(thequux): Set symbol visibility for these functions so that they aren't exported.
 
 long long h_read_bits(HInputStream* state, int count, char signed_p);
@@ -198,7 +199,6 @@ int   h_hashtable_present(HHashTable* ht, void* key);
 void  h_hashtable_del(HHashTable* ht, void* key);
 void  h_hashtable_free(HHashTable* ht);
 
-
 #if 0
 #include <malloc.h>
 #define h_arena_malloc(a, s) malloc(s)
diff --git a/src/parsers/action.c b/src/parsers/action.c
index 479a840cd8382db524762241ade0d2605ec2416f..0f1686f22245d91e9147ffa0054b512ecfc89fd4 100644
--- a/src/parsers/action.c
+++ b/src/parsers/action.c
@@ -23,10 +23,14 @@ static const HParserVtable action_vt = {
   .parse = parse_action,
 };
 
-const HParser* h_action(const HParser* p, const HAction a) { 
-  HParser *res = g_new(HParser, 1);
+const HParser* h_action(const HParser* p, const HAction a) {
+  return h_action__m(&system_allocator, p, a);
+}
+
+const HParser* h_action__m(HAllocator* mm__, const HParser* p, const HAction a) {
+  HParser *res = h_new(HParser, 1);
   res->vtable = &action_vt;
-  HParseAction *env = g_new(HParseAction, 1);
+  HParseAction *env = h_new(HParseAction, 1);
   env->p = p;
   env->action = a;
   res->env = (void*)env;
diff --git a/src/parsers/and.c b/src/parsers/and.c
index fb117fb153a482794d9c4c04bdb0c5caab182af8..532cbbaf7c249f2fb06c4af47495325614550807 100644
--- a/src/parsers/and.c
+++ b/src/parsers/and.c
@@ -13,9 +13,13 @@ static const HParserVtable and_vt = {
   .parse = parse_and,
 };
 
+
 const HParser* h_and(const HParser* p) {
+  return h_and__m(&system_allocator, p);
+}
+const HParser* h_and__m(HAllocator* mm__, const HParser* p) {
   // zero-width postive lookahead
-  HParser *res = g_new(HParser, 1);
+  HParser *res = h_new(HParser, 1);
   res->env = (void*)p;
   res->vtable = &and_vt;
   return res;
diff --git a/src/parsers/attr_bool.c b/src/parsers/attr_bool.c
index bf9e6dcffa34ba8eb251b10bae0a60b8ae444e88..6fa36f844d94725369d1079e583723b2e0e90356 100644
--- a/src/parsers/attr_bool.c
+++ b/src/parsers/attr_bool.c
@@ -21,10 +21,14 @@ static const HParserVtable attr_bool_vt = {
   .parse = parse_attr_bool,
 };
 
-const HParser* h_attr_bool(const HParser* p, HPredicate pred) { 
-  HParser *res = g_new(HParser, 1);
+
+const HParser* h_attr_bool(const HParser* p, HPredicate pred) {
+  return h_attr_bool__m(&system_allocator, p, pred);
+}
+const HParser* h_attr_bool__m(HAllocator* mm__, const HParser* p, HPredicate pred) { 
+  HParser *res = h_new(HParser, 1);
   res->vtable = &attr_bool_vt;
-  HAttrBool *env = g_new(HAttrBool, 1);
+  HAttrBool *env = h_new(HAttrBool, 1);
   env->p = p;
   env->pred = pred;
   res->env = (void*)env;
diff --git a/src/parsers/bits.c b/src/parsers/bits.c
index 32b7a552b8bfb236d44ced877f2bd88cd4dd8401..196e33bba25d6eab243d18570ac2188acad060a0 100644
--- a/src/parsers/bits.c
+++ b/src/parsers/bits.c
@@ -20,18 +20,24 @@ static const HParserVtable bits_vt = {
   .parse = parse_bits,
 };
 const HParser* h_bits(size_t len, bool sign) {
-  struct bits_env *env = g_new(struct bits_env, 1);
+  return h_bits__m(&system_allocator, len, sign);
+}
+const HParser* h_bits__m(HAllocator* mm__, size_t len, bool sign) {
+  struct bits_env *env = h_new(struct bits_env, 1);
   env->length = len;
   env->signedp = sign;
-  HParser *res = g_new(HParser, 1);
+  HParser *res = h_new(HParser, 1);
   res->vtable = &bits_vt;
   res->env = env;
   return res;
 }
 
 #define SIZED_BITS(name_pre, len, signedp) \
-  const HParser* h_##name_pre##len () {	       \
-    return h_bits(len, signedp);	       \
+  const HParser* h_##name_pre##len () {				\
+    return h_bits__m(&system_allocator, len, signedp);		\
+  }								\
+  const HParser* h_##name_pre##len##__m(HAllocator* mm__) {	\
+    return h_bits__m(mm__, len, signedp);			\
   }
 SIZED_BITS(int, 8, true)
 SIZED_BITS(int, 16, true)
diff --git a/src/parsers/butnot.c b/src/parsers/butnot.c
index 5026d79d0df540530b6879db8947acb8bbb11e9d..422e0e1fd64309e57b46b9d17918282aea4a5193 100644
--- a/src/parsers/butnot.c
+++ b/src/parsers/butnot.c
@@ -39,10 +39,13 @@ static const HParserVtable butnot_vt = {
   .parse = parse_butnot,
 };
 
-const HParser* h_butnot(const HParser* p1, const HParser* p2) { 
-  HTwoParsers *env = g_new(HTwoParsers, 1);
+const HParser* h_butnot(const HParser* p1, const HParser* p2) {
+  return h_butnot__m(&system_allocator, p1, p2);
+}
+const HParser* h_butnot__m(HAllocator* mm__, const HParser* p1, const HParser* p2) {
+  HTwoParsers *env = h_new(HTwoParsers, 1);
   env->p1 = p1; env->p2 = p2;
-  HParser *ret = g_new(HParser, 1);
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &butnot_vt; ret->env = (void*)env;
   return ret;
 }
diff --git a/src/parsers/ch.c b/src/parsers/ch.c
index fbfa57edaabdc4b45edf2e19b0a4643fe4ac30ed..bb3073f0e80db93fe95332d6850df9be263f0387 100644
--- a/src/parsers/ch.c
+++ b/src/parsers/ch.c
@@ -15,8 +15,12 @@ static HParseResult* parse_ch(void* env, HParseState *state) {
 static const HParserVtable ch_vt = {
   .parse = parse_ch,
 };
-const HParser* h_ch(const uint8_t c) {  
-  HParser *ret = g_new(HParser, 1);
+
+const HParser* h_ch(const uint8_t c) {
+  return h_ch__m(&system_allocator, c);
+}
+const HParser* h_ch__m(HAllocator* mm__, const uint8_t c) {  
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &ch_vt;
   ret->env = GUINT_TO_POINTER(c);
   return (const HParser*)ret;
diff --git a/src/parsers/charset.c b/src/parsers/charset.c
index b9642fccd0aef2394f64de70fed56e911a918ad9..f11715ff1ac1670d229ab4c1906c92da59fffc20 100644
--- a/src/parsers/charset.c
+++ b/src/parsers/charset.c
@@ -1,5 +1,24 @@
+#include <string.h>
 #include "parser_internal.h"
 
+typedef unsigned int *HCharset;
+
+static inline HCharset new_charset(HAllocator* mm__) {
+  HCharset cs = h_new(unsigned int, 256 / sizeof(unsigned int));
+  memset(cs, 0, 256);
+  return cs;
+}
+
+static inline int charset_isset(HCharset cs, uint8_t pos) {
+  return !!(cs[pos / sizeof(*cs)] & (1 << (pos % sizeof(*cs))));
+}
+
+static inline void charset_set(HCharset cs, uint8_t pos, int val) {
+  cs[pos / sizeof(*cs)] =
+    val
+    ? cs[pos / sizeof(*cs)] |  (1 << (pos % sizeof(*cs)))
+    : cs[pos / sizeof(*cs)] & ~(1 << (pos % sizeof(*cs)));
+}
 
 static HParseResult* parse_charset(void *env, HParseState *state) {
   uint8_t in = h_read_bits(&state->input_stream, 8, false);
@@ -18,8 +37,11 @@ static const HParserVtable charset_vt = {
 };
 
 const HParser* h_ch_range(const uint8_t lower, const uint8_t upper) {
-  HParser *ret = g_new(HParser, 1);
-  HCharset cs = new_charset();
+  return h_ch_range__m(&system_allocator, lower, upper);
+}
+const HParser* h_ch_range__m(HAllocator* mm__, const uint8_t lower, const uint8_t upper) {
+  HParser *ret = h_new(HParser, 1);
+  HCharset cs = new_charset(mm__);
   for (int i = 0; i < 256; i++)
     charset_set(cs, i, (lower <= i) && (i <= upper));
   ret->vtable = &charset_vt;
@@ -28,9 +50,9 @@ const HParser* h_ch_range(const uint8_t lower, const uint8_t upper) {
 }
 
 
-const HParser* h_in_or_not(const uint8_t *options, size_t count, int val) {
-  HParser *ret = g_new(HParser, 1);
-  HCharset cs = new_charset();
+static const HParser* h_in_or_not__m(HAllocator* mm__, const uint8_t *options, size_t count, int val) {
+  HParser *ret = h_new(HParser, 1);
+  HCharset cs = new_charset(mm__);
   for (size_t i = 0; i < 256; i++)
     charset_set(cs, i, 1-val);
   for (size_t i = 0; i < count; i++)
@@ -42,10 +64,18 @@ const HParser* h_in_or_not(const uint8_t *options, size_t count, int val) {
 }
 
 const HParser* h_in(const uint8_t *options, size_t count) {
-  return h_in_or_not(options, count, 1);
+  return h_in_or_not__m(&system_allocator, options, count, 1);
+}
+
+const HParser* h_in__m(HAllocator* mm__, const uint8_t *options, size_t count) {
+  return h_in_or_not__m(mm__, options, count, 1);
 }
 
 const HParser* h_not_in(const uint8_t *options, size_t count) {
-  return h_in_or_not(options, count, 0);
+  return h_in_or_not__m(&system_allocator, options, count, 0);
+}
+
+const HParser* h_not_in__m(HAllocator* mm__, const uint8_t *options, size_t count) {
+  return h_in_or_not__m(mm__, options, count, 0);
 }
 
diff --git a/src/parsers/choice.c b/src/parsers/choice.c
index 082a2e10f343b1b97ddc09ef4958193b6e6adc65..2430352236b56bb63e4eca2d4dd3fd5430ea7cdf 100644
--- a/src/parsers/choice.c
+++ b/src/parsers/choice.c
@@ -25,20 +25,40 @@ static const HParserVtable choice_vt = {
 };
 
 const HParser* h_choice(const HParser* p, ...) {
+  va_list ap;
+  va_start(ap, p);
+  const HParser* ret = h_choice__mv(&system_allocator, p,  ap);
+  va_end(ap);
+  return ret;
+}
+
+const HParser* h_choice__m(HAllocator* mm__, const HParser* p, ...) {
+  va_list ap;
+  va_start(ap, p);
+  const HParser* ret = h_choice__mv(mm__, p,  ap);
+  va_end(ap);
+  return ret;
+}
+
+const HParser* h_choice__v(const HParser* p, va_list ap) {
+  return h_choice__mv(&system_allocator, p, ap);
+}
+
+const HParser* h_choice__mv(HAllocator* mm__, const HParser* p, va_list ap_) {
   va_list ap;
   size_t len = 0;
-  HSequence *s = g_new(HSequence, 1);
+  HSequence *s = h_new(HSequence, 1);
 
   const HParser *arg;
-  va_start(ap, p);
+  va_copy(ap, ap_);
   do {
     len++;
     arg = va_arg(ap, const HParser *);
   } while (arg);
   va_end(ap);
-  s->p_array = g_new(const HParser *, len);
+  s->p_array = h_new(const HParser *, len);
 
-  va_start(ap, p);
+  va_copy(ap, ap_);
   s->p_array[0] = p;
   for (size_t i = 1; i < len; i++) {
     s->p_array[i] = va_arg(ap, const HParser *);
@@ -46,7 +66,7 @@ const HParser* h_choice(const HParser* p, ...) {
   va_end(ap);
 
   s->len = len;
-  HParser *ret = g_new(HParser, 1);
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &choice_vt; ret->env = (void*)s;
   return ret;
 }
diff --git a/src/parsers/difference.c b/src/parsers/difference.c
index 7f167a003fc3edd69d9ffdadaf97466a5a5bc97a..c6cc69cef86bfba3537b3c98c8a2777447c4f598 100644
--- a/src/parsers/difference.c
+++ b/src/parsers/difference.c
@@ -38,10 +38,13 @@ static HParserVtable difference_vt = {
   .parse = parse_difference,
 };
 
-const HParser* h_difference(const HParser* p1, const HParser* p2) { 
-  HTwoParsers *env = g_new(HTwoParsers, 1);
+const HParser* h_difference(const HParser* p1, const HParser* p2) {
+  return h_difference__m(&system_allocator, p1, p2);
+}
+const HParser* h_difference__m(HAllocator* mm__, const HParser* p1, const HParser* p2) { 
+  HTwoParsers *env = h_new(HTwoParsers, 1);
   env->p1 = p1; env->p2 = p2;
-  HParser *ret = g_new(HParser, 1);
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &difference_vt; ret->env = (void*)env;
   return ret;
 }
diff --git a/src/parsers/end.c b/src/parsers/end.c
index 8e427bd50eb238b2ed5960693c5b72aa30a306c6..0f0d1c7d6c66375256f540f2a00b849ff82170fa 100644
--- a/src/parsers/end.c
+++ b/src/parsers/end.c
@@ -14,8 +14,13 @@ static const HParserVtable end_vt = {
   .parse = parse_end,
 };
 
-const HParser* h_end_p() { 
-  HParser *ret = g_new(HParser, 1);
-  ret->vtable = &end_vt; ret->env = NULL;
+const HParser* h_end_p() {
+  return h_end_p__m(&system_allocator);
+}
+
+const HParser* h_end_p__m(HAllocator* mm__) { 
+  HParser *ret = h_new(HParser, 1);
+  ret->vtable = &end_vt;
+  ret->env = NULL;
   return (const HParser*)ret;
 }
diff --git a/src/parsers/epsilon.c b/src/parsers/epsilon.c
index dc6d7a6db8b294dfab3b636ee72af5d7b4e7e646..ae959cd5455d55cb31446316001ade32904a63c4 100644
--- a/src/parsers/epsilon.c
+++ b/src/parsers/epsilon.c
@@ -20,3 +20,6 @@ static const HParser epsilon_p = {
 const HParser* h_epsilon_p() {
   return &epsilon_p;
 }
+const HParser* h_epsilon_p__m(HAllocator* mm__) {
+  return &epsilon_p;
+}
diff --git a/src/parsers/ignore.c b/src/parsers/ignore.c
index 5972548360cb3bbbc341484d5caa17dd6df89dfc..03cdc107102841e16449aa7483171a8f3e42b33f 100644
--- a/src/parsers/ignore.c
+++ b/src/parsers/ignore.c
@@ -15,7 +15,10 @@ static const HParserVtable ignore_vt = {
 };
 
 const HParser* h_ignore(const HParser* p) {
-  HParser* ret = g_new(HParser, 1);
+  return h_ignore__m(&system_allocator, p);
+}
+const HParser* h_ignore__m(HAllocator* mm__, const HParser* p) {
+  HParser* ret = h_new(HParser, 1);
   ret->vtable = &ignore_vt;
   ret->env = (void*)p;
   return ret;
diff --git a/src/parsers/ignoreseq.c b/src/parsers/ignoreseq.c
index 8aac2c82c5f09658c9962860f7f625bff70523f2..228f63575febe5021b272c65a69b701089e7e081 100644
--- a/src/parsers/ignoreseq.c
+++ b/src/parsers/ignoreseq.c
@@ -35,38 +35,48 @@ static const HParserVtable ignoreseq_vt = {
 // API frontends
 //
 
-static const HParser* h_leftright(const HParser* p, const HParser* q, size_t which) {
-  HIgnoreSeq *seq = g_new(HIgnoreSeq, 1);
-  seq->parsers = g_new(const HParser*, 2);
+static const HParser* h_leftright__m(HAllocator* mm__, const HParser* p, const HParser* q, size_t which) {
+  HIgnoreSeq *seq = h_new(HIgnoreSeq, 1);
+  seq->parsers = h_new(const HParser*, 2);
   seq->parsers[0] = p;
   seq->parsers[1] = q;
   seq->count = 2;
   seq->which = which;
 
-  HParser *ret = g_new(HParser, 1);
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &ignoreseq_vt;
   ret->env = (void*)seq;
   return ret;
 }
 
 const HParser* h_left(const HParser* p, const HParser* q) {
-  return h_leftright(p, q, 0);
+  return h_leftright__m(&system_allocator, p, q, 0);
+}
+const HParser* h_left__m(HAllocator* mm__, const HParser* p, const HParser* q) {
+  return h_leftright__m(mm__, p, q, 0);
 }
 
 const HParser* h_right(const HParser* p, const HParser* q) {
-  return h_leftright(p, q, 1);
+  return h_leftright__m(&system_allocator, p, q, 1);
+}
+const HParser* h_right__m(HAllocator* mm__, const HParser* p, const HParser* q) {
+  return h_leftright__m(mm__, p, q, 1);
 }
 
+
 const HParser* h_middle(const HParser* p, const HParser* x, const HParser* q) {
-  HIgnoreSeq *seq = g_new(HIgnoreSeq, 1);
-  seq->parsers = g_new(const HParser*, 3);
+  return h_middle__m(&system_allocator, p, x, q);
+}
+const HParser* h_middle__m(HAllocator* mm__, const HParser* p, const HParser* x, const HParser* q) {
+  HIgnoreSeq *seq = h_new(HIgnoreSeq, 1);
+  seq->parsers = h_new(const HParser*, 3);
   seq->parsers[0] = p;
   seq->parsers[1] = x;
   seq->parsers[2] = q;
   seq->count = 3;
   seq->which = 1;
 
-  HParser *ret = g_new(HParser, 1);
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &ignoreseq_vt;
   ret->env = (void*)seq;
   return ret;
diff --git a/src/parsers/indirect.c b/src/parsers/indirect.c
index 758116de640ef9a179b934051d7b6421ce4e33cf..96e2a65d4c32f6cb2ea8b3cb05e4e230ab91c4d4 100644
--- a/src/parsers/indirect.c
+++ b/src/parsers/indirect.c
@@ -13,7 +13,10 @@ void h_bind_indirect(HParser* indirect, const HParser* inner) {
 }
 
 HParser* h_indirect() {
-  HParser *res = g_new(HParser, 1);
+  return h_indirect__m(&system_allocator);
+}
+HParser* h_indirect__m(HAllocator* mm__) {
+  HParser *res = h_new(HParser, 1);
   res->vtable = &indirect_vt;
   res->env = NULL;
   return res;
diff --git a/src/parsers/int_range.c b/src/parsers/int_range.c
index 9fb1c7edbe5d69e23a5a07d8ba10942e89fc69da..2a1db63ca3c3c6bc103e8b941ed0e7119ba91d17 100644
--- a/src/parsers/int_range.c
+++ b/src/parsers/int_range.c
@@ -33,6 +33,9 @@ static const HParserVtable int_range_vt = {
 };
 
 const HParser* h_int_range(const HParser *p, const int64_t lower, const int64_t upper) {
+  return h_int_range__m(&system_allocator, p, lower, upper);
+}
+const HParser* h_int_range__m(HAllocator* mm__, const HParser *p, const int64_t lower, const int64_t upper) {
   // p must be an integer parser, which means it's using parse_bits
   // TODO: re-add this check
   //assert_message(p->vtable == &bits_vt, "int_range requires an integer parser"); 
@@ -40,11 +43,11 @@ const HParser* h_int_range(const HParser *p, const int64_t lower, const int64_t
   // and regardless, the bounds need to fit in the parser in question
   // TODO: check this as well.
 
-  HRange *r_env = g_new(HRange, 1);
+  HRange *r_env = h_new(HRange, 1);
   r_env->p = p;
   r_env->lower = lower;
   r_env->upper = upper;
-  HParser *ret = g_new(HParser, 1);
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &int_range_vt;
   ret->env = (void*)r_env;
   return ret;
diff --git a/src/parsers/many.c b/src/parsers/many.c
index f18be26a0f9c0a0b82fa0586940bcc62fa8531de..6cb818bcbe8c6ea9be45ead32b76711eab32968b 100644
--- a/src/parsers/many.c
+++ b/src/parsers/many.c
@@ -49,10 +49,13 @@ static const HParserVtable many_vt = {
 };
 
 const HParser* h_many(const HParser* p) {
-  HParser *res = g_new(HParser, 1);
-  HRepeat *env = g_new(HRepeat, 1);
+  return h_many__m(&system_allocator, p);
+}
+const HParser* h_many__m(HAllocator* mm__, const HParser* p) {
+  HParser *res = h_new(HParser, 1);
+  HRepeat *env = h_new(HRepeat, 1);
   env->p = p;
-  env->sep = h_epsilon_p();
+  env->sep = h_epsilon_p__m(mm__);
   env->count = 0;
   env->min_p = true;
   res->vtable = &many_vt;
@@ -61,10 +64,13 @@ const HParser* h_many(const HParser* p) {
 }
 
 const HParser* h_many1(const HParser* p) {
-  HParser *res = g_new(HParser, 1);
-  HRepeat *env = g_new(HRepeat, 1);
+  return h_many1__m(&system_allocator, p);
+}
+const HParser* h_many1__m(HAllocator* mm__, const HParser* p) {
+  HParser *res = h_new(HParser, 1);
+  HRepeat *env = h_new(HRepeat, 1);
   env->p = p;
-  env->sep = h_epsilon_p();
+  env->sep = h_epsilon_p__m(mm__);
   env->count = 1;
   env->min_p = true;
   res->vtable = &many_vt;
@@ -73,10 +79,13 @@ const HParser* h_many1(const HParser* p) {
 }
 
 const HParser* h_repeat_n(const HParser* p, const size_t n) {
-  HParser *res = g_new(HParser, 1);
-  HRepeat *env = g_new(HRepeat, 1);
+  return h_repeat_n__m(&system_allocator, p, n);
+}
+const HParser* h_repeat_n__m(HAllocator* mm__, const HParser* p, const size_t n) {
+  HParser *res = h_new(HParser, 1);
+  HRepeat *env = h_new(HRepeat, 1);
   env->p = p;
-  env->sep = h_epsilon_p();
+  env->sep = h_epsilon_p__m(mm__);
   env->count = n;
   env->min_p = false;
   res->vtable = &many_vt;
@@ -85,8 +94,11 @@ const HParser* h_repeat_n(const HParser* p, const size_t n) {
 }
 
 const HParser* h_sepBy(const HParser* p, const HParser* sep) {
-  HParser *res = g_new(HParser, 1);
-  HRepeat *env = g_new(HRepeat, 1);
+  return h_sepBy__m(&system_allocator, p, sep);
+}
+const HParser* h_sepBy__m(HAllocator* mm__, const HParser* p, const HParser* sep) {
+  HParser *res = h_new(HParser, 1);
+  HRepeat *env = h_new(HRepeat, 1);
   env->p = p;
   env->sep = sep;
   env->count = 0;
@@ -97,8 +109,11 @@ const HParser* h_sepBy(const HParser* p, const HParser* sep) {
 }
 
 const HParser* h_sepBy1(const HParser* p, const HParser* sep) {
-  HParser *res = g_new(HParser, 1);
-  HRepeat *env = g_new(HRepeat, 1);
+  return h_sepBy1__m(&system_allocator, p, sep);
+}
+const HParser* h_sepBy1__m(HAllocator* mm__, const HParser* p, const HParser* sep) {
+  HParser *res = h_new(HParser, 1);
+  HRepeat *env = h_new(HRepeat, 1);
   env->p = p;
   env->sep = sep;
   env->count = 1;
@@ -135,9 +150,12 @@ static const HParserVtable length_value_vt = {
 };
 
 const HParser* h_length_value(const HParser* length, const HParser* value) {
-  HParser *res = g_new(HParser, 1);
+  return h_length_value__m(&system_allocator, length, value);
+}
+const HParser* h_length_value__m(HAllocator* mm__, const HParser* length, const HParser* value) {
+  HParser *res = h_new(HParser, 1);
   res->vtable = &length_value_vt;
-  HLenVal *env = g_new(HLenVal, 1);
+  HLenVal *env = h_new(HLenVal, 1);
   env->length = length;
   env->value = value;
   res->env = (void*)env;
diff --git a/src/parsers/not.c b/src/parsers/not.c
index 1c46b6dc394f186977d04eef0062b4fbaa5c1ce9..73cf1295fc695d082058798b5a3f88522d34d891 100644
--- a/src/parsers/not.c
+++ b/src/parsers/not.c
@@ -15,7 +15,10 @@ static const HParserVtable not_vt = {
 };
 
 const HParser* h_not(const HParser* p) {
-  HParser *res = g_new(HParser, 1);
+  return h_not__m(&system_allocator, p);
+}
+const HParser* h_not__m(HAllocator* mm__, const HParser* p) {
+  HParser *res = h_new(HParser, 1);
   res->vtable = &not_vt;
   res->env = (void*)p;
   return res;
diff --git a/src/parsers/nothing.c b/src/parsers/nothing.c
index 9f81c02841ad298a6d714206961dfcc8edde0ab5..120c8ef305498bc8d4fe15baa8935196f00b9caa 100644
--- a/src/parsers/nothing.c
+++ b/src/parsers/nothing.c
@@ -10,8 +10,11 @@ static const HParserVtable nothing_vt = {
   .parse = parse_nothing,
 };
 
-const HParser* h_nothing_p() { 
-  HParser *ret = g_new(HParser, 1);
+const HParser* h_nothing_p() {
+  return h_nothing_p__m(&system_allocator);
+}
+const HParser* h_nothing_p__m(HAllocator* mm__) { 
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &nothing_vt; ret->env = NULL;
   return (const HParser*)ret;
 }
diff --git a/src/parsers/optional.c b/src/parsers/optional.c
index c0845765e5206283a2b465d0f668695a5acf9fae..9625fa0f5cf2c40011e1317222f312006eb33b27 100644
--- a/src/parsers/optional.c
+++ b/src/parsers/optional.c
@@ -16,9 +16,12 @@ static const HParserVtable optional_vt = {
 };
 
 const HParser* h_optional(const HParser* p) {
+  return h_optional__m(&system_allocator, p);
+}
+const HParser* h_optional__m(HAllocator* mm__, const HParser* p) {
   // TODO: re-add this
   //assert_message(p->vtable != &ignore_vt, "Thou shalt ignore an option, rather than the other way 'round.");
-  HParser *ret = g_new(HParser, 1);
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &optional_vt;
   ret->env = (void*)p;
   return ret;
diff --git a/src/parsers/sequence.c b/src/parsers/sequence.c
index 54196da103aa9ac288c8aad70ebda8c590d1bb6f..dece4f0eab99386c05bc266bb0d366dc7487f2b6 100644
--- a/src/parsers/sequence.c
+++ b/src/parsers/sequence.c
@@ -27,20 +27,40 @@ static const HParserVtable sequence_vt = {
   .parse = parse_sequence,
 };
 
-const HParser* h_sequence(const HParser *p, ...) {
+const HParser* h_sequence(const HParser* p, ...) {
+  va_list ap;
+  va_start(ap, p);
+  const HParser* ret = h_sequence__mv(&system_allocator, p,  ap);
+  va_end(ap);
+  return ret;
+}
+
+const HParser* h_sequence__m(HAllocator* mm__, const HParser* p, ...) {
+  va_list ap;
+  va_start(ap, p);
+  const HParser* ret = h_sequence__mv(mm__, p,  ap);
+  va_end(ap);
+  return ret;
+}
+
+const HParser* h_sequence__v(const HParser* p, va_list ap) {
+  return h_sequence__mv(&system_allocator, p, ap);
+}
+
+const HParser* h_sequence__mv(HAllocator* mm__, const HParser *p, va_list ap_) {
   va_list ap;
   size_t len = 0;
   const HParser *arg;
-  va_start(ap, p);
+  va_copy(ap, ap_);
   do {
     len++;
     arg = va_arg(ap, const HParser *);
   } while (arg);
   va_end(ap);
-  HSequence *s = g_new(HSequence, 1);
-  s->p_array = g_new(const HParser *, len);
+  HSequence *s = h_new(HSequence, 1);
+  s->p_array = h_new(const HParser *, len);
 
-  va_start(ap, p);
+  va_copy(ap, ap_);
   s->p_array[0] = p;
   for (size_t i = 1; i < len; i++) {
     s->p_array[i] = va_arg(ap, const HParser *);
@@ -48,7 +68,7 @@ const HParser* h_sequence(const HParser *p, ...) {
   va_end(ap);
 
   s->len = len;
-  HParser *ret = g_new(HParser, 1);
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &sequence_vt; ret->env = (void*)s;
   return ret;
 }
diff --git a/src/parsers/token.c b/src/parsers/token.c
index b3be207c3a1bea8b81bba908b0fc31780ef5232b..e57c71d2ac61c207139e683945d72cf92087696d 100644
--- a/src/parsers/token.c
+++ b/src/parsers/token.c
@@ -24,10 +24,13 @@ const const HParserVtable token_vt = {
   .parse = parse_token,
 };
 
-const HParser* h_token(const uint8_t *str, const size_t len) { 
-  HToken *t = g_new(HToken, 1);
+const HParser* h_token(const uint8_t *str, const size_t len) {
+  return h_token__m(&system_allocator, str, len);
+}
+const HParser* h_token__m(HAllocator* mm__, const uint8_t *str, const size_t len) { 
+  HToken *t = h_new(HToken, 1);
   t->str = (uint8_t*)str, t->len = len;
-  HParser *ret = g_new(HParser, 1);
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &token_vt;
   ret->env = t;
   return (const HParser*)ret;
diff --git a/src/parsers/unimplemented.c b/src/parsers/unimplemented.c
index 99d153b715b92ea4664e8475bcc4cc95cbc044b0..35ee391c228246698f13da7b68b4524f732d228e 100644
--- a/src/parsers/unimplemented.c
+++ b/src/parsers/unimplemented.c
@@ -24,3 +24,6 @@ static HParser unimplemented = {
 const HParser* h_unimplemented() {
   return &unimplemented;
 }
+const HParser* h_unimplemented__m(HAllocator* mm__) {
+  return &unimplemented;
+}
diff --git a/src/parsers/whitespace.c b/src/parsers/whitespace.c
index 4d2ec179f15bc368a4d02c79b5c21c695434ffe6..8e009a43df268bc73257a98d6b790dfc3b1ec928 100644
--- a/src/parsers/whitespace.c
+++ b/src/parsers/whitespace.c
@@ -19,7 +19,10 @@ static const HParserVtable whitespace_vt = {
 };
 
 const HParser* h_whitespace(const HParser* p) {
-  HParser *ret = g_new(HParser, 1);
+  return h_whitespace__m(&system_allocator, p);
+}
+const HParser* h_whitespace__m(HAllocator* mm__, const HParser* p) {
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &whitespace_vt;
   ret->env = (void*)p;
   return ret;
diff --git a/src/parsers/xor.c b/src/parsers/xor.c
index 9ffd51ef12fe081bbde8d5d0b4f5d9f68e2ca7a7..a11ad4aeae80d8589569729fd3e429e6eeb0c5a6 100644
--- a/src/parsers/xor.c
+++ b/src/parsers/xor.c
@@ -35,10 +35,13 @@ static const HParserVtable xor_vt = {
   .parse = parse_xor,
 };
 
-const HParser* h_xor(const HParser* p1, const HParser* p2) { 
-  HTwoParsers *env = g_new(HTwoParsers, 1);
+const HParser* h_xor(const HParser* p1, const HParser* p2) {
+  return h_xor__m(&system_allocator, p1, p2);
+}
+const HParser* h_xor__m(HAllocator* mm__, const HParser* p1, const HParser* p2) { 
+  HTwoParsers *env = h_new(HTwoParsers, 1);
   env->p1 = p1; env->p2 = p2;
-  HParser *ret = g_new(HParser, 1);
+  HParser *ret = h_new(HParser, 1);
   ret->vtable = &xor_vt; ret->env = (void*)env;
   return ret;
 }
diff --git a/src/system_allocator.c b/src/system_allocator.c
new file mode 100644
index 0000000000000000000000000000000000000000..26e2273606bda27e7311a32c49973924d4716502
--- /dev/null
+++ b/src/system_allocator.c
@@ -0,0 +1,20 @@
+#include <malloc.h>
+#include "internal.h"
+
+static void* system_alloc(HAllocator *allocator, size_t size) {
+  return malloc(size);
+}
+
+static void* system_realloc(HAllocator *allocator, void* ptr, size_t size) {
+  return realloc(ptr, size);
+}
+
+static void system_free(HAllocator *allocator, void* ptr) {
+  free(ptr);
+}
+
+HAllocator system_allocator = {
+  .alloc = system_alloc,
+  .realloc = system_realloc,
+  .free = system_free,
+};