diff --git a/src/parsers/attr_bool.c b/src/parsers/attr_bool.c
index bfc4976a62da7a83f17a7312874f783afc5a6cbd..059bfbc8181fdd6d14a4ceeadafbda4a32d4490b 100644
--- a/src/parsers/attr_bool.c
+++ b/src/parsers/attr_bool.c
@@ -27,10 +27,15 @@ static bool ab_isValidCF(void *env) {
   return ab->p->vtable->isValidCF(ab->p->env);
 }
 
+static HCFChoice* desugar_ab(HAllocator *mm__, void *env) {
+
+}
+
 static const HParserVtable attr_bool_vt = {
   .parse = parse_attr_bool,
   .isValidRegular = ab_isValidRegular,
   .isValidCF = ab_isValidCF,
+  .desugar = desugar_ab,
 };
 
 
diff --git a/src/parsers/butnot.c b/src/parsers/butnot.c
index 4d5bf5783ef04b7af1fb6bfaac01c84920d4b5bb..adb2e97e1598d7aa879425aaf79d790af9cfc02e 100644
--- a/src/parsers/butnot.c
+++ b/src/parsers/butnot.c
@@ -41,10 +41,15 @@ static bool bn_isValidCF(void *env) {
 	  tp->p2->vtable->isValidCF(tp->p2->env));
 }
 
+static HCFChoice* desugar_butnot(HAllocator *mm__, void *env) {
+
+}
+
 static const HParserVtable butnot_vt = {
   .parse = parse_butnot,
   .isValidRegular = h_false,
   .isValidCF = bn_isValidCF,
+  .desugar = desugar_butnot,
 };
 
 const HParser* h_butnot(const HParser* p1, const HParser* p2) {
diff --git a/src/parsers/difference.c b/src/parsers/difference.c
index e3c41ec33a7f2e36b80f681bf0de9e8f71faa2b4..1b0e09f668e1fdf07cdeb39442f3696b3239affa 100644
--- a/src/parsers/difference.c
+++ b/src/parsers/difference.c
@@ -40,10 +40,15 @@ static bool diff_isValidCF(void *env) {
 	  tp->p2->vtable->isValidCF(tp->p2->env));
 }
 
+static HCFChoice* desugar_difference(HAllocator *mm__, void *env) {
+
+}
+
 static HParserVtable difference_vt = {
   .parse = parse_difference,
   .isValidRegular = h_false,
   .isValidCF = diff_isValidCF,
+  .desugar = desugar_difference,
 };
 
 const HParser* h_difference(const HParser* p1, const HParser* p2) {
diff --git a/src/parsers/end.c b/src/parsers/end.c
index 26bd0e93ccd5d48fb3c26afd4ac8dc16130c5481..2a458e526aa25642c1c48aace62daa203879dc29 100644
--- a/src/parsers/end.c
+++ b/src/parsers/end.c
@@ -10,7 +10,7 @@ static HParseResult* parse_end(void *env, HParseState *state) {
   }
 }
 
