diff --git a/src/hammer.hxx b/src/hammer.hxx
index 8f3200c8aaee5d394e759d73fc0d5f9d30ebae43..c0c39c5a7f4a9a1d45c5b2b091e0ccb7966a82b2 100644
--- a/src/hammer.hxx
+++ b/src/hammer.hxx
@@ -72,6 +72,8 @@ namespace hammer {
   class Many1;
   template<class T> class Optional;
   class RepeatN;
+  class Ignore;
+  class Indirect;
   template<class T> class IntRange;
 
   template<typename T>
@@ -83,8 +85,12 @@ namespace hammer {
     Many<T> many();
     RepeatN many(size_t n);
     Optional<T> optional();
+    Ignore ignore();
     RepeatN operator[](size_t n);
     HParser* parser() { return _parser; }
+    int compile(HParserBackend backend, const void* params) {
+	return h_compile(_parser, backend, params);
+    }
   protected:
     HParser* _parser;
     Parser() { }
@@ -478,10 +484,17 @@ namespace hammer {
   class Indirect : public Parser<T> {
   public:
     typedef typename T::result_type result_type;
+    /*
     Indirect(Parser<T> &p) : _p(p) {
       this->_parser = h_indirect();
       h_bind_indirect(this->_parser, p.parser());
     }
+    */
+    Indirect() : _p(0) {}
+    bind(Parser<T> &p) {
+      this->_parser = h_indirect();
+      h_bind_indirect(this->_parser, p.parser());
+    }
   private:
     Parser<T> _p;
   };
diff --git a/src/pprint.c b/src/pprint.c
index d8b22e2d2fa1d317db15334b70021696c054dd9d..969476cf6bd295c4c613da57be1465bb3b7299d2 100644
--- a/src/pprint.c
+++ b/src/pprint.c
@@ -22,6 +22,14 @@
 #include "internal.h"
 #include <stdlib.h>
 
+#ifdef __cplusplus
+#include "hammer.hxx"
+#include <string>
+#include <sstream>
+
+using std::string; using std::stringstream;
+#endif
+
 typedef struct pp_state {
   int delta;
   int indent_amt;
@@ -172,7 +180,13 @@ char* h_write_result_unamb__m(HAllocator* mm__, const HParsedToken* tok) {
   unamb_sub(tok, &buf);
   append_buf_c(&buf, 0);
   return buf.output;
-}
-  
-
 
+#ifdef __cplusplus
+template<typename T>
+string& h_write_result_unamb(ParseResult<T> tok) {
+  stringstream s;
+  s << boost::get<T>(tok.result()[0]);
+  return s.str();
+}
+#endif
+}
diff --git a/src/t_cplusplus.cxx b/src/t_cplusplus.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..88e0c2993bdcfcd873baaf51c0e1e56b24636c32
--- /dev/null
+++ b/src/t_cplusplus.cxx
@@ -0,0 +1,565 @@
+#include "hammer.hxx"
+#include "test_suite.h"
+#include <glib.h>
+#include <iostream>
+#include <string>
+//#include <vector>
+//#include <boost/variant.hpp>
+
+static void test_token_cxx(gconstpointer backend) {
+    hammer::Token token_ = hammer::Token("95\xa2");
+
+    g_check_parse_ok_cxx(token_, (HParserBackend)GPOINTER_TO_INT(backend), "95\xa2", 3, "<39.35.a2>"); // FIXME this will fail because pretty-printing
+    g_check_parse_failed_cxx(token_, (HParserBackend)GPOINTER_TO_INT(backend), "95", 2);
+}
+
+static void test_ch_cxx(gconstpointer backend) {
+    hammer::Ch ch_ = hammer::Ch(0xa2);
+
+    g_check_parse_ok_cxx(ch_, (HParserBackend)GPOINTER_TO_INT(backend), "\xa2", "u0xa2"); // FIXME this will fail, c++ pretty-printing doesn't do this yet
+    g_check_parse_failed_cxx(ch_, (HParserBackend)GPOINTER_TO_INT(backend), "\xa3");
+}
+
+static void test_ch_range_cxx(gconstpointer backend) {
+    hammer::ChRange range_ = hammer::ChRange('a', 'c');
+
+    g_check_parse_ok_cxx(range_, (HParserBackend)GPOINTER_TO_INT(backend), "b", "b");
+    g_check_parse_failed_cxx(range_, (HParserBackend)GPOINTER_TO_INT(backend), "d");
+}
+
+static void test_int64_cxx(gconstpointer backend) {
+    hammer::Int64 int64_ = hammer::Int64();
+
+    g_check_parse_ok_cxx(int64_, (HParserBackend)GPOINTER_TO_INT(backend), "\xff\xff\xff\xfe\x00\x00\x00\x00", "s-0x200000000"); // FIXME this will fail because pretty-printing
+    g_check_parse_failed_cxx(int64_, (HParserBackend)GPOINTER_TO_INT(backend), "\xff\xff\xff\xfe\x00\x00\x00");
+}
+
+static void test_int32_cxx(gconstpointer backend) {
+    hammer::Int32 int32_ = hammer::Int32();
+
+    g_check_parse_ok_cxx(int32_, (HParserBackend)GPOINTER_TO_INT(backend), "\xff\xfe\x00\x00", "s-0x20000"); // FIXME this will fail because pretty-printing
+    g_check_parse_failed_cxx(int32_, (HParserBackend)GPOINTER_TO_INT(backend), "\xff\xfe\x00");
+
+    g_check_parse_ok_cxx(int32_, (HParserBackend)GPOINTER_TO_INT(backend), "\x00\x02\x00\x00", "s0x20000"); // FIXME this will fail because pretty-printing
+    g_check_parse_failed_cxx(int32_, (HParserBackend)GPOINTER_TO_INT(backend), "\x00\x02\x00");
+}
+
+static void test_int16_cxx(gconstpointer backend) {
+    hammer::Int16 int16_ = hammer::Int16();
+
+    g_check_parse_ok_cxx(int16_, (HParserBackend)GPOINTER_TO_INT(backend), "\xfe\x00", "s-0x200"); // FIXME this will fail because pretty-printing
+    g_check_parse_failed_cxx(int16_, (HParserBackend)GPOINTER_TO_INT(backend), "\xfe");
+
+    g_check_parse_ok_cxx(int16_, (HParserBackend)GPOINTER_TO_INT(backend), "\x02\x00", "s0x200"); // FIXME this will fail because pretty-printing
+    g_check_parse_failed_cxx(int16_, (HParserBackend)GPOINTER_TO_INT(backend), "\x02");
+}
+
+static void test_int8_cxx(gconstpointer backend) {
+    hammer::Int8 int8_ = hammer::Int8();
+
+    g_check_parse_ok_cxx(int8_, (HParserBackend)GPOINTER_TO_INT(backend), "\x88", "s-0x78"); // FIXME this will fail because pretty-printing
+    g_check_parse_failed_cxx(int8_, (HParserBackend)GPOINTER_TO_INT(backend), "");
+}
+
+static void test_uint64_cxx(gconstpointer backend) {
+    hammer::Uint64 uint64_ = hammer::Uint64();
+
+    g_check_parse_ok_cxx(uint64_, (HParserBackend)GPOINTER_TO_INT(backend), "\x00\x00\x00\x02\x00\x00\x00\x00", "u0x200000000"); // FIXME this will fail because pretty-printing
+    g_check_parse_failed_cxx(uint64_, (HParserBackend)GPOINTER_TO_INT(backend), "\x00\x00\x00\x02\x00\x00\x00");
+}
+
+static void test_uint32_cxx(gconstpointer backend) {
+    hammer::Uint32 uint32_ = hammer::Uint32();
+
+    g_check_parse_ok_cxx(uint32_, (HParserBackend)GPOINTER_TO_INT(backend), "\x00\x02\x00\x00", "u0x20000"); // FIXME this will fail because pretty-printing
+    g_check_parse_failed_cxx(uint32_, (HParserBackend)GPOINTER_TO_INT(backend), "\x00\x02\x00", 3);
+}
+
+static void test_uint16_cxx(gconstpointer backend) {
+    hammer::Uint16 uint16_ = hammer::Uint16();
+
+    g_check_parse_ok_cxx(uint16_, (HParserBackend)GPOINTER_TO_INT(backend), "\x02\x00", "u0x200"); // FIXME this will fail because pretty-printing
+    g_check_parse_failed_cxx(uint16_, (HParserBackend)GPOINTER_TO_INT(backend), "\x02");
+}
+
+static void test_uint8_cxx(gconstpointer backend) {
+    hammer::Uint8 uint8_ = hammer::Uint8();
+
+    g_check_parse_ok_cxx(uint8_, (HParserBackend)GPOINTER_TO_INT(backend), "\x78", "u0x78"); // FIXME this will fail because pretty-printing
+    g_check_parse_failed_cxx(uint8_, (HParserBackend)GPOINTER_TO_INT(backend), "");
+}
+
+static void test_int_range_cxx(gconstpointer backend) {
+    hammer::IntRange<UintResult> int_range_ = hammer::Uint8().in_range(3, 10);
+  
+    g_check_parse_ok_cxx(int_range_, (HParserBackend)GPOINTER_TO_INT(backend), "\x05", "u0x5"); // FIXME this will fail because pretty-printing
+    g_check_parse_failed_cxx(int_range_, (HParserBackend)GPOINTER_TO_INT(backend), "\xb");
+}
+
+static void test_whitespace_cxx(gconstpointer backend) {
+    hammer::Whitespace whitespace_ = hammer::Whitespace(hammer::Ch('a'));
+    hammer::Whitespace whitespace_end = hammer::Whitespace(hammer::End());
+    
+    g_check_parse_ok_cxx(whitespace_, (HParserBackend)GPOINTER_TO_INT(backend), "a", "u0x61");
+    g_check_parse_ok_cxx(whitespace_, (HParserBackend)GPOINTER_TO_INT(backend), " a", "u0x61");
+    g_check_parse_ok_cxx(whitespace_, (HParserBackend)GPOINTER_TO_INT(backend), "  a", "u0x61");
+    g_check_parse_ok_cxx(whitespace_, (HParserBackend)GPOINTER_TO_INT(backend), "\ta", "u0x61");
+    g_check_parse_failed_cxx(whitespace_, (HParserBackend)GPOINTER_TO_INT(backend), "_a");
+
+    g_check_parse_ok_cxx(whitespace_end, (HParserBackend)GPOINTER_TO_INT(backend), "", "NULL");
+    g_check_parse_ok_cxx(whitespace_end, (HParserBackend)GPOINTER_TO_INT(backend),"  ", "NULL");
+    g_check_parse_failed_cxx(whitespace_end, (HParserBackend)GPOINTER_TO_INT(backend),"  x");
+}
+
+static void test_left_cxx(gconstpointer backend) {
+    hammer::Left left_ = hammer::Left(hammer::Ch('a'), hammer::Ch(' '));
+
+    g_check_parse_ok_cxx(left_, (HParserBackend)GPOINTER_TO_INT(backend), "a ", "u0x61");
+    g_check_parse_failed_cxx(left_, (HParserBackend)GPOINTER_TO_INT(backend), "a");
+    g_check_parse_failed_cxx(left_, (HParserBackend)GPOINTER_TO_INT(backend), " ");
+    g_check_parse_failed_cxx(left_, (HParserBackend)GPOINTER_TO_INT(backend), "ab");
+}
+
+static void test_right_cxx(gconstpointer backend) {
+    hammer::Right right_ = hammer::Right(hammer::Ch(' '), hammer::Ch('a'));
+
+    g_check_parse_ok_cxx(right_, (HParserBackend)GPOINTER_TO_INT(backend), " a", "u0x61");
+    g_check_parse_failed_cxx(right_, (HParserBackend)GPOINTER_TO_INT(backend), "a");
+    g_check_parse_failed_cxx(right_, (HParserBackend)GPOINTER_TO_INT(backend), " ");
+    g_check_parse_failed_cxx(right_, (HParserBackend)GPOINTER_TO_INT(backend), "ba");
+}
+
+static void test_middle_cxx(gconstpointer backend) {
+    hammer::Middle middle_ = hammer::Middle(hammer::Ch(' '), hammer::Ch('a'), hammer::Ch(' '));
+
+    g_check_parse_ok_cxx(middle_, (HParserBackend)GPOINTER_TO_INT(backend), " a ", "u0x61");
+    g_check_parse_failed_cxx(middle_, (HParserBackend)GPOINTER_TO_INT(backend), "a");
+    g_check_parse_failed_cxx(middle_, (HParserBackend)GPOINTER_TO_INT(backend), " ");
+    g_check_parse_failed_cxx(middle_, (HParserBackend)GPOINTER_TO_INT(backend), " a");
+    g_check_parse_failed_cxx(middle_, (HParserBackend)GPOINTER_TO_INT(backend), "a ");
+    g_check_parse_failed_cxx(middle_, (HParserBackend)GPOINTER_TO_INT(backend), " b ");
+    g_check_parse_failed_cxx(middle_, (HParserBackend)GPOINTER_TO_INT(backend), "ba ");
+    g_check_parse_failed_cxx(middle_, (HParserBackend)GPOINTER_TO_INT(backend), " ab");
+}
+
+static void test_in_cxx(gconstpointer backend) {
+    std::string options = "abc";
+    hammer::In in_ = hammer::In(options);
+    g_check_parse_ok_cxx(in_, (HParserBackend)GPOINTER_TO_INT(backend), "b", "u0x62");
+    g_check_parse_failed_cxx(in_, (HParserBackend)GPOINTER_TO_INT(backend), "d");
+
+}
+
+static void test_not_in_cxx(gconstpointer backend) {
+    std::string options = "abc";
+    hammer::NotIn not_in_ = hammer::NotIn(options);
+    g_check_parse_ok_cxx(not_in_, (HParserBackend)GPOINTER_TO_INT(backend), "d", "u0x64");
+    g_check_parse_failed_cxx(not_in_, (HParserBackend)GPOINTER_TO_INT(backend), "a");
+
+}
+
+static void test_end_cxx(gconstpointer backend) {
+    hammer::End end_ = hammer::Sequence(hammer::Ch('a'), hammer::End());
+    g_check_parse_ok_cxx(end_, (HParserBackend)GPOINTER_TO_INT(backend), "a", "(u0x61)");
+    g_check_parse_failed_cxx(end_, (HParserBackend)GPOINTER_TO_INT(backend), "aa");
+}
+
+static void test_nothing_cxx(gconstpointer backend) {
+    hammer::Nothing nothing_ = hammer::Nothing();
+    g_check_parse_failed_cxx(nothing_, (HParserBackend)GPOINTER_TO_INT(backend),"a");
+}
+
+static void test_sequence_cxx(gconstpointer backend) {
+    hammer::Sequence sequence_1 = hammer::Sequence(hammer::Ch('a'), hammer::Ch('b'));
+    hammer::Sequence sequence_2 = hammer::Sequence(hammer::Ch('a'), hammer::Whitespace(hammer::Ch('b')));
+
+    g_check_parse_ok_cxx(sequence_1, (HParserBackend)GPOINTER_TO_INT(backend), "ab", "(u0x61 u0x62)");
+    g_check_parse_failed_cxx(sequence_1, (HParserBackend)GPOINTER_TO_INT(backend), "a");
+    g_check_parse_failed_cxx(sequence_1, (HParserBackend)GPOINTER_TO_INT(backend), "b");
+    g_check_parse_ok_cxx(sequence_2, (HParserBackend)GPOINTER_TO_INT(backend), "ab", "(u0x61 u0x62)");
+    g_check_parse_ok_cxx(sequence_2, (HParserBackend)GPOINTER_TO_INT(backend), "a b", "(u0x61 u0x62)");
+    g_check_parse_ok_cxx(sequence_2, (HParserBackend)GPOINTER_TO_INT(backend), "a  b", "(u0x61 u0x62)");  
+}
+
+static void test_choice_cxx(gconstpointer backend) {
+    hammer::Choice choice_ = hammer::Choice(hammer::Ch('a'), hammer::Ch('b'));
+
+    g_check_parse_ok_cxx(choice_, (HParserBackend)GPOINTER_TO_INT(backend), "a", "u0x61");
+    g_check_parse_ok_cxx(choice_, (HParserBackend)GPOINTER_TO_INT(backend), "b", "u0x62");
+    g_check_parse_failed_cxx(choice_, (HParserBackend)GPOINTER_TO_INT(backend), "c");
+}
+
+static void test_butnot_cxx(gconstpointer backend) {
+    hammer::ButNot butnot_1 = hammer::ButNot(hammer::Ch('a'), hammer::Token("ab"));
+    hammer::ButNot butnot_2 = hammer::ButNot(hammer::ChRange('0', '9'), hammer::Ch('6'));
+
+    g_check_parse_ok_cxx(butnot_1, (HParserBackend)GPOINTER_TO_INT(backend), "a", "u0x61");
+    g_check_parse_failed_cxx(butnot_1, (HParserBackend)GPOINTER_TO_INT(backend), "ab");
+    g_check_parse_ok_cxx(butnot_1, (HParserBackend)GPOINTER_TO_INT(backend), "aa", "u0x61");
+    g_check_parse_failed_cxx(butnot_2, (HParserBackend)GPOINTER_TO_INT(backend), "6");
+}
+
+static void test_difference_cxx(gconstpointer backend) {
+    hammer::Difference difference_ = hammer::Difference(hammer::Token("ab"), hammer::Ch('a'));
+
+    g_check_parse_ok_cxx(difference_, (HParserBackend)GPOINTER_TO_INT(backend), "ab", "<61.62>");
+    g_check_parse_failed_cxx(difference_, (HParserBackend)GPOINTER_TO_INT(backend), "a");
+}
+
+static void test_xor_cxx(gconstpointer backend) {
+    hammer::Xor xor_ = hammer::Xor(hammer::ChRange('0', '6'), hammer::ChRange('5', '9'));
+
+    g_check_parse_ok_cxx(xor_, (HParserBackend)GPOINTER_TO_INT(backend), "0", "u0x30");
+    g_check_parse_ok_cxx(xor_, (HParserBackend)GPOINTER_TO_INT(backend), "9", "u0x39");
+    g_check_parse_failed_cxx(xor_, (HParserBackend)GPOINTER_TO_INT(backend), "5");
+    g_check_parse_failed_cxx(xor_, (HParserBackend)GPOINTER_TO_INT(backend), "a");
+}
+
+static void test_many_cxx(gconstpointer backend) {
+    hammer::Many many_ = hammer::Choice(hammer::Ch('a'), hammer::Ch('b')).many();
+
+    g_check_parse_ok_cxx(many_, (HParserBackend)GPOINTER_TO_INT(backend), "", "()");
+    g_check_parse_ok_cxx(many_, (HParserBackend)GPOINTER_TO_INT(backend), "a", "(u0x61)");
+    g_check_parse_ok_cxx(many_, (HParserBackend)GPOINTER_TO_INT(backend), "b", "(u0x62)");
+    g_check_parse_ok_cxx(many_, (HParserBackend)GPOINTER_TO_INT(backend), "aabbaba", "(u0x61 u0x61 u0x62 u0x62 u0x61 u0x62 u0x61)");
+}
+
+static void test_many1_cxx(gconstpointer backend) {
+    hammer::Many1 many1_ = hammer::Choice(hammer::Ch('a'), hammer::Ch('b')).many1();
+
+    g_check_parse_failed_cxx(many1_, (HParserBackend)GPOINTER_TO_INT(backend), "");
+    g_check_parse_ok_cxx(many1_, (HParserBackend)GPOINTER_TO_INT(backend), "a", "(u0x61)");
+    g_check_parse_ok_cxx(many1_, (HParserBackend)GPOINTER_TO_INT(backend), "b", "(u0x62)");
+    g_check_parse_ok_cxx(many1_, (HParserBackend)GPOINTER_TO_INT(backend), "aabbaba", "(u0x61 u0x61 u0x62 u0x62 u0x61 u0x62 u0x61)");
+    g_check_parse_failed_cxx(many1_, (HParserBackend)GPOINTER_TO_INT(backend), "daabbabadef");  
+}
+
+static void test_repeat_n_cxx(gconstpointer backend) {
+    hammer::RepeatN repeat_n_ = hammer::Choice(hammer::Ch('a'), hammer::Ch('b'))[2];
+
+    g_check_parse_failed_cxx(repeat_n_, (HParserBackend)GPOINTER_TO_INT(backend), "adef");
+    g_check_parse_ok_cxx(repeat_n_, (HParserBackend)GPOINTER_TO_INT(backend), "abdef", "(u0x61 u0x62)");
+    g_check_parse_failed_cxx(repeat_n_, (HParserBackend)GPOINTER_TO_INT(backend), "dabdef");
+}
+
+static void test_optional_cxx(gconstpointer backend) {
+    hammer::Optional optional_ = hammer::Sequence(hammer::Ch('a'), 
+						  hammer::Choice(hammer::Ch('b'), hammer::Ch('c')).optional(), 
+						  hammer::ch('d'));
+  
+    g_check_parse_ok_cxx(optional_, (HParserBackend)GPOINTER_TO_INT(backend), "abd", "(u0x61 u0x62 u0x64)");
+    g_check_parse_ok_cxx(optional_, (HParserBackend)GPOINTER_TO_INT(backend), "acd", "(u0x61 u0x63 u0x64)");
+    g_check_parse_ok_cxx(optional_, (HParserBackend)GPOINTER_TO_INT(backend), "ad", "(u0x61 null u0x64)");
+    g_check_parse_failed_cxx(optional_, (HParserBackend)GPOINTER_TO_INT(backend), "aed");
+    g_check_parse_failed_cxx(optional_, (HParserBackend)GPOINTER_TO_INT(backend), "ab");
+    g_check_parse_failed_cxx(optional_, (HParserBackend)GPOINTER_TO_INT(backend), "ac");
+}
+
+static void test_ignore_cxx(gconstpointer backend) {
+    hammer::Ignore ignore_ = hammer::Sequence(hammer::Ch('a'), 
+					      hammer::ch('b').ignore(), 
+					      hammer::ch('c'));
+
+    g_check_parse_ok_cxx(ignore_, (HParserBackend)GPOINTER_TO_INT(backend), "abc", "(u0x61 u0x63)");
+    g_check_parse_failed_cxx(ignore_, (HParserBackend)GPOINTER_TO_INT(backend), "ac");
+}
+
+static void test_sepBy_cxx(gconstpointer backend) {
+    hammer::SepBy sepBy_ = hammer::SepBy(hammer::Choice(hammer::Ch('1'), hammer::Ch('2'), hammer::Ch('3')), hammer::Ch(','));
+
+    g_check_parse_ok_cxx(sepBy_, (HParserBackend)GPOINTER_TO_INT(backend), "1,2,3", "(u0x31 u0x32 u0x33)");
+  g_check_parse_ok_cxx(sepBy_, (HParserBackend)GPOINTER_TO_INT(backend), "1,3,2", "(u0x31 u0x33 u0x32)");
+  g_check_parse_ok_cxx(sepBy_, (HParserBackend)GPOINTER_TO_INT(backend), "1,3", "(u0x31 u0x33)");
+  g_check_parse_ok_cxx(sepBy_, (HParserBackend)GPOINTER_TO_INT(backend), "3", "(u0x33)");
+  g_check_parse_ok_cxx(sepBy_, (HParserBackend)GPOINTER_TO_INT(backend), "", "()");
+}
+
+static void test_sepBy1_cxx(gconstpointer backend) {
+    hammer::SepBy1 sepBy1_ = hammer::SepBy1(hammer::Choice(hammer::Ch('1'), hammer::Ch('2'), hammer::Ch('3')), hammer::Ch(','));
+
+    g_check_parse_ok_cxx(sepBy1_, (HParserBackend)GPOINTER_TO_INT(backend), "1,2,3", "(u0x31 u0x32 u0x33)");
+    g_check_parse_ok_cxx(sepBy1_, (HParserBackend)GPOINTER_TO_INT(backend), "1,3,2", "(u0x31 u0x33 u0x32)");
+    g_check_parse_ok_cxx(sepBy1_, (HParserBackend)GPOINTER_TO_INT(backend), "1,3", "(u0x31 u0x33)");
+    g_check_parse_ok_cxx(sepBy1_, (HParserBackend)GPOINTER_TO_INT(backend), "3", "(u0x33)");
+    g_check_parse_failed_cxx(sepBy1_, (HParserBackend)GPOINTER_TO_INT(backend), "");
+}
+
+static void test_epsilon_cxx(gconstpointer backend) {
+    hammer::Epsilon epsilon_p_1 = hammer::Sequence(hammer::Ch('a'), hammer::Epsilon(), hammer::Ch('b'));
+    hammer::Epsilon epsilon_p_2 = hammer::Sequence(hammer::Epsilon(), hammer::Ch('a'));
+    hammer::Epsilon epsilon_p_3 = hammer::Sequence(hammer::Ch('a'), hammer::Epsilon());
+  
+    g_check_parse_ok_cxx(epsilon_p_1, (HParserBackend)GPOINTER_TO_INT(backend), "ab", "(u0x61 u0x62)");
+    g_check_parse_ok_cxx(epsilon_p_2, (HParserBackend)GPOINTER_TO_INT(backend), "a", "(u0x61)");
+    g_check_parse_ok_cxx(epsilon_p_3, (HParserBackend)GPOINTER_TO_INT(backend), "a", "(u0x61)");
+}
+
+static void test_and_cxx(gconstpointer backend) {
+    hammer::And and_1 = hammer::Sequence(hammer::And(hammer::Ch('0')), hammer::Ch('0'));
+    hammer::And and_2 = hammer::Sequence(hammer::And(hammer::Ch('0')), hammer::Ch('1'));
+    hammer::And and_3 = hammer::Sequence(hammer::Ch('1'), hammer::And(hammer::Ch('2')));
+
+    g_check_parse_ok_cxx(and_1, (HParserBackend)GPOINTER_TO_INT(backend), "0", "(u0x30)");
+    g_check_parse_failed_cxx(and_2, (HParserBackend)GPOINTER_TO_INT(backend), "0");
+    g_check_parse_ok_cxx(and_3, (HParserBackend)GPOINTER_TO_INT(backend), "12", "(u0x31)");
+}
+
+static void test_not_cxx(gconstpointer backend) {
+    hammer::Not not_1 = hammer::Sequence(hammer::Ch('a'), hammer::Choice(hammer::Ch('+'), hammer::Token("++")), hammer::Ch('b'));
+    hammer::Not not_2 = hammer::Sequence(hammer::Ch('a'),
+					 hammer::Choice(hammer::Sequence(hammer::Ch('+'), 
+									 hammer::Not(hammer::Ch('+'))),
+							hammer::Token("++")), 
+					 hammer::Ch('b'));
+
+    g_check_parse_ok_cxx(not_1, (HParserBackend)GPOINTER_TO_INT(backend), "a+b", "(u0x61 u0x2b u0x62)");
+    g_check_parse_failed_cxx(not_1, (HParserBackend)GPOINTER_TO_INT(backend), "a++b");
+    g_check_parse_ok_cxx(not_2, (HParserBackend)GPOINTER_TO_INT(backend), "a+b", "(u0x61 (u0x2b) u0x62)");
+    g_check_parse_ok_cxx(not_2, (HParserBackend)GPOINTER_TO_INT(backend), "a++b", "(u0x61 <2b.2b> u0x62)");
+}
+
+static void test_leftrec(gconstpointer backend) {
+    hammer::Ch a_ = hammer::Ch('a');
+
+    hammer::Indirect lr_ = hammer::Indirect(); 
+
+    lr_.bind(hammer::Choice(hammer::Sequence(lr_, a_), a_));
+
+    g_check_parse_ok_cxx(lr_, (HParserBackend)GPOINTER_TO_INT(backend), "a", "u0x61");
+    g_check_parse_ok_cxx(lr_, (HParserBackend)GPOINTER_TO_INT(backend), "aa", "(u0x61 u0x61)");
+    g_check_parse_ok_cxx(lr_, (HParserBackend)GPOINTER_TO_INT(backend), "aaa", "((u0x61 u0x61) u0x61)");
+}
+
+static void test_rightrec(gconstpointer backend) {
+    hammer::Ch a_ = hammer::Ch('a');
+
+    hammer::Indirect rr_ = hammer::Indirect();
+    rr_.bind(hammer::Choice(hammer::Sequence(a_, rr_), hammer::Epsilon()));
+
+    g_check_parse_ok_cxx(rr_, (HParserBackend)GPOINTER_TO_INT(backend), "a", "(u0x61)");
+    g_check_parse_ok_cxx(rr_, (HParserBackend)GPOINTER_TO_INT(backend), "aa", "(u0x61 (u0x61))");
+    g_check_parse_ok_cxx(rr_, (HParserBackend)GPOINTER_TO_INT(backend), "aaa", "(u0x61 (u0x61 (u0x61)))");
+}
+
+// FIXME won't be ready until action is ready
+/*
+static void test_ambiguous(gconstpointer backend) {
+  hammer::Ch d_ = hammer::Ch('d');
+  hammer::Ch p_ = hammer::Ch('+');
+  hammer::Indirect E_ = hammer::Indirect();
+  E_.bind(hammer::Choice(hammer::Sequence(E_, p_, E_), d_));
+  hammer::Action expr_ = hammer::Action(E_, act_flatten);
+
+  g_check_parse_ok_cxx(expr_, (HParserBackend)GPOINTER_TO_INT(backend), "d", "(u0x64)");
+  g_check_parse_ok_cxx(expr_, (HParserBackend)GPOINTER_TO_INT(backend), "d+d", "(u0x64 u0x2b u0x64)");
+  g_check_parse_ok_cxx(expr_, (HParserBackend)GPOINTER_TO_INT(backend), "d+d+d", "(u0x64 u0x2b u0x64 u0x2b u0x64)");
+  g_check_parse_failed_cxx(expr_, (HParserBackend)GPOINTER_TO_INT(backend), "d+");
+}
+*/
+
+void register_cxx_tests(void) {
+    g_test_add_data_func("/core/c++/parser/packrat/token", GINT_TO_POINTER(PB_PACKRAT), test_token_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/ch", GINT_TO_POINTER(PB_PACKRAT), test_ch_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/ch_range", GINT_TO_POINTER(PB_PACKRAT), test_ch_range_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/int64", GINT_TO_POINTER(PB_PACKRAT), test_int64_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/int32", GINT_TO_POINTER(PB_PACKRAT), test_int32_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/int16", GINT_TO_POINTER(PB_PACKRAT), test_int16_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/int8", GINT_TO_POINTER(PB_PACKRAT), test_int8_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/uint64", GINT_TO_POINTER(PB_PACKRAT), test_uint64_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/uint32", GINT_TO_POINTER(PB_PACKRAT), test_uint32_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/uint16", GINT_TO_POINTER(PB_PACKRAT), test_uint16_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/uint8", GINT_TO_POINTER(PB_PACKRAT), test_uint8_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/int_range", GINT_TO_POINTER(PB_PACKRAT), test_int_range_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/whitespace", GINT_TO_POINTER(PB_PACKRAT), test_whitespace_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/left", GINT_TO_POINTER(PB_PACKRAT), test_left_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/right", GINT_TO_POINTER(PB_PACKRAT), test_right_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/middle", GINT_TO_POINTER(PB_PACKRAT), test_middle_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/in", GINT_TO_POINTER(PB_PACKRAT), test_in_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/not_in", GINT_TO_POINTER(PB_PACKRAT), test_not_in_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/end", GINT_TO_POINTER(PB_PACKRAT), test_end_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/nothing", GINT_TO_POINTER(PB_PACKRAT), test_nothing_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/sequence", GINT_TO_POINTER(PB_PACKRAT), test_sequence_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/choice", GINT_TO_POINTER(PB_PACKRAT), test_choice_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/butnot", GINT_TO_POINTER(PB_PACKRAT), test_butnot_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/difference", GINT_TO_POINTER(PB_PACKRAT), test_difference_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/xor", GINT_TO_POINTER(PB_PACKRAT), test_xor_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/many", GINT_TO_POINTER(PB_PACKRAT), test_many_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/many1", GINT_TO_POINTER(PB_PACKRAT), test_many1_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/repeat_n", GINT_TO_POINTER(PB_PACKRAT), test_repeat_n_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/optional", GINT_TO_POINTER(PB_PACKRAT), test_optional_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/ignore", GINT_TO_POINTER(PB_PACKRAT), test_ignore_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/sepBy", GINT_TO_POINTER(PB_PACKRAT), test_sepBy_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/sepBy1", GINT_TO_POINTER(PB_PACKRAT), test_sepBy1_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/epsilon", GINT_TO_POINTER(PB_PACKRAT), test_epsilon_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/and", GINT_TO_POINTER(PB_PACKRAT), test_and_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/not", GINT_TO_POINTER(PB_PACKRAT), test_not_cxx);
+    //    g_test_add_data_func("/core/c++/parser/packrat/leftrec", GINT_TO_POINTER(PB_PACKRAT), test_leftrec_cxx);
+    g_test_add_data_func("/core/c++/parser/packrat/rightrec", GINT_TO_POINTER(PB_PACKRAT), test_rightrec_cxx);
+
+    g_test_add_data_Func("/core/c++/parser/llk/token", GINT_TO_POINTER(PB_LLk), test_token_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/token", GINT_TO_POINTER(PB_LLk), test_token_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/ch", GINT_TO_POINTER(PB_LLk), test_ch_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/ch_range", GINT_TO_POINTER(PB_LLk), test_ch_range_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/int64", GINT_TO_POINTER(PB_LLk), test_int64_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/int32", GINT_TO_POINTER(PB_LLk), test_int32_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/int16", GINT_TO_POINTER(PB_LLk), test_int16_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/int8", GINT_TO_POINTER(PB_LLk), test_int8_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/uint64", GINT_TO_POINTER(PB_LLk), test_uint64_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/uint32", GINT_TO_POINTER(PB_LLk), test_uint32_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/uint16", GINT_TO_POINTER(PB_LLk), test_uint16_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/uint8", GINT_TO_POINTER(PB_LLk), test_uint8_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/int_range", GINT_TO_POINTER(PB_LLk), test_int_range_cxx);
+#if 0
+    g_test_add_data_func("/core/c++/parser/llk/float64", GINT_TO_POINTER(PB_LLk), test_float64_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/float32", GINT_TO_POINTER(PB_LLk), test_float32_cxx);
+#endif
+    g_test_add_data_func("/core/c++/parser/llk/whitespace", GINT_TO_POINTER(PB_LLk), test_whitespace_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/left", GINT_TO_POINTER(PB_LLk), test_left_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/right", GINT_TO_POINTER(PB_LLk), test_right_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/middle", GINT_TO_POINTER(PB_LLk), test_middle_cxx);
+    //g_test_add_data_func("/core/c++/parser/llk/action", GINT_TO_POINTER(PB_LLk), test_action_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/in", GINT_TO_POINTER(PB_LLk), test_in_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/not_in", GINT_TO_POINTER(PB_LLk), test_not_in_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/end", GINT_TO_POINTER(PB_LLk), test_end_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/nothing", GINT_TO_POINTER(PB_LLk), test_nothing_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/sequence", GINT_TO_POINTER(PB_LLk), test_sequence_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/choice", GINT_TO_POINTER(PB_LLk), test_choice_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/many", GINT_TO_POINTER(PB_LLk), test_many_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/many1", GINT_TO_POINTER(PB_LLk), test_many1_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/optional", GINT_TO_POINTER(PB_LLk), test_optional_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/sepBy", GINT_TO_POINTER(PB_LLk), test_sepBy_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/sepBy1", GINT_TO_POINTER(PB_LLk), test_sepBy1_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/epsilon", GINT_TO_POINTER(PB_LLk), test_epsilon_cxx);
+    //g_test_add_data_func("/core/c++/parser/llk/attr_bool", GINT_TO_POINTER(PB_LLk), test_attr_bool_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/ignore", GINT_TO_POINTER(PB_LLk), test_ignore_cxx);
+    //g_test_add_data_func("/core/c++/parser/llk/leftrec", GINT_TO_POINTER(PB_LLk), test_leftrec_cxx);
+    g_test_add_data_func("/core/c++/parser/llk/rightrec", GINT_TO_POINTER(PB_LLk), test_rightrec_cxx);
+
+    g_test_add_data_func("/core/c++/parser/regex/token", GINT_TO_POINTER(PB_REGULAR), test_token_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/ch", GINT_TO_POINTER(PB_REGULAR), test_ch_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/ch_range", GINT_TO_POINTER(PB_REGULAR), test_ch_range_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/int64", GINT_TO_POINTER(PB_REGULAR), test_int64_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/int32", GINT_TO_POINTER(PB_REGULAR), test_int32_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/int16", GINT_TO_POINTER(PB_REGULAR), test_int16_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/int8", GINT_TO_POINTER(PB_REGULAR), test_int8_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/uint64", GINT_TO_POINTER(PB_REGULAR), test_uint64_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/uint32", GINT_TO_POINTER(PB_REGULAR), test_uint32_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/uint16", GINT_TO_POINTER(PB_REGULAR), test_uint16_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/uint8", GINT_TO_POINTER(PB_REGULAR), test_uint8_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/int_range", GINT_TO_POINTER(PB_REGULAR), test_int_range_cxx);
+#if 0
+    g_test_add_data_func("/core/c++/parser/regex/float64", GINT_TO_POINTER(PB_REGULAR), test_float64_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/float32", GINT_TO_POINTER(PB_REGULAR), test_float32_cxx);
+#endif
+    g_test_add_data_func("/core/c++/parser/regex/whitespace", GINT_TO_POINTER(PB_REGULAR), test_whitespace_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/left", GINT_TO_POINTER(PB_REGULAR), test_left_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/right", GINT_TO_POINTER(PB_REGULAR), test_right_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/middle", GINT_TO_POINTER(PB_REGULAR), test_middle_cxx);
+    //  g_test_add_data_func("/core/c++/parser/regex/action", GINT_TO_POINTER(PB_REGULAR), test_action_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/in", GINT_TO_POINTER(PB_REGULAR), test_in_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/not_in", GINT_TO_POINTER(PB_REGULAR), test_not_in_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/end", GINT_TO_POINTER(PB_REGULAR), test_end_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/nothing", GINT_TO_POINTER(PB_REGULAR), test_nothing_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/sequence", GINT_TO_POINTER(PB_REGULAR), test_sequence_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/choice", GINT_TO_POINTER(PB_REGULAR), test_choice_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/many", GINT_TO_POINTER(PB_REGULAR), test_many_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/many1", GINT_TO_POINTER(PB_REGULAR), test_many1_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/repeat_n", GINT_TO_POINTER(PB_REGULAR), test_repeat_n_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/optional", GINT_TO_POINTER(PB_REGULAR), test_optional_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/sepBy", GINT_TO_POINTER(PB_REGULAR), test_sepBy_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/sepBy1", GINT_TO_POINTER(PB_REGULAR), test_sepBy1_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/epsilon", GINT_TO_POINTER(PB_REGULAR), test_epsilon_cxx);
+    //  g_test_add_data_func("/core/c++/parser/regex/attr_bool", GINT_TO_POINTER(PB_REGULAR), test_attr_bool_cxx);
+    g_test_add_data_func("/core/c++/parser/regex/ignore", GINT_TO_POINTER(PB_REGULAR), test_ignore_cxx);
+
+    g_test_add_data_func("/core/c++/parser/lalr/token", GINT_TO_POINTER(PB_LALR), test_token_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/ch", GINT_TO_POINTER(PB_LALR), test_ch_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/ch_range", GINT_TO_POINTER(PB_LALR), test_ch_range_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/int64", GINT_TO_POINTER(PB_LALR), test_int64_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/int32", GINT_TO_POINTER(PB_LALR), test_int32_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/int16", GINT_TO_POINTER(PB_LALR), test_int16_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/int8", GINT_TO_POINTER(PB_LALR), test_int8_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/uint64", GINT_TO_POINTER(PB_LALR), test_uint64_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/uint32", GINT_TO_POINTER(PB_LALR), test_uint32_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/uint16", GINT_TO_POINTER(PB_LALR), test_uint16_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/uint8", GINT_TO_POINTER(PB_LALR), test_uint8_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/int_range", GINT_TO_POINTER(PB_LALR), test_int_range_cxx);
+#if 0
+  g_test_add_data_func("/core/c++/parser/lalr/float64", GINT_TO_POINTER(PB_LALR), test_float64_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/float32", GINT_TO_POINTER(PB_LALR), test_float32_cxx);
+#endif
+  g_test_add_data_func("/core/c++/parser/lalr/whitespace", GINT_TO_POINTER(PB_LALR), test_whitespace_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/left", GINT_TO_POINTER(PB_LALR), test_left_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/right", GINT_TO_POINTER(PB_LALR), test_right_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/middle", GINT_TO_POINTER(PB_LALR), test_middle_cxx);
+  //  g_test_add_data_func("/core/c++/parser/lalr/action", GINT_TO_POINTER(PB_LALR), test_action_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/in", GINT_TO_POINTER(PB_LALR), test_in_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/not_in", GINT_TO_POINTER(PB_LALR), test_not_in_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/end", GINT_TO_POINTER(PB_LALR), test_end_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/nothing", GINT_TO_POINTER(PB_LALR), test_nothing_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/sequence", GINT_TO_POINTER(PB_LALR), test_sequence_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/choice", GINT_TO_POINTER(PB_LALR), test_choice_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/many", GINT_TO_POINTER(PB_LALR), test_many_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/many1", GINT_TO_POINTER(PB_LALR), test_many1_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/optional", GINT_TO_POINTER(PB_LALR), test_optional_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/sepBy", GINT_TO_POINTER(PB_LALR), test_sepBy_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/sepBy1", GINT_TO_POINTER(PB_LALR), test_sepBy1_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/epsilon", GINT_TO_POINTER(PB_LALR), test_epsilon_cxx);
+  //  g_test_add_data_func("/core/c++/parser/lalr/attr_bool", GINT_TO_POINTER(PB_LALR), test_attr_bool_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/ignore", GINT_TO_POINTER(PB_LALR), test_ignore_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/leftrec", GINT_TO_POINTER(PB_LALR), test_leftrec_cxx);
+  g_test_add_data_func("/core/c++/parser/lalr/rightrec", GINT_TO_POINTER(PB_LALR), test_rightrec_cxx);
+
+    g_test_add_data_func("/core/c++/parser/glr/token", GINT_TO_POINTER(PB_GLR), test_token_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/ch", GINT_TO_POINTER(PB_GLR), test_ch_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/ch_range", GINT_TO_POINTER(PB_GLR), test_ch_range_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/int64", GINT_TO_POINTER(PB_GLR), test_int64_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/int32", GINT_TO_POINTER(PB_GLR), test_int32_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/int16", GINT_TO_POINTER(PB_GLR), test_int16_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/int8", GINT_TO_POINTER(PB_GLR), test_int8_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/uint64", GINT_TO_POINTER(PB_GLR), test_uint64_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/uint32", GINT_TO_POINTER(PB_GLR), test_uint32_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/uint16", GINT_TO_POINTER(PB_GLR), test_uint16_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/uint8", GINT_TO_POINTER(PB_GLR), test_uint8_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/int_range", GINT_TO_POINTER(PB_GLR), test_int_range_cxx);
+#if 0
+    g_test_add_data_func("/core/c++/parser/glr/float64", GINT_TO_POINTER(PB_GLR), test_float64_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/float32", GINT_TO_POINTER(PB_GLR), test_float32_cxx);
+#endif
+    g_test_add_data_func("/core/c++/parser/glr/whitespace", GINT_TO_POINTER(PB_GLR), test_whitespace_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/left", GINT_TO_POINTER(PB_GLR), test_left_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/right", GINT_TO_POINTER(PB_GLR), test_right_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/middle", GINT_TO_POINTER(PB_GLR), test_middle_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/action", GINT_TO_POINTER(PB_GLR), test_action_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/in", GINT_TO_POINTER(PB_GLR), test_in_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/not_in", GINT_TO_POINTER(PB_GLR), test_not_in_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/end", GINT_TO_POINTER(PB_GLR), test_end_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/nothing", GINT_TO_POINTER(PB_GLR), test_nothing_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/sequence", GINT_TO_POINTER(PB_GLR), test_sequence_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/choice", GINT_TO_POINTER(PB_GLR), test_choice_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/many", GINT_TO_POINTER(PB_GLR), test_many_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/many1", GINT_TO_POINTER(PB_GLR), test_many1_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/optional", GINT_TO_POINTER(PB_GLR), test_optional_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/sepBy", GINT_TO_POINTER(PB_GLR), test_sepBy_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/sepBy1", GINT_TO_POINTER(PB_GLR), test_sepBy1_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/epsilon", GINT_TO_POINTER(PB_GLR), test_epsilon_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/attr_bool", GINT_TO_POINTER(PB_GLR), test_attr_bool_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/ignore", GINT_TO_POINTER(PB_GLR), test_ignore_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/leftrec", GINT_TO_POINTER(PB_GLR), test_leftrec_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/rightrec", GINT_TO_POINTER(PB_GLR), test_rightrec_cxx);
+    g_test_add_data_func("/core/c++/parser/glr/ambiguous", GINT_TO_POINTER(PB_GLR), test_ambiguous_cxx);
+
+}
+
+/*
+int main(int argc, char **argv) {
+  hammer::Ch p = hammer::Ch('a');
+  std::string test = "a";
+  hammer::UintResult r = p.parse(test);
+  std::cerr << r.result() << std::endl;
+  hammer::SequenceResult s = p.many().parse(test);
+  hammer::UintResult u = boost::get<hammer::UintResult>(s.result()[0]);
+  std::cerr << u.result() << std::endl;
+  return 0;
+}
+*/
diff --git a/src/t_parser.c b/src/t_parser.c
index 59adf36a69d1e34f9a460088a7021d8d14ff6df5..c49e443a2a57921105d3f1af7b62b4d8f64e126d 100644
--- a/src/t_parser.c
+++ b/src/t_parser.c
@@ -442,199 +442,199 @@ static void test_ambiguous(gconstpointer backend) {
 }
 
 void register_parser_tests(void) {
-  g_test_add_data_func("/core/parser/packrat/token", GINT_TO_POINTER(PB_PACKRAT), test_token);
-  g_test_add_data_func("/core/parser/packrat/ch", GINT_TO_POINTER(PB_PACKRAT), test_ch);
-  g_test_add_data_func("/core/parser/packrat/ch_range", GINT_TO_POINTER(PB_PACKRAT), test_ch_range);
-  g_test_add_data_func("/core/parser/packrat/int64", GINT_TO_POINTER(PB_PACKRAT), test_int64);
-  g_test_add_data_func("/core/parser/packrat/int32", GINT_TO_POINTER(PB_PACKRAT), test_int32);
-  g_test_add_data_func("/core/parser/packrat/int16", GINT_TO_POINTER(PB_PACKRAT), test_int16);
-  g_test_add_data_func("/core/parser/packrat/int8", GINT_TO_POINTER(PB_PACKRAT), test_int8);
-  g_test_add_data_func("/core/parser/packrat/uint64", GINT_TO_POINTER(PB_PACKRAT), test_uint64);
-  g_test_add_data_func("/core/parser/packrat/uint32", GINT_TO_POINTER(PB_PACKRAT), test_uint32);
-  g_test_add_data_func("/core/parser/packrat/uint16", GINT_TO_POINTER(PB_PACKRAT), test_uint16);
-  g_test_add_data_func("/core/parser/packrat/uint8", GINT_TO_POINTER(PB_PACKRAT), test_uint8);
-  g_test_add_data_func("/core/parser/packrat/int_range", GINT_TO_POINTER(PB_PACKRAT), test_int_range);
+  g_test_add_data_func("/core/c/parser/packrat/token", GINT_TO_POINTER(PB_PACKRAT), test_token);
+  g_test_add_data_func("/core/c/parser/packrat/ch", GINT_TO_POINTER(PB_PACKRAT), test_ch);
+  g_test_add_data_func("/core/c/parser/packrat/ch_range", GINT_TO_POINTER(PB_PACKRAT), test_ch_range);
+  g_test_add_data_func("/core/c/parser/packrat/int64", GINT_TO_POINTER(PB_PACKRAT), test_int64);
+  g_test_add_data_func("/core/c/parser/packrat/int32", GINT_TO_POINTER(PB_PACKRAT), test_int32);
+  g_test_add_data_func("/core/c/parser/packrat/int16", GINT_TO_POINTER(PB_PACKRAT), test_int16);
+  g_test_add_data_func("/core/c/parser/packrat/int8", GINT_TO_POINTER(PB_PACKRAT), test_int8);
+  g_test_add_data_func("/core/c/parser/packrat/uint64", GINT_TO_POINTER(PB_PACKRAT), test_uint64);
+  g_test_add_data_func("/core/c/parser/packrat/uint32", GINT_TO_POINTER(PB_PACKRAT), test_uint32);
+  g_test_add_data_func("/core/c/parser/packrat/uint16", GINT_TO_POINTER(PB_PACKRAT), test_uint16);
+  g_test_add_data_func("/core/c/parser/packrat/uint8", GINT_TO_POINTER(PB_PACKRAT), test_uint8);
+  g_test_add_data_func("/core/c/parser/packrat/int_range", GINT_TO_POINTER(PB_PACKRAT), test_int_range);
 #if 0
-  g_test_add_data_func("/core/parser/packrat/float64", GINT_TO_POINTER(PB_PACKRAT), test_float64);
-  g_test_add_data_func("/core/parser/packrat/float32", GINT_TO_POINTER(PB_PACKRAT), test_float32);
+  g_test_add_data_func("/core/c/parser/packrat/float64", GINT_TO_POINTER(PB_PACKRAT), test_float64);
+  g_test_add_data_func("/core/c/parser/packrat/float32", GINT_TO_POINTER(PB_PACKRAT), test_float32);
 #endif
-  g_test_add_data_func("/core/parser/packrat/whitespace", GINT_TO_POINTER(PB_PACKRAT), test_whitespace);
-  g_test_add_data_func("/core/parser/packrat/left", GINT_TO_POINTER(PB_PACKRAT), test_left);
-  g_test_add_data_func("/core/parser/packrat/right", GINT_TO_POINTER(PB_PACKRAT), test_right);
-  g_test_add_data_func("/core/parser/packrat/middle", GINT_TO_POINTER(PB_PACKRAT), test_middle);
-  g_test_add_data_func("/core/parser/packrat/action", GINT_TO_POINTER(PB_PACKRAT), test_action);
-  g_test_add_data_func("/core/parser/packrat/in", GINT_TO_POINTER(PB_PACKRAT), test_in);
-  g_test_add_data_func("/core/parser/packrat/not_in", GINT_TO_POINTER(PB_PACKRAT), test_not_in);
-  g_test_add_data_func("/core/parser/packrat/end_p", GINT_TO_POINTER(PB_PACKRAT), test_end_p);
-  g_test_add_data_func("/core/parser/packrat/nothing_p", GINT_TO_POINTER(PB_PACKRAT), test_nothing_p);
-  g_test_add_data_func("/core/parser/packrat/sequence", GINT_TO_POINTER(PB_PACKRAT), test_sequence);
-  g_test_add_data_func("/core/parser/packrat/choice", GINT_TO_POINTER(PB_PACKRAT), test_choice);
-  g_test_add_data_func("/core/parser/packrat/butnot", GINT_TO_POINTER(PB_PACKRAT), test_butnot);
-  g_test_add_data_func("/core/parser/packrat/difference", GINT_TO_POINTER(PB_PACKRAT), test_difference);
-  g_test_add_data_func("/core/parser/packrat/xor", GINT_TO_POINTER(PB_PACKRAT), test_xor);
-  g_test_add_data_func("/core/parser/packrat/many", GINT_TO_POINTER(PB_PACKRAT), test_many);
-  g_test_add_data_func("/core/parser/packrat/many1", GINT_TO_POINTER(PB_PACKRAT), test_many1);
-  g_test_add_data_func("/core/parser/packrat/repeat_n", GINT_TO_POINTER(PB_PACKRAT), test_repeat_n);
-  g_test_add_data_func("/core/parser/packrat/optional", GINT_TO_POINTER(PB_PACKRAT), test_optional);
-  g_test_add_data_func("/core/parser/packrat/sepBy", GINT_TO_POINTER(PB_PACKRAT), test_sepBy);
-  g_test_add_data_func("/core/parser/packrat/sepBy1", GINT_TO_POINTER(PB_PACKRAT), test_sepBy1);
-  g_test_add_data_func("/core/parser/packrat/epsilon_p", GINT_TO_POINTER(PB_PACKRAT), test_epsilon_p);
-  g_test_add_data_func("/core/parser/packrat/attr_bool", GINT_TO_POINTER(PB_PACKRAT), test_attr_bool);
-  g_test_add_data_func("/core/parser/packrat/and", GINT_TO_POINTER(PB_PACKRAT), test_and);
-  g_test_add_data_func("/core/parser/packrat/not", GINT_TO_POINTER(PB_PACKRAT), test_not);
-  g_test_add_data_func("/core/parser/packrat/ignore", GINT_TO_POINTER(PB_PACKRAT), test_ignore);
-  //  g_test_add_data_func("/core/parser/packrat/leftrec", GINT_TO_POINTER(PB_PACKRAT), test_leftrec);
-  g_test_add_data_func("/core/parser/packrat/rightrec", GINT_TO_POINTER(PB_PACKRAT), test_rightrec);
-
-  g_test_add_data_func("/core/parser/llk/token", GINT_TO_POINTER(PB_LLk), test_token);
-  g_test_add_data_func("/core/parser/llk/ch", GINT_TO_POINTER(PB_LLk), test_ch);
-  g_test_add_data_func("/core/parser/llk/ch_range", GINT_TO_POINTER(PB_LLk), test_ch_range);
-  g_test_add_data_func("/core/parser/llk/int64", GINT_TO_POINTER(PB_LLk), test_int64);
-  g_test_add_data_func("/core/parser/llk/int32", GINT_TO_POINTER(PB_LLk), test_int32);
-  g_test_add_data_func("/core/parser/llk/int16", GINT_TO_POINTER(PB_LLk), test_int16);
-  g_test_add_data_func("/core/parser/llk/int8", GINT_TO_POINTER(PB_LLk), test_int8);
-  g_test_add_data_func("/core/parser/llk/uint64", GINT_TO_POINTER(PB_LLk), test_uint64);
-  g_test_add_data_func("/core/parser/llk/uint32", GINT_TO_POINTER(PB_LLk), test_uint32);
-  g_test_add_data_func("/core/parser/llk/uint16", GINT_TO_POINTER(PB_LLk), test_uint16);
-  g_test_add_data_func("/core/parser/llk/uint8", GINT_TO_POINTER(PB_LLk), test_uint8);
-  g_test_add_data_func("/core/parser/llk/int_range", GINT_TO_POINTER(PB_LLk), test_int_range);
+  g_test_add_data_func("/core/c/parser/packrat/whitespace", GINT_TO_POINTER(PB_PACKRAT), test_whitespace);
+  g_test_add_data_func("/core/c/parser/packrat/left", GINT_TO_POINTER(PB_PACKRAT), test_left);
+  g_test_add_data_func("/core/c/parser/packrat/right", GINT_TO_POINTER(PB_PACKRAT), test_right);
+  g_test_add_data_func("/core/c/parser/packrat/middle", GINT_TO_POINTER(PB_PACKRAT), test_middle);
+  g_test_add_data_func("/core/c/parser/packrat/action", GINT_TO_POINTER(PB_PACKRAT), test_action);
+  g_test_add_data_func("/core/c/parser/packrat/in", GINT_TO_POINTER(PB_PACKRAT), test_in);
+  g_test_add_data_func("/core/c/parser/packrat/not_in", GINT_TO_POINTER(PB_PACKRAT), test_not_in);
+  g_test_add_data_func("/core/c/parser/packrat/end_p", GINT_TO_POINTER(PB_PACKRAT), test_end_p);
+  g_test_add_data_func("/core/c/parser/packrat/nothing_p", GINT_TO_POINTER(PB_PACKRAT), test_nothing_p);
+  g_test_add_data_func("/core/c/parser/packrat/sequence", GINT_TO_POINTER(PB_PACKRAT), test_sequence);
+  g_test_add_data_func("/core/c/parser/packrat/choice", GINT_TO_POINTER(PB_PACKRAT), test_choice);
+  g_test_add_data_func("/core/c/parser/packrat/butnot", GINT_TO_POINTER(PB_PACKRAT), test_butnot);
+  g_test_add_data_func("/core/c/parser/packrat/difference", GINT_TO_POINTER(PB_PACKRAT), test_difference);
+  g_test_add_data_func("/core/c/parser/packrat/xor", GINT_TO_POINTER(PB_PACKRAT), test_xor);
+  g_test_add_data_func("/core/c/parser/packrat/many", GINT_TO_POINTER(PB_PACKRAT), test_many);
+  g_test_add_data_func("/core/c/parser/packrat/many1", GINT_TO_POINTER(PB_PACKRAT), test_many1);
+  g_test_add_data_func("/core/c/parser/packrat/repeat_n", GINT_TO_POINTER(PB_PACKRAT), test_repeat_n);
+  g_test_add_data_func("/core/c/parser/packrat/optional", GINT_TO_POINTER(PB_PACKRAT), test_optional);
+  g_test_add_data_func("/core/c/parser/packrat/sepBy", GINT_TO_POINTER(PB_PACKRAT), test_sepBy);
+  g_test_add_data_func("/core/c/parser/packrat/sepBy1", GINT_TO_POINTER(PB_PACKRAT), test_sepBy1);
+  g_test_add_data_func("/core/c/parser/packrat/epsilon_p", GINT_TO_POINTER(PB_PACKRAT), test_epsilon_p);
+  g_test_add_data_func("/core/c/parser/packrat/attr_bool", GINT_TO_POINTER(PB_PACKRAT), test_attr_bool);
+  g_test_add_data_func("/core/c/parser/packrat/and", GINT_TO_POINTER(PB_PACKRAT), test_and);
+  g_test_add_data_func("/core/c/parser/packrat/not", GINT_TO_POINTER(PB_PACKRAT), test_not);
+  g_test_add_data_func("/core/c/parser/packrat/ignore", GINT_TO_POINTER(PB_PACKRAT), test_ignore);
+  //  g_test_add_data_func("/core/c/parser/packrat/leftrec", GINT_TO_POINTER(PB_PACKRAT), test_leftrec);
+  g_test_add_data_func("/core/c/parser/packrat/rightrec", GINT_TO_POINTER(PB_PACKRAT), test_rightrec);
+
+  g_test_add_data_func("/core/c/parser/llk/token", GINT_TO_POINTER(PB_LLk), test_token);
+  g_test_add_data_func("/core/c/parser/llk/ch", GINT_TO_POINTER(PB_LLk), test_ch);
+  g_test_add_data_func("/core/c/parser/llk/ch_range", GINT_TO_POINTER(PB_LLk), test_ch_range);
+  g_test_add_data_func("/core/c/parser/llk/int64", GINT_TO_POINTER(PB_LLk), test_int64);
+  g_test_add_data_func("/core/c/parser/llk/int32", GINT_TO_POINTER(PB_LLk), test_int32);
+  g_test_add_data_func("/core/c/parser/llk/int16", GINT_TO_POINTER(PB_LLk), test_int16);
+  g_test_add_data_func("/core/c/parser/llk/int8", GINT_TO_POINTER(PB_LLk), test_int8);
+  g_test_add_data_func("/core/c/parser/llk/uint64", GINT_TO_POINTER(PB_LLk), test_uint64);
+  g_test_add_data_func("/core/c/parser/llk/uint32", GINT_TO_POINTER(PB_LLk), test_uint32);
+  g_test_add_data_func("/core/c/parser/llk/uint16", GINT_TO_POINTER(PB_LLk), test_uint16);
+  g_test_add_data_func("/core/c/parser/llk/uint8", GINT_TO_POINTER(PB_LLk), test_uint8);
+  g_test_add_data_func("/core/c/parser/llk/int_range", GINT_TO_POINTER(PB_LLk), test_int_range);
 #if 0
-  g_test_add_data_func("/core/parser/llk/float64", GINT_TO_POINTER(PB_LLk), test_float64);
-  g_test_add_data_func("/core/parser/llk/float32", GINT_TO_POINTER(PB_LLk), test_float32);
+  g_test_add_data_func("/core/c/parser/llk/float64", GINT_TO_POINTER(PB_LLk), test_float64);
+  g_test_add_data_func("/core/c/parser/llk/float32", GINT_TO_POINTER(PB_LLk), test_float32);
 #endif
-  g_test_add_data_func("/core/parser/llk/whitespace", GINT_TO_POINTER(PB_LLk), test_whitespace);
-  g_test_add_data_func("/core/parser/llk/left", GINT_TO_POINTER(PB_LLk), test_left);
-  g_test_add_data_func("/core/parser/llk/right", GINT_TO_POINTER(PB_LLk), test_right);
-  g_test_add_data_func("/core/parser/llk/middle", GINT_TO_POINTER(PB_LLk), test_middle);
-  g_test_add_data_func("/core/parser/llk/action", GINT_TO_POINTER(PB_LLk), test_action);
-  g_test_add_data_func("/core/parser/llk/in", GINT_TO_POINTER(PB_LLk), test_in);
-  g_test_add_data_func("/core/parser/llk/not_in", GINT_TO_POINTER(PB_LLk), test_not_in);
-  g_test_add_data_func("/core/parser/llk/end_p", GINT_TO_POINTER(PB_LLk), test_end_p);
-  g_test_add_data_func("/core/parser/llk/nothing_p", GINT_TO_POINTER(PB_LLk), test_nothing_p);
-  g_test_add_data_func("/core/parser/llk/sequence", GINT_TO_POINTER(PB_LLk), test_sequence);
-  g_test_add_data_func("/core/parser/llk/choice", GINT_TO_POINTER(PB_LLk), test_choice);
-  g_test_add_data_func("/core/parser/llk/many", GINT_TO_POINTER(PB_LLk), test_many);
-  g_test_add_data_func("/core/parser/llk/many1", GINT_TO_POINTER(PB_LLk), test_many1);
-  g_test_add_data_func("/core/parser/llk/optional", GINT_TO_POINTER(PB_LLk), test_optional);
-  g_test_add_data_func("/core/parser/llk/sepBy", GINT_TO_POINTER(PB_LLk), test_sepBy);
-  g_test_add_data_func("/core/parser/llk/sepBy1", GINT_TO_POINTER(PB_LLk), test_sepBy1);
-  g_test_add_data_func("/core/parser/llk/epsilon_p", GINT_TO_POINTER(PB_LLk), test_epsilon_p);
-  g_test_add_data_func("/core/parser/llk/attr_bool", GINT_TO_POINTER(PB_LLk), test_attr_bool);
-  g_test_add_data_func("/core/parser/llk/ignore", GINT_TO_POINTER(PB_LLk), test_ignore);
-  //g_test_add_data_func("/core/parser/llk/leftrec", GINT_TO_POINTER(PB_LLk), test_leftrec);
-  g_test_add_data_func("/core/parser/llk/rightrec", GINT_TO_POINTER(PB_LLk), test_rightrec);
-
-  g_test_add_data_func("/core/parser/regex/token", GINT_TO_POINTER(PB_REGULAR), test_token);
-  g_test_add_data_func("/core/parser/regex/ch", GINT_TO_POINTER(PB_REGULAR), test_ch);
-  g_test_add_data_func("/core/parser/regex/ch_range", GINT_TO_POINTER(PB_REGULAR), test_ch_range);
-  g_test_add_data_func("/core/parser/regex/int64", GINT_TO_POINTER(PB_REGULAR), test_int64);
-  g_test_add_data_func("/core/parser/regex/int32", GINT_TO_POINTER(PB_REGULAR), test_int32);
-  g_test_add_data_func("/core/parser/regex/int16", GINT_TO_POINTER(PB_REGULAR), test_int16);
-  g_test_add_data_func("/core/parser/regex/int8", GINT_TO_POINTER(PB_REGULAR), test_int8);
-  g_test_add_data_func("/core/parser/regex/uint64", GINT_TO_POINTER(PB_REGULAR), test_uint64);
-  g_test_add_data_func("/core/parser/regex/uint32", GINT_TO_POINTER(PB_REGULAR), test_uint32);
-  g_test_add_data_func("/core/parser/regex/uint16", GINT_TO_POINTER(PB_REGULAR), test_uint16);
-  g_test_add_data_func("/core/parser/regex/uint8", GINT_TO_POINTER(PB_REGULAR), test_uint8);
-  g_test_add_data_func("/core/parser/regex/int_range", GINT_TO_POINTER(PB_REGULAR), test_int_range);
+  g_test_add_data_func("/core/c/parser/llk/whitespace", GINT_TO_POINTER(PB_LLk), test_whitespace);
+  g_test_add_data_func("/core/c/parser/llk/left", GINT_TO_POINTER(PB_LLk), test_left);
+  g_test_add_data_func("/core/c/parser/llk/right", GINT_TO_POINTER(PB_LLk), test_right);
+  g_test_add_data_func("/core/c/parser/llk/middle", GINT_TO_POINTER(PB_LLk), test_middle);
+  g_test_add_data_func("/core/c/parser/llk/action", GINT_TO_POINTER(PB_LLk), test_action);
+  g_test_add_data_func("/core/c/parser/llk/in", GINT_TO_POINTER(PB_LLk), test_in);
+  g_test_add_data_func("/core/c/parser/llk/not_in", GINT_TO_POINTER(PB_LLk), test_not_in);
+  g_test_add_data_func("/core/c/parser/llk/end_p", GINT_TO_POINTER(PB_LLk), test_end_p);
+  g_test_add_data_func("/core/c/parser/llk/nothing_p", GINT_TO_POINTER(PB_LLk), test_nothing_p);
+  g_test_add_data_func("/core/c/parser/llk/sequence", GINT_TO_POINTER(PB_LLk), test_sequence);
+  g_test_add_data_func("/core/c/parser/llk/choice", GINT_TO_POINTER(PB_LLk), test_choice);
+  g_test_add_data_func("/core/c/parser/llk/many", GINT_TO_POINTER(PB_LLk), test_many);
+  g_test_add_data_func("/core/c/parser/llk/many1", GINT_TO_POINTER(PB_LLk), test_many1);
+  g_test_add_data_func("/core/c/parser/llk/optional", GINT_TO_POINTER(PB_LLk), test_optional);
+  g_test_add_data_func("/core/c/parser/llk/sepBy", GINT_TO_POINTER(PB_LLk), test_sepBy);
+  g_test_add_data_func("/core/c/parser/llk/sepBy1", GINT_TO_POINTER(PB_LLk), test_sepBy1);
+  g_test_add_data_func("/core/c/parser/llk/epsilon_p", GINT_TO_POINTER(PB_LLk), test_epsilon_p);
+  g_test_add_data_func("/core/c/parser/llk/attr_bool", GINT_TO_POINTER(PB_LLk), test_attr_bool);
+  g_test_add_data_func("/core/c/parser/llk/ignore", GINT_TO_POINTER(PB_LLk), test_ignore);
+  //g_test_add_data_func("/core/c/parser/llk/leftrec", GINT_TO_POINTER(PB_LLk), test_leftrec);
+  g_test_add_data_func("/core/c/parser/llk/rightrec", GINT_TO_POINTER(PB_LLk), test_rightrec);
+
+  g_test_add_data_func("/core/c/parser/regex/token", GINT_TO_POINTER(PB_REGULAR), test_token);
+  g_test_add_data_func("/core/c/parser/regex/ch", GINT_TO_POINTER(PB_REGULAR), test_ch);
+  g_test_add_data_func("/core/c/parser/regex/ch_range", GINT_TO_POINTER(PB_REGULAR), test_ch_range);
+  g_test_add_data_func("/core/c/parser/regex/int64", GINT_TO_POINTER(PB_REGULAR), test_int64);
+  g_test_add_data_func("/core/c/parser/regex/int32", GINT_TO_POINTER(PB_REGULAR), test_int32);
+  g_test_add_data_func("/core/c/parser/regex/int16", GINT_TO_POINTER(PB_REGULAR), test_int16);
+  g_test_add_data_func("/core/c/parser/regex/int8", GINT_TO_POINTER(PB_REGULAR), test_int8);
+  g_test_add_data_func("/core/c/parser/regex/uint64", GINT_TO_POINTER(PB_REGULAR), test_uint64);
+  g_test_add_data_func("/core/c/parser/regex/uint32", GINT_TO_POINTER(PB_REGULAR), test_uint32);
+  g_test_add_data_func("/core/c/parser/regex/uint16", GINT_TO_POINTER(PB_REGULAR), test_uint16);
+  g_test_add_data_func("/core/c/parser/regex/uint8", GINT_TO_POINTER(PB_REGULAR), test_uint8);
+  g_test_add_data_func("/core/c/parser/regex/int_range", GINT_TO_POINTER(PB_REGULAR), test_int_range);
 #if 0
-  g_test_add_data_func("/core/parser/regex/float64", GINT_TO_POINTER(PB_REGULAR), test_float64);
-  g_test_add_data_func("/core/parser/regex/float32", GINT_TO_POINTER(PB_REGULAR), test_float32);
+  g_test_add_data_func("/core/c/parser/regex/float64", GINT_TO_POINTER(PB_REGULAR), test_float64);
+  g_test_add_data_func("/core/c/parser/regex/float32", GINT_TO_POINTER(PB_REGULAR), test_float32);
 #endif
-  g_test_add_data_func("/core/parser/regex/whitespace", GINT_TO_POINTER(PB_REGULAR), test_whitespace);
-  g_test_add_data_func("/core/parser/regex/left", GINT_TO_POINTER(PB_REGULAR), test_left);
-  g_test_add_data_func("/core/parser/regex/right", GINT_TO_POINTER(PB_REGULAR), test_right);
-  g_test_add_data_func("/core/parser/regex/middle", GINT_TO_POINTER(PB_REGULAR), test_middle);
-  g_test_add_data_func("/core/parser/regex/action", GINT_TO_POINTER(PB_REGULAR), test_action);
-  g_test_add_data_func("/core/parser/regex/in", GINT_TO_POINTER(PB_REGULAR), test_in);
-  g_test_add_data_func("/core/parser/regex/not_in", GINT_TO_POINTER(PB_REGULAR), test_not_in);
-  g_test_add_data_func("/core/parser/regex/end_p", GINT_TO_POINTER(PB_REGULAR), test_end_p);
-  g_test_add_data_func("/core/parser/regex/nothing_p", GINT_TO_POINTER(PB_REGULAR), test_nothing_p);
-  g_test_add_data_func("/core/parser/regex/sequence", GINT_TO_POINTER(PB_REGULAR), test_sequence);
-  g_test_add_data_func("/core/parser/regex/choice", GINT_TO_POINTER(PB_REGULAR), test_choice);
-  g_test_add_data_func("/core/parser/regex/many", GINT_TO_POINTER(PB_REGULAR), test_many);
-  g_test_add_data_func("/core/parser/regex/many1", GINT_TO_POINTER(PB_REGULAR), test_many1);
-  g_test_add_data_func("/core/parser/regex/repeat_n", GINT_TO_POINTER(PB_REGULAR), test_repeat_n);
-  g_test_add_data_func("/core/parser/regex/optional", GINT_TO_POINTER(PB_REGULAR), test_optional);
-  g_test_add_data_func("/core/parser/regex/sepBy", GINT_TO_POINTER(PB_REGULAR), test_sepBy);
-  g_test_add_data_func("/core/parser/regex/sepBy1", GINT_TO_POINTER(PB_REGULAR), test_sepBy1);
-  g_test_add_data_func("/core/parser/regex/epsilon_p", GINT_TO_POINTER(PB_REGULAR), test_epsilon_p);
-  g_test_add_data_func("/core/parser/regex/attr_bool", GINT_TO_POINTER(PB_REGULAR), test_attr_bool);
-  g_test_add_data_func("/core/parser/regex/ignore", GINT_TO_POINTER(PB_REGULAR), test_ignore);
-
-  g_test_add_data_func("/core/parser/lalr/token", GINT_TO_POINTER(PB_LALR), test_token);
-  g_test_add_data_func("/core/parser/lalr/ch", GINT_TO_POINTER(PB_LALR), test_ch);
-  g_test_add_data_func("/core/parser/lalr/ch_range", GINT_TO_POINTER(PB_LALR), test_ch_range);
-  g_test_add_data_func("/core/parser/lalr/int64", GINT_TO_POINTER(PB_LALR), test_int64);
-  g_test_add_data_func("/core/parser/lalr/int32", GINT_TO_POINTER(PB_LALR), test_int32);
-  g_test_add_data_func("/core/parser/lalr/int16", GINT_TO_POINTER(PB_LALR), test_int16);
-  g_test_add_data_func("/core/parser/lalr/int8", GINT_TO_POINTER(PB_LALR), test_int8);
-  g_test_add_data_func("/core/parser/lalr/uint64", GINT_TO_POINTER(PB_LALR), test_uint64);
-  g_test_add_data_func("/core/parser/lalr/uint32", GINT_TO_POINTER(PB_LALR), test_uint32);
-  g_test_add_data_func("/core/parser/lalr/uint16", GINT_TO_POINTER(PB_LALR), test_uint16);
-  g_test_add_data_func("/core/parser/lalr/uint8", GINT_TO_POINTER(PB_LALR), test_uint8);
-  g_test_add_data_func("/core/parser/lalr/int_range", GINT_TO_POINTER(PB_LALR), test_int_range);
+  g_test_add_data_func("/core/c/parser/regex/whitespace", GINT_TO_POINTER(PB_REGULAR), test_whitespace);
+  g_test_add_data_func("/core/c/parser/regex/left", GINT_TO_POINTER(PB_REGULAR), test_left);
+  g_test_add_data_func("/core/c/parser/regex/right", GINT_TO_POINTER(PB_REGULAR), test_right);
+  g_test_add_data_func("/core/c/parser/regex/middle", GINT_TO_POINTER(PB_REGULAR), test_middle);
+  g_test_add_data_func("/core/c/parser/regex/action", GINT_TO_POINTER(PB_REGULAR), test_action);
+  g_test_add_data_func("/core/c/parser/regex/in", GINT_TO_POINTER(PB_REGULAR), test_in);
+  g_test_add_data_func("/core/c/parser/regex/not_in", GINT_TO_POINTER(PB_REGULAR), test_not_in);
+  g_test_add_data_func("/core/c/parser/regex/end_p", GINT_TO_POINTER(PB_REGULAR), test_end_p);
+  g_test_add_data_func("/core/c/parser/regex/nothing_p", GINT_TO_POINTER(PB_REGULAR), test_nothing_p);
+  g_test_add_data_func("/core/c/parser/regex/sequence", GINT_TO_POINTER(PB_REGULAR), test_sequence);
+  g_test_add_data_func("/core/c/parser/regex/choice", GINT_TO_POINTER(PB_REGULAR), test_choice);
+  g_test_add_data_func("/core/c/parser/regex/many", GINT_TO_POINTER(PB_REGULAR), test_many);
+  g_test_add_data_func("/core/c/parser/regex/many1", GINT_TO_POINTER(PB_REGULAR), test_many1);
+  g_test_add_data_func("/core/c/parser/regex/repeat_n", GINT_TO_POINTER(PB_REGULAR), test_repeat_n);
+  g_test_add_data_func("/core/c/parser/regex/optional", GINT_TO_POINTER(PB_REGULAR), test_optional);
+  g_test_add_data_func("/core/c/parser/regex/sepBy", GINT_TO_POINTER(PB_REGULAR), test_sepBy);
+  g_test_add_data_func("/core/c/parser/regex/sepBy1", GINT_TO_POINTER(PB_REGULAR), test_sepBy1);
+  g_test_add_data_func("/core/c/parser/regex/epsilon_p", GINT_TO_POINTER(PB_REGULAR), test_epsilon_p);
+  g_test_add_data_func("/core/c/parser/regex/attr_bool", GINT_TO_POINTER(PB_REGULAR), test_attr_bool);
+  g_test_add_data_func("/core/c/parser/regex/ignore", GINT_TO_POINTER(PB_REGULAR), test_ignore);
+
+  g_test_add_data_func("/core/c/parser/lalr/token", GINT_TO_POINTER(PB_LALR), test_token);
+  g_test_add_data_func("/core/c/parser/lalr/ch", GINT_TO_POINTER(PB_LALR), test_ch);
+  g_test_add_data_func("/core/c/parser/lalr/ch_range", GINT_TO_POINTER(PB_LALR), test_ch_range);
+  g_test_add_data_func("/core/c/parser/lalr/int64", GINT_TO_POINTER(PB_LALR), test_int64);
+  g_test_add_data_func("/core/c/parser/lalr/int32", GINT_TO_POINTER(PB_LALR), test_int32);
+  g_test_add_data_func("/core/c/parser/lalr/int16", GINT_TO_POINTER(PB_LALR), test_int16);
+  g_test_add_data_func("/core/c/parser/lalr/int8", GINT_TO_POINTER(PB_LALR), test_int8);
+  g_test_add_data_func("/core/c/parser/lalr/uint64", GINT_TO_POINTER(PB_LALR), test_uint64);
+  g_test_add_data_func("/core/c/parser/lalr/uint32", GINT_TO_POINTER(PB_LALR), test_uint32);
+  g_test_add_data_func("/core/c/parser/lalr/uint16", GINT_TO_POINTER(PB_LALR), test_uint16);
+  g_test_add_data_func("/core/c/parser/lalr/uint8", GINT_TO_POINTER(PB_LALR), test_uint8);
+  g_test_add_data_func("/core/c/parser/lalr/int_range", GINT_TO_POINTER(PB_LALR), test_int_range);
 #if 0
-  g_test_add_data_func("/core/parser/lalr/float64", GINT_TO_POINTER(PB_LALR), test_float64);
-  g_test_add_data_func("/core/parser/lalr/float32", GINT_TO_POINTER(PB_LALR), test_float32);
+  g_test_add_data_func("/core/c/parser/lalr/float64", GINT_TO_POINTER(PB_LALR), test_float64);
+  g_test_add_data_func("/core/c/parser/lalr/float32", GINT_TO_POINTER(PB_LALR), test_float32);
 #endif
-  g_test_add_data_func("/core/parser/lalr/whitespace", GINT_TO_POINTER(PB_LALR), test_whitespace);
-  g_test_add_data_func("/core/parser/lalr/left", GINT_TO_POINTER(PB_LALR), test_left);
-  g_test_add_data_func("/core/parser/lalr/right", GINT_TO_POINTER(PB_LALR), test_right);
-  g_test_add_data_func("/core/parser/lalr/middle", GINT_TO_POINTER(PB_LALR), test_middle);
-  g_test_add_data_func("/core/parser/lalr/action", GINT_TO_POINTER(PB_LALR), test_action);
-  g_test_add_data_func("/core/parser/lalr/in", GINT_TO_POINTER(PB_LALR), test_in);
-  g_test_add_data_func("/core/parser/lalr/not_in", GINT_TO_POINTER(PB_LALR), test_not_in);
-  g_test_add_data_func("/core/parser/lalr/end_p", GINT_TO_POINTER(PB_LALR), test_end_p);
-  g_test_add_data_func("/core/parser/lalr/nothing_p", GINT_TO_POINTER(PB_LALR), test_nothing_p);
-  g_test_add_data_func("/core/parser/lalr/sequence", GINT_TO_POINTER(PB_LALR), test_sequence);
-  g_test_add_data_func("/core/parser/lalr/choice", GINT_TO_POINTER(PB_LALR), test_choice);
-  g_test_add_data_func("/core/parser/lalr/many", GINT_TO_POINTER(PB_LALR), test_many);
-  g_test_add_data_func("/core/parser/lalr/many1", GINT_TO_POINTER(PB_LALR), test_many1);
-  g_test_add_data_func("/core/parser/lalr/optional", GINT_TO_POINTER(PB_LALR), test_optional);
-  g_test_add_data_func("/core/parser/lalr/sepBy", GINT_TO_POINTER(PB_LALR), test_sepBy);
-  g_test_add_data_func("/core/parser/lalr/sepBy1", GINT_TO_POINTER(PB_LALR), test_sepBy1);
-  g_test_add_data_func("/core/parser/lalr/epsilon_p", GINT_TO_POINTER(PB_LALR), test_epsilon_p);
-  g_test_add_data_func("/core/parser/lalr/attr_bool", GINT_TO_POINTER(PB_LALR), test_attr_bool);
-  g_test_add_data_func("/core/parser/lalr/ignore", GINT_TO_POINTER(PB_LALR), test_ignore);
-  g_test_add_data_func("/core/parser/lalr/leftrec", GINT_TO_POINTER(PB_LALR), test_leftrec);
-  g_test_add_data_func("/core/parser/lalr/rightrec", GINT_TO_POINTER(PB_LALR), test_rightrec);
-
-  g_test_add_data_func("/core/parser/glr/token", GINT_TO_POINTER(PB_GLR), test_token);
-  g_test_add_data_func("/core/parser/glr/ch", GINT_TO_POINTER(PB_GLR), test_ch);
-  g_test_add_data_func("/core/parser/glr/ch_range", GINT_TO_POINTER(PB_GLR), test_ch_range);
-  g_test_add_data_func("/core/parser/glr/int64", GINT_TO_POINTER(PB_GLR), test_int64);
-  g_test_add_data_func("/core/parser/glr/int32", GINT_TO_POINTER(PB_GLR), test_int32);
-  g_test_add_data_func("/core/parser/glr/int16", GINT_TO_POINTER(PB_GLR), test_int16);
-  g_test_add_data_func("/core/parser/glr/int8", GINT_TO_POINTER(PB_GLR), test_int8);
-  g_test_add_data_func("/core/parser/glr/uint64", GINT_TO_POINTER(PB_GLR), test_uint64);
-  g_test_add_data_func("/core/parser/glr/uint32", GINT_TO_POINTER(PB_GLR), test_uint32);
-  g_test_add_data_func("/core/parser/glr/uint16", GINT_TO_POINTER(PB_GLR), test_uint16);
-  g_test_add_data_func("/core/parser/glr/uint8", GINT_TO_POINTER(PB_GLR), test_uint8);
-  g_test_add_data_func("/core/parser/glr/int_range", GINT_TO_POINTER(PB_GLR), test_int_range);
+  g_test_add_data_func("/core/c/parser/lalr/whitespace", GINT_TO_POINTER(PB_LALR), test_whitespace);
+  g_test_add_data_func("/core/c/parser/lalr/left", GINT_TO_POINTER(PB_LALR), test_left);
+  g_test_add_data_func("/core/c/parser/lalr/right", GINT_TO_POINTER(PB_LALR), test_right);
+  g_test_add_data_func("/core/c/parser/lalr/middle", GINT_TO_POINTER(PB_LALR), test_middle);
+  g_test_add_data_func("/core/c/parser/lalr/action", GINT_TO_POINTER(PB_LALR), test_action);
+  g_test_add_data_func("/core/c/parser/lalr/in", GINT_TO_POINTER(PB_LALR), test_in);
+  g_test_add_data_func("/core/c/parser/lalr/not_in", GINT_TO_POINTER(PB_LALR), test_not_in);
+  g_test_add_data_func("/core/c/parser/lalr/end_p", GINT_TO_POINTER(PB_LALR), test_end_p);
+  g_test_add_data_func("/core/c/parser/lalr/nothing_p", GINT_TO_POINTER(PB_LALR), test_nothing_p);
+  g_test_add_data_func("/core/c/parser/lalr/sequence", GINT_TO_POINTER(PB_LALR), test_sequence);
+  g_test_add_data_func("/core/c/parser/lalr/choice", GINT_TO_POINTER(PB_LALR), test_choice);
+  g_test_add_data_func("/core/c/parser/lalr/many", GINT_TO_POINTER(PB_LALR), test_many);
+  g_test_add_data_func("/core/c/parser/lalr/many1", GINT_TO_POINTER(PB_LALR), test_many1);
+  g_test_add_data_func("/core/c/parser/lalr/optional", GINT_TO_POINTER(PB_LALR), test_optional);
+  g_test_add_data_func("/core/c/parser/lalr/sepBy", GINT_TO_POINTER(PB_LALR), test_sepBy);
+  g_test_add_data_func("/core/c/parser/lalr/sepBy1", GINT_TO_POINTER(PB_LALR), test_sepBy1);
+  g_test_add_data_func("/core/c/parser/lalr/epsilon_p", GINT_TO_POINTER(PB_LALR), test_epsilon_p);
+  g_test_add_data_func("/core/c/parser/lalr/attr_bool", GINT_TO_POINTER(PB_LALR), test_attr_bool);
+  g_test_add_data_func("/core/c/parser/lalr/ignore", GINT_TO_POINTER(PB_LALR), test_ignore);
+  g_test_add_data_func("/core/c/parser/lalr/leftrec", GINT_TO_POINTER(PB_LALR), test_leftrec);
+  g_test_add_data_func("/core/c/parser/lalr/rightrec", GINT_TO_POINTER(PB_LALR), test_rightrec);
+
+  g_test_add_data_func("/core/c/parser/glr/token", GINT_TO_POINTER(PB_GLR), test_token);
+  g_test_add_data_func("/core/c/parser/glr/ch", GINT_TO_POINTER(PB_GLR), test_ch);
+  g_test_add_data_func("/core/c/parser/glr/ch_range", GINT_TO_POINTER(PB_GLR), test_ch_range);
+  g_test_add_data_func("/core/c/parser/glr/int64", GINT_TO_POINTER(PB_GLR), test_int64);
+  g_test_add_data_func("/core/c/parser/glr/int32", GINT_TO_POINTER(PB_GLR), test_int32);
+  g_test_add_data_func("/core/c/parser/glr/int16", GINT_TO_POINTER(PB_GLR), test_int16);
+  g_test_add_data_func("/core/c/parser/glr/int8", GINT_TO_POINTER(PB_GLR), test_int8);
+  g_test_add_data_func("/core/c/parser/glr/uint64", GINT_TO_POINTER(PB_GLR), test_uint64);
+  g_test_add_data_func("/core/c/parser/glr/uint32", GINT_TO_POINTER(PB_GLR), test_uint32);
+  g_test_add_data_func("/core/c/parser/glr/uint16", GINT_TO_POINTER(PB_GLR), test_uint16);
+  g_test_add_data_func("/core/c/parser/glr/uint8", GINT_TO_POINTER(PB_GLR), test_uint8);
+  g_test_add_data_func("/core/c/parser/glr/int_range", GINT_TO_POINTER(PB_GLR), test_int_range);
 #if 0
-  g_test_add_data_func("/core/parser/glr/float64", GINT_TO_POINTER(PB_GLR), test_float64);
-  g_test_add_data_func("/core/parser/glr/float32", GINT_TO_POINTER(PB_GLR), test_float32);
+  g_test_add_data_func("/core/c/parser/glr/float64", GINT_TO_POINTER(PB_GLR), test_float64);
+  g_test_add_data_func("/core/c/parser/glr/float32", GINT_TO_POINTER(PB_GLR), test_float32);
 #endif
-  g_test_add_data_func("/core/parser/glr/whitespace", GINT_TO_POINTER(PB_GLR), test_whitespace);
-  g_test_add_data_func("/core/parser/glr/left", GINT_TO_POINTER(PB_GLR), test_left);
-  g_test_add_data_func("/core/parser/glr/right", GINT_TO_POINTER(PB_GLR), test_right);
-  g_test_add_data_func("/core/parser/glr/middle", GINT_TO_POINTER(PB_GLR), test_middle);
-  g_test_add_data_func("/core/parser/glr/action", GINT_TO_POINTER(PB_GLR), test_action);
-  g_test_add_data_func("/core/parser/glr/in", GINT_TO_POINTER(PB_GLR), test_in);
-  g_test_add_data_func("/core/parser/glr/not_in", GINT_TO_POINTER(PB_GLR), test_not_in);
-  g_test_add_data_func("/core/parser/glr/end_p", GINT_TO_POINTER(PB_GLR), test_end_p);
-  g_test_add_data_func("/core/parser/glr/nothing_p", GINT_TO_POINTER(PB_GLR), test_nothing_p);
-  g_test_add_data_func("/core/parser/glr/sequence", GINT_TO_POINTER(PB_GLR), test_sequence);
-  g_test_add_data_func("/core/parser/glr/choice", GINT_TO_POINTER(PB_GLR), test_choice);
-  g_test_add_data_func("/core/parser/glr/many", GINT_TO_POINTER(PB_GLR), test_many);
-  g_test_add_data_func("/core/parser/glr/many1", GINT_TO_POINTER(PB_GLR), test_many1);
-  g_test_add_data_func("/core/parser/glr/optional", GINT_TO_POINTER(PB_GLR), test_optional);
-  g_test_add_data_func("/core/parser/glr/sepBy", GINT_TO_POINTER(PB_GLR), test_sepBy);
-  g_test_add_data_func("/core/parser/glr/sepBy1", GINT_TO_POINTER(PB_GLR), test_sepBy1);
-  g_test_add_data_func("/core/parser/glr/epsilon_p", GINT_TO_POINTER(PB_GLR), test_epsilon_p);
-  g_test_add_data_func("/core/parser/glr/attr_bool", GINT_TO_POINTER(PB_GLR), test_attr_bool);
-  g_test_add_data_func("/core/parser/glr/ignore", GINT_TO_POINTER(PB_GLR), test_ignore);
-  g_test_add_data_func("/core/parser/glr/leftrec", GINT_TO_POINTER(PB_GLR), test_leftrec);
-  g_test_add_data_func("/core/parser/glr/rightrec", GINT_TO_POINTER(PB_GLR), test_rightrec);
-  g_test_add_data_func("/core/parser/glr/ambiguous", GINT_TO_POINTER(PB_GLR), test_ambiguous);
+  g_test_add_data_func("/core/c/parser/glr/whitespace", GINT_TO_POINTER(PB_GLR), test_whitespace);
+  g_test_add_data_func("/core/c/parser/glr/left", GINT_TO_POINTER(PB_GLR), test_left);
+  g_test_add_data_func("/core/c/parser/glr/right", GINT_TO_POINTER(PB_GLR), test_right);
+  g_test_add_data_func("/core/c/parser/glr/middle", GINT_TO_POINTER(PB_GLR), test_middle);
+  g_test_add_data_func("/core/c/parser/glr/action", GINT_TO_POINTER(PB_GLR), test_action);
+  g_test_add_data_func("/core/c/parser/glr/in", GINT_TO_POINTER(PB_GLR), test_in);
+  g_test_add_data_func("/core/c/parser/glr/not_in", GINT_TO_POINTER(PB_GLR), test_not_in);
+  g_test_add_data_func("/core/c/parser/glr/end_p", GINT_TO_POINTER(PB_GLR), test_end_p);
+  g_test_add_data_func("/core/c/parser/glr/nothing_p", GINT_TO_POINTER(PB_GLR), test_nothing_p);
+  g_test_add_data_func("/core/c/parser/glr/sequence", GINT_TO_POINTER(PB_GLR), test_sequence);
+  g_test_add_data_func("/core/c/parser/glr/choice", GINT_TO_POINTER(PB_GLR), test_choice);
+  g_test_add_data_func("/core/c/parser/glr/many", GINT_TO_POINTER(PB_GLR), test_many);
+  g_test_add_data_func("/core/c/parser/glr/many1", GINT_TO_POINTER(PB_GLR), test_many1);
+  g_test_add_data_func("/core/c/parser/glr/optional", GINT_TO_POINTER(PB_GLR), test_optional);
+  g_test_add_data_func("/core/c/parser/glr/sepBy", GINT_TO_POINTER(PB_GLR), test_sepBy);
+  g_test_add_data_func("/core/c/parser/glr/sepBy1", GINT_TO_POINTER(PB_GLR), test_sepBy1);
+  g_test_add_data_func("/core/c/parser/glr/epsilon_p", GINT_TO_POINTER(PB_GLR), test_epsilon_p);
+  g_test_add_data_func("/core/c/parser/glr/attr_bool", GINT_TO_POINTER(PB_GLR), test_attr_bool);
+  g_test_add_data_func("/core/c/parser/glr/ignore", GINT_TO_POINTER(PB_GLR), test_ignore);
+  g_test_add_data_func("/core/c/parser/glr/leftrec", GINT_TO_POINTER(PB_GLR), test_leftrec);
+  g_test_add_data_func("/core/c/parser/glr/rightrec", GINT_TO_POINTER(PB_GLR), test_rightrec);
+  g_test_add_data_func("/core/c/parser/glr/ambiguous", GINT_TO_POINTER(PB_GLR), test_ambiguous);
 }
diff --git a/src/test_suite.c b/src/test_suite.c
index e065f138ece71d5b09c4aa0e1060a2e944f1d283..9191f93c0c77de747c0ea05e9b6c06b9ff7ec612 100644
--- a/src/test_suite.c
+++ b/src/test_suite.c
@@ -25,6 +25,9 @@ extern void register_parser_tests();
 extern void register_grammar_tests();
 extern void register_misc_tests();
 extern void register_benchmark_tests();
+#ifdef __cplusplus
+extern void register_cxx_tests();
+#endif
 
 int main(int argc, char** argv) {
   g_test_init(&argc, &argv, NULL);
@@ -36,6 +39,9 @@ int main(int argc, char** argv) {
   register_grammar_tests();
   register_misc_tests();
   register_benchmark_tests();
+  #ifdef __cplusplus
+  register_cxx_tests();
+  #endif
 
   g_test_run();
 }
diff --git a/src/test_suite.h b/src/test_suite.h
index fc008e7fb96b6524b6298f6d27e7b45e4c7c5b3a..76c6d78020ccaaf2b3157c749d6314e32e88dd1b 100644
--- a/src/test_suite.h
+++ b/src/test_suite.h
@@ -19,6 +19,16 @@
 #define HAMMER_TEST_SUITE__H
 #include <stdlib.h>
 
+#ifdef __cplusplus
+extern "C" {
+#include <string>
+#include <boost/variant.hpp>
+#endif
+
+#ifndef __cplusplus
+typedef int bool;
+#endif
+
 // Equivalent to g_assert_*, but not using g_assert...
 #define g_check_inttype(fmt, typ, n1, op, n2) do {				\
     typ _n1 = (n1);							\
@@ -52,6 +62,19 @@
     }							\
   } while(0)
 
+#ifdef __cplusplus
+#define g_check_string_cxx(n1, op, n2) do {		\
+    std::string _n1 = (n1);				\
+    std::string _n2 = (n2);				\
+    if (!(_n1.compare(_n2) op 0)) {			\
+      g_test_message("Check failed: (%s) (%s %s %s)",	\
+		     #n1 " " #op " " #n2,		\
+		     _n1.c_str(), #op, _n2.c_str());	\
+      g_test_fail();					\
+    }							\
+  } while(0)
+#endif
+
 #define g_check_regular(lang) do {			\
     if (!lang->isValidRegular(lang->env)) {		\
       g_test_message("Language is not regular");	\
@@ -95,6 +118,21 @@
       g_test_fail();							\
     }									\
   } while(0)
+ 
+#ifdef __cplusplus
+#define g_check_parse_failed_cxx(parser, backend, input) do {	\
+    int skip = parser.compile((HParserBackend)backend, NULL);	\
+    if(skip != 0) {	\
+      g_test_message("Backend not applicable, skipping test");	\
+      break;	\
+    }	\
+    parser::result_type result = parser.parse(input);		\
+    if (NULL != result) {						\
+      g_test_message("Check failed: shouldn't have succeeded, but did"); \
+      g_test_fail();							\
+    }									\
+  } while(0)
+#endif
 
 #define g_check_parse_ok(parser, backend, input, inp_len, result) do {	\
     int skip = h_compile((HParser *)(parser), (HParserBackend) backend, NULL); \
@@ -120,6 +158,34 @@
     }									\
   } while(0)
 
+#ifdef __cplusplus
+#define g_check_parse_ok_cxx(parser, backend, input, result) do {	\
+    int skip = parser.compile((HParserBackend)backend, NULL); \
+    if(skip) {	\
+        g_test_message("Backend not applicable, skipping test");	\
+        break;	\
+    }									\
+    parser::result_type res = parser.parse((std::string)input); \
+    if (!res) {								\
+	g_test_message("Parse failed on line %d", __LINE__);		\
+	g_test_fail();							\
+    } else {								\
+	std::string& cres = h_write_result_unamb(res);			\
+	g_check_string_cxx(cres, ==, (std::string)result);		\
+	/*
+	system_allocator.free(&system_allocator, cres);			\
+	HArenaStats stats;						\
+	h_allocator_stats(res->arena, &stats);				\
+	g_test_message("Parse used %zd bytes, wasted %zd bytes. "	\
+		       "Inefficiency: %5f%%",				\
+		       stats.used, stats.wasted,			\
+		       stats.wasted * 100. / (stats.used+stats.wasted)); \
+	h_delete_arena(res->arena);					\
+	*/ // FIXME might've made a memory leak there
+    }									\
+  } while(0)
+#endif
+
 #define g_check_hashtable_present(table, key) do {			\
     if(!h_hashtable_present(table, key)) {				\
       g_test_message("Check failed: key should have been in table, but wasn't"); \
@@ -197,6 +263,8 @@
 #define g_check_cmpfloat(n1, op, n2) g_check_inttype("%g", float, n1, op, n2)
 #define g_check_cmpdouble(n1, op, n2) g_check_inttype("%g", double, n1, op, n2)
 
-
+#ifdef __cplusplus
+}
+#endif
 
 #endif // #ifndef HAMMER_TEST_SUITE__H