diff --git a/src/backends/llvm/llvm.c b/src/backends/llvm/llvm.c
index 356b279b2754772921ae9e449c6848d3b792a2b4..1f4209c3a9616894bd96d1a7cd33dfa9e6da26ea 100644
--- a/src/backends/llvm/llvm.c
+++ b/src/backends/llvm/llvm.c
@@ -178,7 +178,7 @@ int h_llvm_compile(HAllocator* mm__, HParser* parser, const void* params) {
    * Translate the contents of the children of `parser` into their LLVM
    * instruction equivalents
    */
-  if (parser->vtable->llvm(ctxt, parser->env, &res)) {
+  if (parser->vtable->llvm(ctxt, parser, &res)) {
     /* Okay, we got it - set up a postamble basic block */
     postamble_name_len = snprintf(NULL, 0, "postamble_%p", (void *)parser);
     postamble_name = h_new(char, postamble_name_len + 1);
diff --git a/src/internal.h b/src/internal.h
index 7646e3a6576ae73d9d54b74f02f38f5253a2ed7f..23e0b7cd0b3a8bdab8799294d9b0b7ba5bd5ef67 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -505,7 +505,7 @@ struct HParserVtable_ {
   bool (*compile_to_rvm)(HRVMProg *prog, void* env); // FIXME: forgot what the bool return value was supposed to mean.
   void (*desugar)(HAllocator *mm__, HCFStack *stk__, void *env);
 #ifdef HAMMER_LLVM_BACKEND
-  bool (*llvm)(HLLVMParserCompileContext *ctxt, void *env, LLVMValueRef *result);
+  bool (*llvm)(HLLVMParserCompileContext *ctxt, HParser *p, LLVMValueRef *result);
 #endif
   bool higher; // false if primitive
 };
diff --git a/src/parsers/bits.c b/src/parsers/bits.c
index f59849fde9d0d4d66e5ebb678fe061a4161f4633..91669726d4129c3e803dbc2f3cd577c5cd227bb7 100644
--- a/src/parsers/bits.c
+++ b/src/parsers/bits.c
@@ -26,22 +26,25 @@ static HParseResult* parse_bits(void* env, HParseState *state) {
 
 #ifdef HAMMER_LLVM_BACKEND
 
-static bool bits_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *res) {
+static bool bits_llvm(HLLVMParserCompileContext *ctxt,
+                      HParser *p,
+                      LLVMValueRef *res) {
   /* Emit LLVM IR to parse ((struct bits_env *)env)->length bits */
 
   if (!res) return false;
+  if (!p) return false;
   /* This will get set to non-NULL only when we return true */
   *res = NULL;
   if (!ctxt) return false;
 
-  struct bits_env *env_ = env;
+  struct bits_env *env = (struct bits_env *)(p->env);
   /* Error out on unsupported length */
-  if (env_->length > 64 || env_->length == 0) return false;
+  if (env->length > 64 || env->length == 0) return false;
   /* Set up params for call to h_read_bits */
   LLVMValueRef bits_args[3];
   bits_args[0] = ctxt->stream;
-  bits_args[1] = LLVMConstInt(LLVMInt32Type(), env_->length, 0);
-  bits_args[2] = LLVMConstInt(LLVMInt8Type(), env_->signedp ? 1 : 0, 0);
+  bits_args[1] = LLVMConstInt(LLVMInt32Type(), env->length, 0);
+  bits_args[2] = LLVMConstInt(LLVMInt8Type(), env->signedp ? 1 : 0, 0);
 
   /* Set up basic blocks: entry, success and failure branches, then exit */
   LLVMBasicBlockRef bits_bb = LLVMAppendBasicBlock(ctxt->func, "bits");
@@ -57,7 +60,7 @@ static bool bits_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *
 
   /* Make an HParseResult out of it */
   LLVMValueRef mr;
-  h_llvm_make_tt_suint(ctxt, env_->length, env_->signedp, bits, &mr);
+  h_llvm_make_tt_suint(ctxt, env->length, env->signedp, bits, &mr);
 
   /* Return mr */
   *res = mr;
diff --git a/src/parsers/ch.c b/src/parsers/ch.c
index 2db312d6fc45a299261a36be2b2782467382fa11..9a3dbfe9a67be6b529cacbed117e2c28a1a6f568 100644
--- a/src/parsers/ch.c
+++ b/src/parsers/ch.c
@@ -50,52 +50,76 @@ static bool ch_ctrvm(HRVMProg *prog, void* env) {
 
 #ifdef HAMMER_LLVM_BACKEND
 
-static bool ch_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *res) {
+static bool ch_llvm(HLLVMParserCompileContext *ctxt,
+                    HParser *p,
+                    LLVMValueRef *res) {
   /* Build a new LLVM function to parse a character */
 
+  /* Basic blocks we will be using */
+  LLVMBasicBlockRef entry, success, end;
+  /* Args for call to h_read_bits() */
+  LLVMValueRef bits_args[3];
+  /* Result of call to h_read_bits() */
+  LLVMValueRef bits;
+  /* Truncated result of call to h_read_bits() */
+  LLVMValueRef r;
+  /* Character to check for */
+  uint8_t cval;
+  /* Character to check for as an LLVM value */
+  LLVMValueRef c;
+  /* Result of LLVM comparison */
+  LLVMValueRef icmp;
+  /* Completed token */
+  LLVMValueRef mr;
+  /* Return value (a phi) */
+  LLVMValueRef rv;
+  /* Inputs to the phi */
+  LLVMBasicBlockRef rv_phi_incoming_blocks[2];
+  LLVMValueRef rv_phi_incoming_values[2];
+
   if (!res) return false;
+  if (!p) return false;
   if (!ctxt) return false;
 
-  /* Set up params for calls to h_read_bits() and h_arena_malloc() */
-  LLVMValueRef bits_args[3];
-  bits_args[0] = ctxt->stream;
-  bits_args[1] = LLVMConstInt(LLVMInt32Type(), 8, 0);
-  bits_args[2] = LLVMConstInt(LLVMInt8Type(), 0, 0);
-
   /*
    * Set up basic blocks: entry, success and failure branches, then exit
    *
    * TODO should these basic block names reflect the particular HParser to
    * make the IR dump more comprehensible?
    */
-  LLVMBasicBlockRef entry = LLVMAppendBasicBlock(ctxt->func, "ch_entry");
-  LLVMBasicBlockRef success = LLVMAppendBasicBlock(ctxt->func, "ch_success");
-  LLVMBasicBlockRef end = LLVMAppendBasicBlock(ctxt->func, "ch_end");
+  entry = LLVMAppendBasicBlock(ctxt->func, "ch_entry");
+  success = LLVMAppendBasicBlock(ctxt->func, "ch_success");
+  end = LLVMAppendBasicBlock(ctxt->func, "ch_end");
 
   /* Basic block: entry */
   LLVMBuildBr(ctxt->builder, entry);
   LLVMPositionBuilderAtEnd(ctxt->builder, entry);
 
+  /* Set up params for calls to h_read_bits() */
+  bits_args[0] = ctxt->stream;
+  bits_args[1] = LLVMConstInt(LLVMInt32Type(), 8, 0);
+  bits_args[2] = LLVMConstInt(LLVMInt8Type(), 0, 0);
+
   /*
    * Call to h_read_bits()
    *
    * %read_bits = call i64 @h_read_bits(%struct.HInputStream_* %8,
    *                                    i32 8, i8 signext 0)
    */
-  LLVMValueRef bits = LLVMBuildCall(ctxt->builder,
-      LLVMGetNamedFunction(ctxt->mod, "h_read_bits"), bits_args, 3, "read_bits");
+  bits = LLVMBuildCall(ctxt->builder,
+                       LLVMGetNamedFunction(ctxt->mod, "h_read_bits"),
+                       bits_args, 3, "read_bits");
   /* %2 = trunc i64 %read_bits to i8 */
-  LLVMValueRef r = LLVMBuildTrunc(ctxt->builder,
-      bits, LLVMInt8Type(), "");
+  r = LLVMBuildTrunc(ctxt->builder, bits, LLVMInt8Type(), "");
 
   /*
    * Check if h_read_bits succeeded
    *
    * %"c == r" = icmp eq i8 -94, %2 ; the -94 comes from c_
    */
-  uint8_t c_ = (uint8_t)(uintptr_t)(env);
-  LLVMValueRef c = LLVMConstInt(LLVMInt8Type(), c_, 0);
-  LLVMValueRef icmp = LLVMBuildICmp(ctxt->builder, LLVMIntEQ, c, r, "c == r");
+  cval = (uint8_t)(uintptr_t)(p->env);
+  c = LLVMConstInt(LLVMInt8Type(), cval, 0);
+  icmp = LLVMBuildICmp(ctxt->builder, LLVMIntEQ, c, r, "c == r");
 
   /*
    * Branch so success or failure basic block, as appropriate
@@ -107,7 +131,6 @@ static bool ch_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *re
   LLVMPositionBuilderAtEnd(ctxt->builder, success);
 
   /* Make a token */
-  LLVMValueRef mr;
   h_llvm_make_tt_suint(ctxt, 8, 0, r, &mr);
 
   /* br label %ch_end */
@@ -119,15 +142,11 @@ static bool ch_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *re
    * %rv = phi %struct.HParseResult_.3* [ %make_result, %ch_success ],
    *       [ null, %ch_entry ]
    */
-  LLVMValueRef rv = LLVMBuildPhi(ctxt->builder, ctxt->llvm_parseresultptr, "rv");
-  LLVMBasicBlockRef rv_phi_incoming_blocks[] = {
-    success,
-    entry
-    };
-  LLVMValueRef rv_phi_incoming_values[] = {
-    mr,
-    LLVMConstNull(ctxt->llvm_parseresultptr)
-    };
+  rv = LLVMBuildPhi(ctxt->builder, ctxt->llvm_parseresultptr, "rv");
+  rv_phi_incoming_blocks[0] = success;
+  rv_phi_incoming_values[0] = mr;
+  rv_phi_incoming_blocks[1] = entry;
+  rv_phi_incoming_values[1] = LLVMConstNull(ctxt->llvm_parseresultptr);
   LLVMAddIncoming(rv, rv_phi_incoming_values, rv_phi_incoming_blocks, 2);
   /* Pass rv out to caller */
   *res = rv;
diff --git a/src/parsers/charset.c b/src/parsers/charset.c
index f77d9e78e9e6736950ea81cd295793ba27f6ad24..49dd5601d92549711db6197594c6327bc6476ed2 100644
--- a/src/parsers/charset.c
+++ b/src/parsers/charset.c
@@ -79,7 +79,9 @@ static bool cs_ctrvm(HRVMProg *prog, void *env) {
 
 #ifdef HAMMER_LLVM_BACKEND
 
-static bool cs_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *res) {
+static bool cs_llvm(HLLVMParserCompileContext *ctxt,
+                    HParser *p,
+                    LLVMValueRef *res) {
   /*
    * LLVM to build a function to parse a charset; the args are a stream and an
    * arena.
@@ -104,6 +106,7 @@ static bool cs_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *re
   LLVMBasicBlockRef rv_phi_incoming_blocks[2];
 
   if (!res) return false;
+  if (!p) return false;
   if (!ctxt) return false;
 
   /* Set up our basic blocks */
@@ -126,7 +129,7 @@ static bool cs_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *re
   r = LLVMBuildTrunc(ctxt->builder, bits, LLVMInt8Type(), "");
 
   /* We have a char, need to check if it's in the charset */
-  cs = (HCharset)env;
+  cs = (HCharset)(p->env);
   /* Branch to either success or end, conditional on whether r is in cs */
   ok = h_llvm_make_charset_membership_test(ctxt, r, cs, success, fail);
 
diff --git a/src/parsers/end.c b/src/parsers/end.c
index 11dcd33fd152188113bbb2eae10a12ff65cbfb10..6355334c3df9a3baed50c7b7c693ab14b447dc53 100644
--- a/src/parsers/end.c
+++ b/src/parsers/end.c
@@ -28,7 +28,9 @@ static bool end_ctrvm(HRVMProg *prog, void *env) {
 
 #ifdef HAMMER_LLVM_BACKEND
 
-static bool end_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *res) {
+static bool end_llvm(HLLVMParserCompileContext *ctxt, 
+                     HParser *p,
+                     LLVMValueRef *res) {
   /* Basic blocks for parsing end */
   LLVMBasicBlockRef entry, success, end;
   /* Indices for GEP */
@@ -45,6 +47,7 @@ static bool end_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *r
   LLVMValueRef rv_phi_incoming_values[2];
 
   if (!res) return false;
+  if (!p) return false;
   if (!ctxt) return false;
 
   /* Set up some basic blocks */
diff --git a/src/parsers/epsilon.c b/src/parsers/epsilon.c
index 2fd163a98a70772e87a0ebf98b83ca8542bf479f..b9021d6c46848def867edd8dd23c9055239c8352 100644
--- a/src/parsers/epsilon.c
+++ b/src/parsers/epsilon.c
@@ -21,7 +21,9 @@ static bool epsilon_ctrvm(HRVMProg *prog, void* env) {
 
 #ifdef HAMMER_LLVM_BACKEND
 
-static bool epsilon_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *res) {
+static bool epsilon_llvm(HLLVMParserCompileContext *ctxt,
+                         HParser *p,
+                         LLVMValueRef *res) {
   /* Epsilon basic block */
   LLVMBasicBlockRef epsilon_bb;
   /* Args for make_result() */
@@ -30,6 +32,7 @@ static bool epsilon_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRe
   LLVMValueRef result_ptr;
 
   if (!res) return false;
+  if (!p) return false;
   if (!ctxt) return false;
 
   epsilon_bb = LLVMAppendBasicBlock(ctxt->func, "epsilon");
diff --git a/src/parsers/nothing.c b/src/parsers/nothing.c
index df9e3f79786fb9275e6dadd479db8a0e3cb611c6..f5e427b1cfd8bf3cba9f63d0e247b276609c869b 100644
--- a/src/parsers/nothing.c
+++ b/src/parsers/nothing.c
@@ -27,13 +27,16 @@ static bool nothing_ctrvm(HRVMProg *prog, void* env) {
 
 #ifdef HAMMER_LLVM_BACKEND
 
-static bool nothing_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *res) {
+static bool nothing_llvm(HLLVMParserCompileContext *ctxt,
+                         HParser *p,
+                         LLVMValueRef *res) {
   /* Nothing entry bb */
   LLVMBasicBlockRef entry;
   /* Nothing result */
   LLVMValueRef rv;
 
   if (!res) return false;
+  if (!p) return false;
   if (!ctxt) return false;
 
   /* This one just always returns NULL */
diff --git a/src/parsers/token.c b/src/parsers/token.c
index 8b031989ff38308a638856a76f105b15ce3c63bf..f63bbbee9da7bc6f60456c38815d7b750391228c 100644
--- a/src/parsers/token.c
+++ b/src/parsers/token.c
@@ -285,14 +285,19 @@ static bool token_llvm_with_sequential_comparisons(
 
 #define TOKEN_LENGTH_USE_GLOBAL_CUTOFF 4
 
-static bool token_llvm(HLLVMParserCompileContext *ctxt, void* env, LLVMValueRef *res) {
+static bool token_llvm(HLLVMParserCompileContext *ctxt,
+                       HParser *p,
+                       LLVMValueRef *res) {
   HToken *t;
 
   if (!res) return false;
+  if (!p) return false;
   if (!ctxt) return false;
 
   /* Get the token */
-  t = (HToken *)env;
+  t = (HToken *)(p->env);
+  if (!t) return false;
+
   /*
    * Check its length; we have two possible code-generation strategies
    * here: treat it like chars sequentially and emit a series of read/