-static const HCFChoice* desugar_end(HAllocator *mm__, void *env) {
+static HCFChoice* desugar_end(HAllocator *mm__, void *env) {
   static HCFChoice ret = {
     .type = HCF_END
   };
diff --git a/src/parsers/epsilon.c b/src/parsers/epsilon.c
index 8b73b96e851daffeb57ac1c61465e882ceece11b..5063e6033e8f833c7d47d3c90e4b40a05cb999f5 100644
--- a/src/parsers/epsilon.c
+++ b/src/parsers/epsilon.c
@@ -12,7 +12,8 @@ static HCFChoice* desugar_epsilon(HAllocator *mm__, void *env) {
   static HCFSequence res_seq = {NULL};
   static HCFChoice res_ch = {
     .type = HCF_CHOICE,
-    .seq = &res_seq
+    .seq = &res_seq,
+    .action = NULL;
   };
 
   return &res_ch;
diff --git a/src/parsers/ignore.c b/src/parsers/ignore.c
index 6191eff91ffe068049b597ef11662fc4311a924c..a642c84b92456dff3c5feda4eb92e0e096b4a9cb 100644
--- a/src/parsers/ignore.c
+++ b/src/parsers/ignore.c
@@ -20,10 +20,15 @@ static bool ignore_isValidCF(void *env) {
   return (p->vtable->isValidCF(p->env));
 }
 
+static HCFChoice* desugar_ignore(HAllocator *mm__, void *env) {
+
+}
+
 static const HParserVtable ignore_vt = {
   .parse = parse_ignore,
   .isValidRegular = ignore_isValidRegular,
   .isValidCF = ignore_isValidCF,
+  .desugar = desugar_ignore,
 };
 
 const HParser* h_ignore(const HParser* p) {
diff --git a/src/parsers/indirect.c b/src/parsers/indirect.c
index 4415f067e8f5e26ddf29f4490c33af03b90613f1..ed556270d1ab100c6d1ca4250f7a47f4e8d81490 100644
--- a/src/parsers/indirect.c
+++ b/src/parsers/indirect.c
@@ -10,10 +10,15 @@ static bool indirect_isValidCF(void *env) {
   return inner->vtable->isValidCF(inner->env);
 }
 
+static HCFChoice desugar_indirect(HAllocator *mm__, void *env) {
+
+}
+
 static const HParserVtable indirect_vt = {
   .parse = parse_indirect,
   .isValidRegular = h_false,
   .isValidCF = indirect_isValidCF,
+  .desugar = desugar_indirect,
 };
 
 void h_bind_indirect(HParser* indirect, const HParser* inner) {
diff --git a/src/parsers/int_range.c b/src/parsers/int_range.c
index bcd896ad409d3cac118bc578cf4f43ee46f1a94c..f2ee03f4de28c161c0987f616a95de5968899e1c 100644
--- a/src/parsers/int_range.c
+++ b/src/parsers/int_range.c
@@ -40,38 +40,84 @@ HCFChoice* gen_int_range(HAllocator *mm__, uint64_t low, uint64_t high, uint8_t
     return cs;
   }
   else if (1 < bytes) {
-    HCFChoice *root = h_new(HCFChoice, 1);
-    root->type = HCF_CHOICE;
-    root->seq = h_new(HCFSequence*, 4);
-    root->seq[0] = h_new(HCFSequence, 1);
-    root->seq[0]->items = h_new(HCFChoice*, 2);
-    root->seq[0]->items[0] = gen_int_range(mm__, low, high, FIXME);
-    root->seq[0]->items[1] = NULL;
-    root->seq[1] = h_new(HCFSequence, 1);
-    root->seq[1]->items = h_new(HCFChoice*, 2);
-    root->seq[1]->items[0] = h_new(HCFChoice, 1);
-    /* do something with root->seq[1]->items[0] */
-    root->seq[1]->items[1] = NULL;
-    root->seq[2] = h_new(HCFSequence, 1);
-    root->seq[2]->items = h_new(HCFChoice*, 2);
-    root->seq[2]->items[0] = gen_int_range(mm__, low, high, FIXME);
-    root->seq[2]->items[1] = NULL;
-    root->seq[3] = NULL;
-    root->action = NULL;
-    return root;
+    uint8_t low_head, hi_head;
+    low_head = ((low >> (8*(bytes - 1))) & 0xFF);
+    hi_head = ((high >> (8*(bytes - 1))) & 0xFF);
+    if (low_head != hi_head) {
+      HCFChoice *root = h_new(HCFChoice, 1);
+      root->type = HCF_CHOICE;
+      root->seq = h_new(HCFSequence*, 4);
+      root->seq[0] = h_new(HCFSequence, 1);
+      root->seq[0]->items = h_new(HCFChoice*, 3);
+      root->seq[0]->items[0] = h_new(HCFChoice, 1);
+      root->seq[0]->items[0]->type = HCF_CHAR;
+      root->seq[0]->items[0]->chr = low_head;
+      root->seq[0]->items[0]->action = NULL;
+      root->seq[0]->items[1] = gen_int_range(mm__, low & ((1 << (8 * (bytes - 1))) - 1), ((1 << (8*(bytes-1)))-1), bytes-1);
+      root->seq[0]->items[2] = NULL;
+      root->seq[1] = h_new(HCFSequence, 1);
+      root->seq[1]->items = h_new(HCFChoice*, bytes+1);
+      root->seq[1]->items[0] = h_new(HCFChoice, 2);
+      root->seq[1]->items[0]->type = HCF_CHARSET;
+      root->seq[1]->items[0]->charset = new_charset(mm__);
+      root->seq[1]->items[0]->action = NULL;
+      root->seq[1]->items[1] = root->seq[1]->items[0] + 1;
+      root->seq[1]->items[1]->type = HCF_CHARSET;
+      root->seq[1]->items[1]->charset = new_charset(mm__);
+      for (int i = 0; i < 256; i++) {
+	charset_set(root->seq[1]->items[0]->charset, i, (i > low_head && i < hi_head));
+	charset_set(root->seq[1]->items[1]->charset, i, 1);
+      }
+      root->seq[1]->items[1]->action = NULL;
+      for (int i = 2; i < bytes; i++)
+	root->seq[1]->items[i] = root->seq[1]->items[1];
+      root->seq[1]->items[bytes] = NULL;
+      root->seq[2] = h_new(HCFSequence, 1);
+      root->seq[2]->items = h_new(HCFChoice*, 3);
+      root->seq[2]->items[0] = h_new(HCFChoice, 1);
+      root->seq[2]->items[0]->type = HCF_CHAR;
+      root->seq[2]->items[0]->type = hi_head;
+      root->seq[2]->items[0]->action = NULL;
+      root->seq[2]->items[1] = gen_int_range(mm__, 0, high & ((1 << (8 * (bytes - 1))) - 1), bytes-1);
+      root->seq[2]->items[2] = NULL;
+      root->seq[3] = NULL;
+      root->action = NULL;
+      return root;
+    } else {
+      HCFChoice *root = h_new(HCFChoice, 1);
+      root->type = HCF_CHOICE;
+      root->seq = h_new(HCFSequence*, 2);
+      root->seq[0] = h_new(HCFSequence, 1);
+      root->seq[0]->items = h_new(HCFChoice*, 3);
+      root->seq[0]->items[0] = h_new(HCFChoice, 1);
+      root->seq[0]->items[0]->type = HCF_CHAR;
+      root->seq[0]->items[0]->chr = low_head;
+      root->seq[0]->items[0]->action = NULL;
+      root->seq[0]->items[1] = gen_int_range(mm__,
+					     low & ((1 << (8 * (bytes - 1))) - 1),
+					     high & ((1 << (8 * (bytes - 1))) - 1),
+					     bytes - 1);
+      root->seq[0]->items[2] = NULL;
+      root->seq[1] = NULL;
+      root->action = NULL;
+      return root;
+    }
   }
   else { // idk why this would ever be <1, but whatever
     return NULL; 
   }
 }
 
+struct bits_env {
+  uint8_t length;
+  uint8_t signedp;
+};
+
 static HCFChoice* desugar_int_range(HAllocator *mm__, void *env) {
   HRange *r = (HRange*)env;
-  HCFChoice *ret = h_new(HCFChoice, 1);
-  ret->type = HCF_CHOICE;
-  uint8_t bytes = r->p->env->length / 8;
-  HCFSequence *seq = h_new(HCFSequence, 1);
-  
+  struct bits_env* be = (struct bits_env*)r->p->env;
+  uint8_t bytes = be->length / 8;
+  return gen_int_range(mm__, r->lower, r->upper, bytes);
 }
 
 static const HParserVtable int_range_vt = {
diff --git a/src/parsers/many.c b/src/parsers/many.c
index 2c2577efc2811e97e5373a2169dc4a48fb281118..193fadcb76e271a03e687f7c1bec430798a4c319 100644
--- a/src/parsers/many.c
+++ b/src/parsers/many.c
@@ -56,10 +56,15 @@ static bool many_isValidCF(void *env) {
 	  repeat->sep->vtable->isValidCF(repeat->sep->env));
 }
 
+static HCFChoice* desugar_many(HAllocator *mm__, void *env) {
+
+}
+
 static const HParserVtable many_vt = {
   .parse = parse_many,
   .isValidRegular = many_isValidRegular,
   .isValidCF = many_isValidCF,
+  .desugar = desugar_many,
 };
 
 const HParser* h_many(const HParser* p) {
diff --git a/src/parsers/not.c b/src/parsers/not.c
index 6642d9e838d3e1f78a2737144b273e061f825b43..d6f25d529c21c7efd131a5dcf2ca76e6196986ac 100644
--- a/src/parsers/not.c
+++ b/src/parsers/not.c
@@ -10,10 +10,16 @@ static HParseResult* parse_not(void* env, HParseState* state) {
   }
 }
 
+static const HCFChoice* desugar_not(HAllocator *mm__, void *env) {
+  assert_message(0, "Not context-free, can't be desugared");
+  return NULL;
+}
+
 static const HParserVtable not_vt = {
   .parse = parse_not,
   .isValidRegular = h_false,  /* see and.c for why */
   .isValidCF = h_false,       /* also see and.c for why */
+  .desugar = desugar_not,
 };
 
 const HParser* h_not(const HParser* p) {
diff --git a/src/parsers/nothing.c b/src/parsers/nothing.c
index 01c029ebfc872828fd7fe17f3de1ab23c294ad85..ebf0daf48e1ac7dafbac741046bcaf69e4a56072 100644
--- a/src/parsers/nothing.c
+++ b/src/parsers/nothing.c
@@ -6,10 +6,20 @@ static HParseResult* parse_nothing() {
   return NULL;
 }
 
+static HCFChoice *desugar_nothing(HAllocator *mm__, void *env) {
+  HCFChoice *ret = h_new(HCFChoice, 1);
+  ret->type = HCF_CHOICE;
+  ret->seq = h_new(HCFSequence*, 1);
+  ret->seq[0] = NULL;
+  ret->action = NULL;
+  return ret;
+}
+
 static const HParserVtable nothing_vt = {
   .parse = parse_nothing,
   .isValidRegular = h_true,
   .isValidCF = h_true,
+  .desugar = desugar_nothing,
 };
 
 const HParser* h_nothing_p() {
diff --git a/src/parsers/optional.c b/src/parsers/optional.c
index 0b405e5a2dda1515254a2a61127acef9d55f1def..f59ca55f096cbdc07f6086115528b7e7251b387e 100644
--- a/src/parsers/optional.c
+++ b/src/parsers/optional.c
@@ -21,10 +21,15 @@ static bool opt_isValidCF(void *env) {
   return p->vtable->isValidCF(p->env);
 }
 
+static HCFChoice* desugar_optional(HAllocator *mm__, void *env) {
+
+}
+
 static const HParserVtable optional_vt = {
   .parse = parse_optional,
   .isValidRegular = opt_isValidRegular,
   .isValidCF = opt_isValidCF,
+  .desugar = desugar_optional,
 };
 
 const HParser* h_optional(const HParser* p) {
diff --git a/src/parsers/sequence.c b/src/parsers/sequence.c
index f5e19246fdf0653e84281ccf55e3fcc3577a4f48..b15b168d04aa0dc8ba2aee296913f2340aeb9d6d 100644
--- a/src/parsers/sequence.c
+++ b/src/parsers/sequence.c
@@ -42,10 +42,28 @@ static bool sequence_isValidCF(void *env) {
   return true;
 }
 
+static HCFChoice* desugar_sequence(HAllocator *mm__, void *env) {
+  HSequence *s = (HSequence*)env;
+  HCFSequence *seq = h_new(HCFSequence, 1);
+  seq->items = h_new(HCFChoice*, s->len+1);
+  for (size_t i=0; i<s->len; ++i) {
+    seq->items[i] = s->p_array[i]->vtable->desugar(mm__, s->p_array[i]->env);
+  }
+  seq->items[s->len] = NULL;
+  HCFChoice *ret = h_new(HCFChoice, 1);
+  ret->type = HCF_CHOICE;
+  ret->seq = h_new(HCFSequence*, 2);
+  ret->seq[0] = seq;
+  ret->seq[1] = NULL;
+  ret->action = NULL;
+  return ret;
+}
+
 static const HParserVtable sequence_vt = {
   .parse = parse_sequence,
   .isValidRegular = sequence_isValidRegular,
   .isValidCF = sequence_isValidCF,
+  .desugar = desugar_sequence,
 };
 
 const HParser* h_sequence(const HParser* p, ...) {
diff --git a/src/parsers/xor.c b/src/parsers/xor.c
index 7679a645055660960c6d4f674fd30b69e81990f9..ed67371144f29dcafe1503659a41a9106a91ad93 100644
--- a/src/parsers/xor.c
+++ b/src/parsers/xor.c
@@ -37,10 +37,15 @@ static bool xor_isValidCF(void *env) {
 	  tp->p2->vtable->isValidCF(tp->p2->env));
 }
 
+static HCFChoice* desugar_xor(HAllocator *mm__, void *env) {
+
+}
+
 static const HParserVtable xor_vt = {
   .parse = parse_xor,
   .isValidRegular = h_false,
   .isValidCF = xor_isValidCF,
+  .desugar = desugar_xor,
 };
 
 const HParser* h_xor(const HParser* p1, const HParser* p2) {