diff --git a/src/cfgrammar.h b/src/cfgrammar.h
index f336db5c0ca6e52651034095b14289e8ff2a0e26..fdfa7c5c6751070dc95f280b63bfb4dac39b3792 100644
--- a/src/cfgrammar.h
+++ b/src/cfgrammar.h
@@ -19,8 +19,8 @@ typedef struct HCFGrammar_ {
  * therefore we must avoid 0 as a token value because NULL means "not in set".
  */
 typedef uintptr_t HCFToken;
-static inline HCFToken char_token(char c) { return (0x100 | c); }
-static inline char token_char(HCFToken t) { return (0xFF & t); }
+static inline HCFToken char_token(uint8_t c) { return (0x100 | c); }
+static inline uint8_t token_char(HCFToken t) { return (0xFF & t); }
 static const HCFToken end_token = 0x200;
 
 
diff --git a/src/parsers/bits.c b/src/parsers/bits.c
index 091e4e63c5a39d5ae85709ff8819e36e637e8df3..408ea29b7eecf38bc75ff5d041d4725b6dc8c1c4 100644
--- a/src/parsers/bits.c
+++ b/src/parsers/bits.c
@@ -17,6 +17,41 @@ static HParseResult* parse_bits(void* env, HParseState *state) {
   return make_result(state->arena, result);
 }
 
+static HParsedToken *reshape_bits(const HParseResult *p, bool signedp) {
+  // XXX works only for whole bytes
+  // XXX assumes big-endian
+  assert(p->ast);
+  assert(p->ast->token_type == TT_SEQUENCE);
+
+  HCountedArray *seq = p->ast->seq;
+  HParsedToken *ret = h_arena_malloc(p->arena, sizeof(HParsedToken));
+  ret->token_type = TT_UINT;
+
+  if(signedp && (seq->elements[0]->uint & 128))
+    ret->uint = -1; // all ones
+
+  for(size_t i=0; i<seq->used; i++) {
+    HParsedToken *t = seq->elements[i];
+    assert(t->token_type == TT_UINT);
+
+    ret->uint <<= 8;
+    ret->uint |= t->uint & 0xFF;
+  }
+
+  if(signedp) {
+    ret->token_type = TT_SINT;
+    ret->sint = ret->uint;
+  }
+
+  return ret;
+}
+static const HParsedToken *reshape_bits_unsigned(const HParseResult *p) {
+  return reshape_bits(p, false);
+}
+static const HParsedToken *reshape_bits_signed(const HParseResult *p) {
+  return reshape_bits(p, true);
+}
+
 static HCFChoice* desugar_bits(HAllocator *mm__, void *env) {
   struct bits_env *bits = (struct bits_env*)env;
   if (0 != bits->length % 8)
@@ -46,6 +81,11 @@ static HCFChoice* desugar_bits(HAllocator *mm__, void *env) {
   ret->seq[1] = NULL;
   ret->action = NULL;
 
+  if(bits->signedp)
+    ret->reshape = reshape_bits_signed;
+  else
+    ret->reshape = reshape_bits_unsigned;
+
   return ret;
 }
 
diff --git a/src/t_parser.c b/src/t_parser.c
index 13c4bdf7d980ca8c976c421cd87c0984d11beced..6c4b62a990eff2c89be58426f089eab6bb9c0e06 100644
--- a/src/t_parser.c
+++ b/src/t_parser.c
@@ -41,6 +41,13 @@ static void test_int32(void) {
   g_check_parse_failed(int32_, "\xff\xfe\x00", 3);
 }
 
+static void test_int32_pos(void) {
+  const HParser *int32_ = h_int32();
+
+  g_check_parse_ok(int32_, "\x00\x02\x00\x00", 4, "s0x20000");
+  g_check_parse_failed(int32_, "\x00\x02\x00", 3);
+}
+
 static void test_int16(void) {
   const HParser *int16_ = h_int16();
 
@@ -48,6 +55,13 @@ static void test_int16(void) {
   g_check_parse_failed(int16_, "\xfe", 1);
 }
 
+static void test_int16_pos(void) {
+  const HParser *int16_ = h_int16();
+
+  g_check_parse_ok(int16_, "\x02\x00", 2, "s0x200");
+  g_check_parse_failed(int16_, "\x02", 1);
+}
+
 static void test_int8(void) {
   const HParser *int8_ = h_int8();
 
@@ -395,7 +409,9 @@ void register_parser_tests(void) {
   g_test_add_func("/core/parser/ch_range", test_ch_range);
   g_test_add_func("/core/parser/int64", test_int64);
   g_test_add_func("/core/parser/int32", test_int32);
+  g_test_add_func("/core/parser/int32_pos", test_int32_pos);
   g_test_add_func("/core/parser/int16", test_int16);
+  g_test_add_func("/core/parser/int16_pos", test_int16_pos);
   g_test_add_func("/core/parser/int8", test_int8);
   g_test_add_func("/core/parser/uint64", test_uint64);
   g_test_add_func("/core/parser/uint32", test_uint32);