]> granicus.if.org Git - re2c/commitdiff
Added tests for "--input custom".
authorUlya Trofimovich <skvadrik@gmail.com>
Sun, 18 Jan 2015 13:47:51 +0000 (13:47 +0000)
committerUlya Trofimovich <skvadrik@gmail.com>
Sun, 18 Jan 2015 13:47:51 +0000 (13:47 +0000)
This implied modifying runtests.sh, as it couldn't handle
test names of the form "basename.--long-switch.re":
it inserted '-' in front of all switches.

re2c/run_tests.sh.in
re2c/test/input_custom_default.--input(custom).c [new file with mode: 0644]
re2c/test/input_custom_default.--input(custom).re [new file with mode: 0644]
re2c/test/input_custom_fgetc.--input(custom).c [new file with mode: 0644]
re2c/test/input_custom_fgetc.--input(custom).re [new file with mode: 0644]
re2c/test/input_custom_istringstream.--input(custom).c [new file with mode: 0644]
re2c/test/input_custom_istringstream.--input(custom).re [new file with mode: 0644]
re2c/test/input_custom_mjson.--input(custom).c [new file with mode: 0644]
re2c/test/input_custom_mjson.--input(custom).re [new file with mode: 0644]

index 2ab4544f35f4e22d86dd72474e5d4657482f57fd..9b6ad50cce2488a6123be1f1223d979257b4432a 100644 (file)
@@ -39,7 +39,7 @@ tests="$@"
 fi;
 for x in $tests; do
        tstcnt=$(($tstcnt+1))
-       switches=`basename $x|sed -e 's/^[^.]*\.\(.*\)\.re$/-\1/g' -e 's/^[^-].*//g' -e 's/\([^ ]\)--/\1 --/g' -e 's/(\([^)]*\))/ \1/g'`
+       switches=`basename $x|sed -e 's/^[^.]*\.\(.*\)\.re$/-\1/g' -e 's/^[^-].*//g' -e 's/\([^ ]\)--/\1 --/g' -e 's/(\([^)]*\))/ \1/g' -e 's/- //g'`
        genname=`printf "%s" "$switches"|sed -e 's,--.*$,,g' -e 's,^.[^o]*$,,g' -e 's,^[^ot]*t.*o.*$,,g' -e 's,^-[^o]*o\(.*\),@builddir@/test/\1,g'`
        headers=`printf "%s" "$switches"|sed -e 's,--.*$,,g' -e 's,^.[^t]*$,,g' -e 's,^[^ot]*o.*t.*$,,g' -e 's,^-[^t]*t\(.*\),@builddir@/test/\1,g'`
        switches=`printf "%s" "$switches"|sed -e 's,^-\([^ot-]*[ot]\)\(.*\)$,-\1@builddir@/test/\2,g'`
diff --git a/re2c/test/input_custom_default.--input(custom).c b/re2c/test/input_custom_default.--input(custom).c
new file mode 100644 (file)
index 0000000..7e31b80
--- /dev/null
@@ -0,0 +1,165 @@
+/* Generated by re2c */
+#line 1 "input_custom_default.--input(custom).re"
+bool lex (const char * cursor, const char * const limit)
+{
+    const char * marker;
+    const char * ctxmarker;
+#   define YYCTYPE        char
+#   define YYPEEK()       *cursor
+#   define YYSKIP()       ++cursor
+#   define YYBACKUP()     marker = cursor
+#   define YYBACKUPCTX()  ctxmarker = cursor
+#   define YYRESTORE()    cursor = marker
+#   define YYRESTORECTX() cursor = ctxmarker
+#   define YYHAS(n)       limit - cursor < n
+#   define YYFILL(n)      {}
+    
+#line 18 "<stdout>"
+{
+       YYCTYPE yych;
+
+       if (YYHAS (13)) YYFILL(13);
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'i':       goto yy4;
+       default:        goto yy2;
+       }
+yy2:
+       YYSKIP ();
+yy3:
+#line 16 "input_custom_default.--input(custom).re"
+       { return false; }
+#line 33 "<stdout>"
+yy4:
+       YYSKIP ();
+       YYBACKUP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'n':       goto yy5;
+       default:        goto yy3;
+       }
+yy5:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 't':       goto yy7;
+       default:        goto yy6;
+       }
+yy6:
+       YYRESTORE ();
+       goto yy3;
+yy7:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case ' ':       goto yy8;
+       default:        goto yy6;
+       }
+yy8:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'b':       goto yy9;
+       default:        goto yy6;
+       }
+yy9:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'u':       goto yy10;
+       default:        goto yy6;
+       }
+yy10:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'f':       goto yy11;
+       default:        goto yy6;
+       }
+yy11:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'f':       goto yy12;
+       default:        goto yy6;
+       }
+yy12:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'e':       goto yy13;
+       default:        goto yy6;
+       }
+yy13:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'r':       goto yy14;
+       default:        goto yy6;
+       }
+yy14:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case ' ':       goto yy15;
+       default:        goto yy6;
+       }
+yy15:
+       YYBACKUPCTX ();
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case '[':       goto yy16;
+       default:        goto yy6;
+       }
+yy16:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy17;
+       default:        goto yy6;
+       }
+yy17:
+       YYSKIP ();
+       if (YYHAS (1)) YYFILL(1);
+       yych = YYPEEK ();
+       switch (yych) {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy17;
+       case ']':       goto yy19;
+       default:        goto yy6;
+       }
+yy19:
+       YYSKIP ();
+       YYRESTORECTX ();
+       YYSKIP ();
+#line 15 "input_custom_default.--input(custom).re"
+       { return true; }
+#line 156 "<stdout>"
+}
+#line 17 "input_custom_default.--input(custom).re"
+
+}
+
+int main ()
+{
+    char buffer [] = "int buffer [1024]";
+    return !lex (buffer, buffer + sizeof (buffer));
+}
diff --git a/re2c/test/input_custom_default.--input(custom).re b/re2c/test/input_custom_default.--input(custom).re
new file mode 100644 (file)
index 0000000..933d766
--- /dev/null
@@ -0,0 +1,24 @@
+bool lex (const char * cursor, const char * const limit)
+{
+    const char * marker;
+    const char * ctxmarker;
+#   define YYCTYPE        char
+#   define YYPEEK()       *cursor
+#   define YYSKIP()       ++cursor
+#   define YYBACKUP()     marker = cursor
+#   define YYBACKUPCTX()  ctxmarker = cursor
+#   define YYRESTORE()    cursor = marker
+#   define YYRESTORECTX() cursor = ctxmarker
+#   define YYHAS(n)       limit - cursor < n
+#   define YYFILL(n)      {}
+    /*!re2c
+        "int buffer " / "[" [0-9]+ "]" { return true; }
+        *                              { return false; }
+    */
+}
+
+int main ()
+{
+    char buffer [] = "int buffer [1024]";
+    return !lex (buffer, buffer + sizeof (buffer));
+}
diff --git a/re2c/test/input_custom_fgetc.--input(custom).c b/re2c/test/input_custom_fgetc.--input(custom).c
new file mode 100644 (file)
index 0000000..9e04391
--- /dev/null
@@ -0,0 +1,184 @@
+/* Generated by re2c */
+#line 1 "input_custom_fgetc.--input(custom).re"
+#include <stdio.h>
+
+char peek (FILE * f)
+{
+    char c = fgetc (f);
+    ungetc (c, f);
+    return c;
+}
+
+bool lex (FILE * f, const long limit)
+{
+    long marker;
+    long ctxmarker;
+#   define YYCTYPE        char
+#   define YYPEEK()       peek (f)
+#   define YYSKIP()       fgetc (f)
+#   define YYBACKUP()     marker = ftell (f)
+#   define YYBACKUPCTX()  ctxmarker = ftell (f)
+#   define YYRESTORE()    fseek (f, marker, SEEK_SET)
+#   define YYRESTORECTX() fseek (f, ctxmarker, SEEK_SET)
+#   define YYHAS(n)       limit - ftell (f) < n
+#   define YYFILL(n)      {}
+    
+#line 27 "<stdout>"
+{
+       YYCTYPE yych;
+
+       if (YYHAS (13)) YYFILL(13);
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'i':       goto yy4;
+       default:        goto yy2;
+       }
+yy2:
+       YYSKIP ();
+yy3:
+#line 25 "input_custom_fgetc.--input(custom).re"
+       { return false; }
+#line 42 "<stdout>"
+yy4:
+       YYSKIP ();
+       YYBACKUP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'n':       goto yy5;
+       default:        goto yy3;
+       }
+yy5:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 't':       goto yy7;
+       default:        goto yy6;
+       }
+yy6:
+       YYRESTORE ();
+       goto yy3;
+yy7:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case ' ':       goto yy8;
+       default:        goto yy6;
+       }
+yy8:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'b':       goto yy9;
+       default:        goto yy6;
+       }
+yy9:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'u':       goto yy10;
+       default:        goto yy6;
+       }
+yy10:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'f':       goto yy11;
+       default:        goto yy6;
+       }
+yy11:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'f':       goto yy12;
+       default:        goto yy6;
+       }
+yy12:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'e':       goto yy13;
+       default:        goto yy6;
+       }
+yy13:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'r':       goto yy14;
+       default:        goto yy6;
+       }
+yy14:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case ' ':       goto yy15;
+       default:        goto yy6;
+       }
+yy15:
+       YYBACKUPCTX ();
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case '[':       goto yy16;
+       default:        goto yy6;
+       }
+yy16:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy17;
+       default:        goto yy6;
+       }
+yy17:
+       YYSKIP ();
+       if (YYHAS (1)) YYFILL(1);
+       yych = YYPEEK ();
+       switch (yych) {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy17;
+       case ']':       goto yy19;
+       default:        goto yy6;
+       }
+yy19:
+       YYSKIP ();
+       YYRESTORECTX ();
+       YYSKIP ();
+#line 24 "input_custom_fgetc.--input(custom).re"
+       { return true; }
+#line 165 "<stdout>"
+}
+#line 26 "input_custom_fgetc.--input(custom).re"
+
+}
+
+int main ()
+{
+    const char buffer [] = "int buffer [1024]";
+    const char fn [] = "input.txt";
+
+    FILE * f = fopen (fn, "w");
+    fwrite (buffer, 1, sizeof (buffer), f);
+    fclose (f);
+
+    f = fopen (fn, "rb");
+    int result = !lex (f, sizeof (buffer));
+    fclose (f);
+
+    return result;
+}
diff --git a/re2c/test/input_custom_fgetc.--input(custom).re b/re2c/test/input_custom_fgetc.--input(custom).re
new file mode 100644 (file)
index 0000000..3116479
--- /dev/null
@@ -0,0 +1,43 @@
+#include <stdio.h>
+
+char peek (FILE * f)
+{
+    char c = fgetc (f);
+    ungetc (c, f);
+    return c;
+}
+
+bool lex (FILE * f, const long limit)
+{
+    long marker;
+    long ctxmarker;
+#   define YYCTYPE        char
+#   define YYPEEK()       peek (f)
+#   define YYSKIP()       fgetc (f)
+#   define YYBACKUP()     marker = ftell (f)
+#   define YYBACKUPCTX()  ctxmarker = ftell (f)
+#   define YYRESTORE()    fseek (f, marker, SEEK_SET)
+#   define YYRESTORECTX() fseek (f, ctxmarker, SEEK_SET)
+#   define YYHAS(n)       limit - ftell (f) < n
+#   define YYFILL(n)      {}
+    /*!re2c
+        "int buffer " / "[" [0-9]+ "]" { return true; }
+        *                              { return false; }
+    */
+}
+
+int main ()
+{
+    const char buffer [] = "int buffer [1024]";
+    const char fn [] = "input.txt";
+
+    FILE * f = fopen (fn, "w");
+    fwrite (buffer, 1, sizeof (buffer), f);
+    fclose (f);
+
+    f = fopen (fn, "rb");
+    int result = !lex (f, sizeof (buffer));
+    fclose (f);
+
+    return result;
+}
diff --git a/re2c/test/input_custom_istringstream.--input(custom).c b/re2c/test/input_custom_istringstream.--input(custom).c
new file mode 100644 (file)
index 0000000..d40a354
--- /dev/null
@@ -0,0 +1,168 @@
+/* Generated by re2c */
+#line 1 "input_custom_istringstream.--input(custom).re"
+#include <sstream>
+
+bool lex (std::istringstream & is, const std::streampos limit)
+{
+    std::streampos marker;
+    std::streampos ctxmarker;
+#   define YYCTYPE        char
+#   define YYPEEK()       is.peek ()
+#   define YYSKIP()       is.ignore ()
+#   define YYBACKUP()     marker = is.tellg ()
+#   define YYBACKUPCTX()  ctxmarker = is.tellg ()
+#   define YYRESTORE()    is.seekg (marker)
+#   define YYRESTORECTX() is.seekg (ctxmarker)
+#   define YYHAS(n)       limit - is.tellg () < n
+#   define YYFILL(n)      {}
+    
+#line 20 "<stdout>"
+{
+       YYCTYPE yych;
+
+       if (YYHAS (13)) YYFILL(13);
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'i':       goto yy4;
+       default:        goto yy2;
+       }
+yy2:
+       YYSKIP ();
+yy3:
+#line 18 "input_custom_istringstream.--input(custom).re"
+       { return false; }
+#line 35 "<stdout>"
+yy4:
+       YYSKIP ();
+       YYBACKUP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'n':       goto yy5;
+       default:        goto yy3;
+       }
+yy5:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 't':       goto yy7;
+       default:        goto yy6;
+       }
+yy6:
+       YYRESTORE ();
+       goto yy3;
+yy7:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case ' ':       goto yy8;
+       default:        goto yy6;
+       }
+yy8:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'b':       goto yy9;
+       default:        goto yy6;
+       }
+yy9:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'u':       goto yy10;
+       default:        goto yy6;
+       }
+yy10:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'f':       goto yy11;
+       default:        goto yy6;
+       }
+yy11:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'f':       goto yy12;
+       default:        goto yy6;
+       }
+yy12:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'e':       goto yy13;
+       default:        goto yy6;
+       }
+yy13:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case 'r':       goto yy14;
+       default:        goto yy6;
+       }
+yy14:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case ' ':       goto yy15;
+       default:        goto yy6;
+       }
+yy15:
+       YYBACKUPCTX ();
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case '[':       goto yy16;
+       default:        goto yy6;
+       }
+yy16:
+       YYSKIP ();
+       yych = YYPEEK ();
+       switch (yych) {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy17;
+       default:        goto yy6;
+       }
+yy17:
+       YYSKIP ();
+       if (YYHAS (1)) YYFILL(1);
+       yych = YYPEEK ();
+       switch (yych) {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':       goto yy17;
+       case ']':       goto yy19;
+       default:        goto yy6;
+       }
+yy19:
+       YYSKIP ();
+       YYRESTORECTX ();
+       YYSKIP ();
+#line 17 "input_custom_istringstream.--input(custom).re"
+       { return true; }
+#line 158 "<stdout>"
+}
+#line 19 "input_custom_istringstream.--input(custom).re"
+
+}
+
+int main ()
+{
+    const char buffer [] = "int buffer [1024]";
+    std::istringstream is (buffer);
+    return !lex (is, sizeof (buffer));
+}
diff --git a/re2c/test/input_custom_istringstream.--input(custom).re b/re2c/test/input_custom_istringstream.--input(custom).re
new file mode 100644 (file)
index 0000000..76197a2
--- /dev/null
@@ -0,0 +1,27 @@
+#include <sstream>
+
+bool lex (std::istringstream & is, const std::streampos limit)
+{
+    std::streampos marker;
+    std::streampos ctxmarker;
+#   define YYCTYPE        char
+#   define YYPEEK()       is.peek ()
+#   define YYSKIP()       is.ignore ()
+#   define YYBACKUP()     marker = is.tellg ()
+#   define YYBACKUPCTX()  ctxmarker = is.tellg ()
+#   define YYRESTORE()    is.seekg (marker)
+#   define YYRESTORECTX() is.seekg (ctxmarker)
+#   define YYHAS(n)       limit - is.tellg () < n
+#   define YYFILL(n)      {}
+    /*!re2c
+        "int buffer " / "[" [0-9]+ "]" { return true; }
+        *                              { return false; }
+    */
+}
+
+int main ()
+{
+    const char buffer [] = "int buffer [1024]";
+    std::istringstream is (buffer);
+    return !lex (is, sizeof (buffer));
+}
diff --git a/re2c/test/input_custom_mjson.--input(custom).c b/re2c/test/input_custom_mjson.--input(custom).c
new file mode 100644 (file)
index 0000000..3c23012
--- /dev/null
@@ -0,0 +1,2881 @@
+/* Generated by re2c */
+#line 1 "input_custom_mjson.--input(custom).re"
+#include <assert.h>
+#include <memory.h>
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+
+/** 
+ * mjson - modified json parser
+ * syntax changes:
+ *   - no {} needed around the whole file
+ *   - "=" is allowed instead of ":"
+ *   - quotes around the key are optional
+ *   - commas after values are optional 
+ *   - and c-style comments allowed
+ *
+ * intermediate storage is based on ideas from BJSON specification: http://bjson.org
+ *
+ * some code ideas are borrowed from another json parser: https://github.com/megous/sjson
+ */
+
+#ifndef __MJSON_H_INCLUDED__
+#define __MJSON_H_INCLUDED__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct _mjson_entry_t;
+
+typedef const struct _mjson_entry_t* mjson_element_t;
+
+enum mjson_element_id_t
+{
+    MJSON_ID_NULL           =  0,
+    MJSON_ID_FALSE          =  1,
+    MJSON_ID_EMPTY_STRING   =  2,
+    MJSON_ID_TRUE           =  3,
+
+    MJSON_ID_UINT32         =  4,
+    MJSON_ID_UINT64         =  5,
+
+    MJSON_ID_SINT32         =  6,
+    MJSON_ID_SINT64         =  7,
+
+    MJSON_ID_FLOAT32        =  8,
+    MJSON_ID_FLOAT64        =  9,
+
+    MJSON_ID_UTF8_KEY32     = 10,
+    MJSON_ID_UTF8_KEY64     = 11,
+
+    MJSON_ID_UTF8_STRING32  = 12,
+    MJSON_ID_UTF8_STRING64  = 13,
+
+    MJSON_ID_BINARY32       = 14,
+    MJSON_ID_BINARY64       = 15,
+
+    MJSON_ID_ARRAY32        = 16,
+    MJSON_ID_ARRAY64        = 17,
+
+    MJSON_ID_DICT32         = 18,
+    MJSON_ID_DICT64         = 19
+};
+
+int mjson_parse(const char *json_data, size_t json_data_size, void* storage_buf, size_t storage_buf_size, mjson_element_t* top_element);
+
+mjson_element_t   mjson_get_top_element(void* storage_buf, size_t storage_buf_size);
+
+mjson_element_t   mjson_get_element_first(mjson_element_t array);
+mjson_element_t   mjson_get_element_next (mjson_element_t array, mjson_element_t current_value);
+mjson_element_t   mjson_get_element      (mjson_element_t array, int index);
+
+mjson_element_t   mjson_get_member_first(mjson_element_t dictionary, mjson_element_t* value);
+mjson_element_t   mjson_get_member_next (mjson_element_t dictionary, mjson_element_t current_key, mjson_element_t* next_value);
+mjson_element_t   mjson_get_member      (mjson_element_t dictionary, const char* name);
+
+int mjson_get_type(mjson_element_t element);
+
+const char* mjson_get_string(mjson_element_t element, const char* fallback);
+int32_t     mjson_get_int   (mjson_element_t element, int32_t     fallback);
+float       mjson_get_float (mjson_element_t element, float       fallback);
+int         mjson_get_bool  (mjson_element_t element, int         fallback);
+int         mjson_is_null   (mjson_element_t element);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+enum mjson_token_t
+{
+    TOK_NONE,
+    TOK_IDENTIFIER,
+    TOK_NOESC_STRING,
+    TOK_STRING,
+    TOK_OCT_NUMBER,
+    TOK_HEX_NUMBER,
+    TOK_DEC_NUMBER,
+    TOK_FLOAT_NUMBER,
+    TOK_COMMA,
+    TOK_COLON,
+    TOK_EQUAL,
+    TOK_LEFT_BRACKET,
+    TOK_RIGHT_BRACKET,
+    TOK_LEFT_CURLY_BRACKET,
+    TOK_RIGHT_CURLY_BRACKET,
+    TOK_FALSE,
+    TOK_TRUE,
+    TOK_NULL,
+    TOK_WHITESPACE,
+    TOK_INVALID,
+    TOK_COUNT
+};
+
+struct _mjson_parser_t
+{
+    int token;
+    uint8_t* start;
+    uint8_t* next;
+    uint8_t* end;
+    uint8_t* bjson;
+    uint8_t* bjson_limit;
+};
+
+struct _mjson_entry_t
+{
+    uint32_t  id;
+    union
+    {
+        uint32_t val_u32;
+        int32_t  val_s32;
+        float    val_f32;
+    };
+};
+
+#define RETURN_VAL_IF_FAIL(cond, val) if (!(cond)) return (val)
+#define RETURN_IF_FAIL(cond) if (!(cond)) return
+#define MAX_UTF8_CHAR_LEN 6
+#define TRUE  1
+#define FALSE 0
+
+typedef struct _mjson_parser_t  mjson_parser_t;
+typedef struct _mjson_entry_t   mjson_entry_t;
+
+static void* parsectx_allocate_output(mjson_parser_t* ctx, ptrdiff_t size);
+
+static void parsectx_next_token    (mjson_parser_t* context);
+
+static int parse_value_list    (mjson_parser_t *context);
+static int parse_key_value_pair(mjson_parser_t *context, int stop_token);
+
+static mjson_element_t next_element(mjson_element_t element);
+
+int mjson_parse(const char *json_data, size_t json_data_size, void* storage_buf, size_t storage_buf_size, const mjson_entry_t** top_element)
+{
+    uint32_t* fourcc;
+    mjson_parser_t c = {
+        TOK_NONE, 0,
+        (uint8_t*)json_data,   (uint8_t*)json_data + json_data_size,
+        (uint8_t*)storage_buf, (uint8_t*)storage_buf + storage_buf_size
+    };
+    int stop_token = TOK_NONE;
+
+    *top_element = 0;
+
+    fourcc = (uint32_t*)parsectx_allocate_output(&c, (ptrdiff_t)sizeof(uint32_t));
+
+    if (!fourcc) return 0;
+
+    *fourcc = '23JB';
+
+    parsectx_next_token(&c);
+
+    if (c.token == TOK_LEFT_BRACKET)
+    {
+        parsectx_next_token(&c);
+        if (!parse_value_list(&c))
+            return 0;
+    }
+    else
+    {
+        if (c.token == TOK_LEFT_CURLY_BRACKET)
+        {
+            stop_token = TOK_RIGHT_CURLY_BRACKET;
+            parsectx_next_token(&c);
+        }
+
+        if (!parse_key_value_pair(&c, stop_token))
+            return 0;
+    }
+
+    if (c.token != TOK_NONE)
+        return 0;
+
+    *top_element = (mjson_entry_t*)(fourcc + 1);
+
+    return 1;
+}
+
+mjson_element_t mjson_get_top_element(void* storage_buf, size_t storage_buf_size)
+{
+    mjson_element_t top = (mjson_element_t)storage_buf;
+    
+    RETURN_VAL_IF_FAIL(top, NULL);
+    RETURN_VAL_IF_FAIL(top->id == MJSON_ID_DICT32 || top->id == MJSON_ID_ARRAY32, NULL);
+    RETURN_VAL_IF_FAIL(top->val_u32 <= storage_buf_size, NULL);
+    
+    return top;
+}
+
+mjson_element_t mjson_get_element_first(mjson_element_t array)
+{
+    RETURN_VAL_IF_FAIL(array, NULL);
+    RETURN_VAL_IF_FAIL(array->id == MJSON_ID_ARRAY32, NULL);
+    
+    return array + 1;
+}
+
+mjson_element_t mjson_get_element_next(mjson_element_t array, mjson_element_t current_value)
+{
+    mjson_element_t next = NULL;
+
+    RETURN_VAL_IF_FAIL(array, NULL);
+    RETURN_VAL_IF_FAIL(current_value, NULL);
+    RETURN_VAL_IF_FAIL(array->id == MJSON_ID_ARRAY32, NULL);
+    RETURN_VAL_IF_FAIL((uint8_t*)array + array->val_u32 > (uint8_t*)current_value, NULL);
+    
+    next = next_element(current_value);
+    
+    RETURN_VAL_IF_FAIL((uint8_t*)array + array->val_u32 > (uint8_t*)next, NULL);
+    
+    return next;
+}
+
+mjson_element_t mjson_get_element(mjson_element_t array, int index)
+{
+    mjson_element_t result;
+    
+    result = mjson_get_element_first(array);
+    while (result && index--)
+        result = mjson_get_element_next(array, result);
+    
+    return result;
+}
+
+mjson_element_t mjson_get_member_first(mjson_element_t dictionary, mjson_element_t* value)
+{
+    RETURN_VAL_IF_FAIL(dictionary, NULL);
+    RETURN_VAL_IF_FAIL(dictionary->id == MJSON_ID_DICT32, NULL);
+    RETURN_VAL_IF_FAIL((dictionary+1)->id == MJSON_ID_UTF8_KEY32, NULL);
+    
+    *value = next_element(dictionary+1);
+    
+    return dictionary + 1;
+}
+
+mjson_element_t mjson_get_member_next(mjson_element_t dictionary, mjson_element_t current_key, mjson_element_t* next_value)
+{
+    mjson_element_t next_key = NULL;
+
+    RETURN_VAL_IF_FAIL(dictionary, NULL);
+    RETURN_VAL_IF_FAIL(dictionary->id == MJSON_ID_DICT32, NULL);
+    RETURN_VAL_IF_FAIL(current_key, NULL);
+    RETURN_VAL_IF_FAIL((uint8_t*)dictionary + dictionary->val_u32 > (uint8_t*)current_key, NULL);
+    RETURN_VAL_IF_FAIL(current_key->id == MJSON_ID_UTF8_KEY32, NULL);
+    
+    next_key = next_element(current_key);
+    next_key = next_element(next_key);
+    
+    RETURN_VAL_IF_FAIL(next_key, NULL);
+    RETURN_VAL_IF_FAIL((uint8_t*)dictionary + dictionary->val_u32 > (uint8_t*)next_key, NULL);
+    RETURN_VAL_IF_FAIL(next_key->id == MJSON_ID_UTF8_KEY32, NULL);
+
+    *next_value = next_element(next_key);
+   
+    return next_key;    
+}
+
+mjson_element_t mjson_get_member(mjson_element_t dictionary, const char* name)
+{
+    mjson_element_t key, result;
+    
+    key = mjson_get_member_first(dictionary, &result);
+    while (key && strncmp(name, (char*)(key+1), key->val_u32) != 0)
+        result = mjson_get_member_next(dictionary, key, &result);
+    
+    return result;
+}
+
+int mjson_get_type(mjson_element_t element)
+{
+    RETURN_VAL_IF_FAIL(element, MJSON_ID_NULL);
+    
+    return element->id;
+}
+
+const char* mjson_get_string(mjson_element_t element, const char* fallback)
+{
+    RETURN_VAL_IF_FAIL(element, fallback);
+    RETURN_VAL_IF_FAIL(element->id == MJSON_ID_UTF8_STRING32 ||
+                       element->id == MJSON_ID_UTF8_KEY32,
+                       fallback);
+    
+    return (const char*)(element+1);
+}
+
+int32_t mjson_get_int(mjson_element_t element, int32_t fallback)
+{
+    RETURN_VAL_IF_FAIL(element, fallback);
+    RETURN_VAL_IF_FAIL(element->id == MJSON_ID_SINT32, fallback);
+    
+    return element->val_s32;
+}
+
+float mjson_get_float(mjson_element_t element, float fallback)
+{
+    RETURN_VAL_IF_FAIL(element, fallback);
+    RETURN_VAL_IF_FAIL(element->id == MJSON_ID_FLOAT32, fallback);
+    
+    return element->val_f32;
+}
+
+int mjson_get_bool(mjson_element_t element, int fallback)
+{
+    RETURN_VAL_IF_FAIL(element, fallback);
+    RETURN_VAL_IF_FAIL(element->id == MJSON_ID_TRUE || element->id == MJSON_ID_FALSE, fallback);
+    
+    return element->id == MJSON_ID_TRUE;
+}
+
+int mjson_is_null(mjson_element_t element)
+{
+    RETURN_VAL_IF_FAIL(element, TRUE);
+
+    return element->id == MJSON_ID_NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// API helpers
+/////////////////////////////////////////////////////////////////////////////
+
+static size_t element_size(mjson_element_t element)
+{
+    RETURN_VAL_IF_FAIL(element, 0);
+
+    switch(element->id)
+    {
+        case MJSON_ID_NULL:
+        case MJSON_ID_FALSE:
+        case MJSON_ID_EMPTY_STRING:
+        case MJSON_ID_TRUE:
+            return sizeof(uint32_t);
+
+        case MJSON_ID_UINT32:
+        case MJSON_ID_SINT32:
+        case MJSON_ID_FLOAT32:
+            return sizeof(mjson_entry_t);
+
+        case MJSON_ID_UTF8_KEY32:
+        case MJSON_ID_UTF8_STRING32:
+            return sizeof(mjson_entry_t) + ((element->val_u32 + 1 + 3) & (~3));
+
+        case MJSON_ID_BINARY32:
+        case MJSON_ID_ARRAY32:
+        case MJSON_ID_DICT32:
+            return sizeof(mjson_entry_t) + ((element->val_u32 + 3) & (~3));
+    };
+
+    return 0;
+}
+
+static mjson_element_t next_element(mjson_element_t element)
+{
+    size_t size;
+    
+    RETURN_VAL_IF_FAIL(element, 0);
+
+    size = element_size(element);
+    assert(size>0);
+    
+    return (mjson_element_t)((uint8_t*)element + size);
+}
+
+static void* parsectx_reserve_output(mjson_parser_t* ctx, ptrdiff_t size)
+{
+    return (ctx->bjson_limit - ctx->bjson < size) ? 0 : ctx->bjson;
+}
+
+static void parsectx_advance_output(mjson_parser_t* ctx, ptrdiff_t size)
+{
+    ctx->bjson += size;
+}
+
+static void* parsectx_allocate_output(mjson_parser_t* ctx, ptrdiff_t size)
+{
+    void* ptr;
+
+    if (ctx->bjson_limit - ctx->bjson < size)
+        return 0;
+
+    ptr = ctx->bjson;
+    ctx->bjson += size;
+
+    return ptr;
+}
+
+//TODO: what about 64 bit code????
+static void parsectx_align4_output(mjson_parser_t* ctx)
+{
+    ctx->bjson = (uint8_t*)(((ptrdiff_t)ctx->bjson + 3) & (~3));
+}
+
+static void unicode_cp_to_utf8(uint32_t uni_cp, uint8_t* utf8char/*[6]*/, size_t* charlen)
+{
+    uint32_t first, i;
+    
+    if (uni_cp < 0x80)
+    {
+        first   = 0;
+        *charlen = 1;
+    }
+    else if (uni_cp < 0x800)
+    {
+        first   = 0xc0;
+        *charlen = 2;
+    }
+    else if (uni_cp < 0x10000)
+    {
+        first   = 0xe0;
+        *charlen = 3;
+    }
+    else if (uni_cp < 0x200000)
+    {
+        first   = 0xf0;
+        *charlen = 4;
+    }
+    else if (uni_cp < 0x4000000)
+    {
+        first   = 0xf8;
+        *charlen = 5;
+    }
+    else
+    {
+        first   = 0xfc;
+        *charlen = 6;
+    }
+
+    for (i = *charlen - 1; i > 0; --i)
+    {
+        utf8char[i] = (uni_cp & 0x3f) | 0x80;
+        uni_cp >>= 6;
+    }
+    utf8char[0] = uni_cp | first;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Lexer+Parser code
+/////////////////////////////////////////////////////////////////////////////
+
+#line 491 "input_custom_mjson.--input(custom).re"
+
+
+static void parsectx_next_token(mjson_parser_t* context)
+{
+#define YYCTYPE        uint8_t
+#define YYPEEK()       (c>=e?0:*c)
+#define YYSKIP()       ++c
+#define YYBACKUP()     m = c
+#define YYRESTORE()    c = m
+
+    uint8_t* c = context->next;
+    uint8_t* e = context->end;
+    uint8_t* m = NULL;
+    uint8_t* s;
+    int token = TOK_NONE;
+
+    assert(context);
+    RETURN_IF_FAIL(context->next != NULL);
+
+    while (TRUE)
+    {
+        s = c;
+
+
+#line 491 "<stdout>"
+        {
+            YYCTYPE yych;
+            unsigned int yyaccept = 0;
+
+            yych = YYPEEK ();
+            switch (yych) {
+            case 0x00:    goto yy31;
+            case '\t':
+            case '\n':
+            case '\r':
+            case ' ':    goto yy2;
+            case '"':    goto yy30;
+            case '+':
+            case '-':    goto yy22;
+            case ',':    goto yy18;
+            case '.':    goto yy24;
+            case '/':    goto yy4;
+            case '0':    goto yy20;
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy23;
+            case ':':    goto yy14;
+            case '=':    goto yy16;
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy29;
+            case '[':    goto yy10;
+            case ']':    goto yy12;
+            case 'f':    goto yy27;
+            case 'n':    goto yy28;
+            case 't':    goto yy25;
+            case '{':    goto yy6;
+            case '}':    goto yy8;
+            default:    goto yy33;
+            }
+yy2:
+            YYSKIP ();
+            yych = YYPEEK ();
+            goto yy126;
+yy3:
+#line 515 "input_custom_mjson.--input(custom).re"
+            {
+                continue; 
+            }
+#line 589 "<stdout>"
+yy4:
+            yyaccept = 0;
+            YYSKIP ();
+            YYBACKUP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '*':    goto yy108;
+            case '/':    goto yy110;
+            default:    goto yy5;
+            }
+yy5:
+#line 622 "input_custom_mjson.--input(custom).re"
+            {
+                context->token = TOK_INVALID;
+                return;
+            }
+#line 606 "<stdout>"
+yy6:
+            YYSKIP ();
+#line 527 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_LEFT_CURLY_BRACKET;
+                goto done;
+            }
+#line 614 "<stdout>"
+yy8:
+            YYSKIP ();
+#line 532 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_RIGHT_CURLY_BRACKET;
+                goto done;
+            }
+#line 622 "<stdout>"
+yy10:
+            YYSKIP ();
+#line 537 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_LEFT_BRACKET;
+                goto done;
+            }
+#line 630 "<stdout>"
+yy12:
+            YYSKIP ();
+#line 542 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_RIGHT_BRACKET;
+                goto done;
+            }
+#line 638 "<stdout>"
+yy14:
+            YYSKIP ();
+#line 547 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_COLON;
+                goto done;
+            }
+#line 646 "<stdout>"
+yy16:
+            YYSKIP ();
+#line 552 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_EQUAL;
+                goto done;
+            }
+#line 654 "<stdout>"
+yy18:
+            YYSKIP ();
+#line 557 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_COMMA;
+                goto done;
+            }
+#line 662 "<stdout>"
+yy20:
+            YYSKIP ();
+            switch ((yych = YYPEEK ())) {
+            case '.':
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'y':
+            case 'z':    goto yy100;
+            case 'X':
+            case 'x':    goto yy104;
+            default:    goto yy21;
+            }
+yy21:
+#line 572 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_DEC_NUMBER;
+                goto done;
+            }
+#line 738 "<stdout>"
+yy22:
+            yyaccept = 0;
+            YYSKIP ();
+            YYBACKUP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '.':    goto yy95;
+            case '0':    goto yy92;
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy93;
+            default:    goto yy5;
+            }
+yy23:
+            YYSKIP ();
+            yych = YYPEEK ();
+            goto yy71;
+yy24:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy63;
+            default:    goto yy5;
+            }
+yy25:
+            YYSKIP ();
+            switch ((yych = YYPEEK ())) {
+            case 'r':    goto yy59;
+            default:    goto yy49;
+            }
+yy26:
+#line 597 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_IDENTIFIER;
+                goto done;
+            }
+#line 790 "<stdout>"
+yy27:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 'a':    goto yy54;
+            default:    goto yy49;
+            }
+yy28:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 'u':    goto yy50;
+            default:    goto yy49;
+            }
+yy29:
+            YYSKIP ();
+            yych = YYPEEK ();
+            goto yy49;
+yy30:
+            yyaccept = 0;
+            YYSKIP ();
+            YYBACKUP ();
+            yych = YYPEEK ();
+            if (yych <= 0x00) goto yy5;
+            goto yy35;
+yy31:
+            YYSKIP ();
+#line 612 "input_custom_mjson.--input(custom).re"
+            { 
+                context->token = TOK_NONE;
+                return;
+            }
+#line 823 "<stdout>"
+yy33:
+            YYSKIP ();
+            yych = YYPEEK ();
+            goto yy5;
+yy34:
+            YYSKIP ();
+            yych = YYPEEK ();
+yy35:
+            switch (yych) {
+            case 0x00:    goto yy36;
+            case '"':    goto yy38;
+            case '\\':    goto yy37;
+            default:    goto yy34;
+            }
+yy36:
+            YYRESTORE ();
+            switch (yyaccept) {
+            case 0:    goto yy5;
+            case 1:    goto yy65;
+            case 2:    goto yy74;
+            case 3:    goto yy21;
+            default:   goto yy120;
+            }
+yy37:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '"':
+            case '/':
+            case '\\':
+            case 'b':
+            case 'f':
+            case 'n':
+            case 'r':
+            case 't':    goto yy41;
+            case 'u':    goto yy40;
+            default:    goto yy36;
+            }
+yy38:
+            YYSKIP ();
+#line 602 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_NOESC_STRING;
+                goto done;
+            }
+#line 869 "<stdout>"
+yy40:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':    goto yy45;
+            default:    goto yy36;
+            }
+yy41:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 0x00:    goto yy36;
+            case '"':    goto yy43;
+            case '\\':    goto yy37;
+            default:    goto yy41;
+            }
+yy43:
+            YYSKIP ();
+#line 607 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_STRING;
+                goto done;
+            }
+#line 914 "<stdout>"
+yy45:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':    goto yy46;
+            default:    goto yy36;
+            }
+yy46:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':    goto yy47;
+            default:    goto yy36;
+            }
+yy47:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':    goto yy41;
+            default:    goto yy36;
+            }
+yy48:
+            YYSKIP ();
+            yych = YYPEEK ();
+yy49:
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy48;
+            default:    goto yy26;
+            }
+yy50:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 'l':    goto yy51;
+            default:    goto yy49;
+            }
+yy51:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 'l':    goto yy52;
+            default:    goto yy49;
+            }
+yy52:
+            YYSKIP ();
+            switch ((yych = YYPEEK ())) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy48;
+            default:    goto yy53;
+            }
+yy53:
+#line 592 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_NULL;
+                goto done;
+            }
+#line 1157 "<stdout>"
+yy54:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 'l':    goto yy55;
+            default:    goto yy49;
+            }
+yy55:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 's':    goto yy56;
+            default:    goto yy49;
+            }
+yy56:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 'e':    goto yy57;
+            default:    goto yy49;
+            }
+yy57:
+            YYSKIP ();
+            switch ((yych = YYPEEK ())) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy48;
+            default:    goto yy58;
+            }
+yy58:
+#line 587 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_FALSE;
+                goto done;
+            }
+#line 1253 "<stdout>"
+yy59:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 'u':    goto yy60;
+            default:    goto yy49;
+            }
+yy60:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 'e':    goto yy61;
+            default:    goto yy49;
+            }
+yy61:
+            YYSKIP ();
+            switch ((yych = YYPEEK ())) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy48;
+            default:    goto yy62;
+            }
+yy62:
+#line 582 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_TRUE;
+                goto done;
+            }
+#line 1342 "<stdout>"
+yy63:
+            yyaccept = 1;
+            YYSKIP ();
+            YYBACKUP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy63;
+            case 'E':
+            case 'e':    goto yy66;
+            default:    goto yy65;
+            }
+yy65:
+#line 577 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_FLOAT_NUMBER;
+                goto done;
+            }
+#line 1369 "<stdout>"
+yy66:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '+':
+            case '-':    goto yy67;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy68;
+            default:    goto yy36;
+            }
+yy67:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy68;
+            default:    goto yy36;
+            }
+yy68:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy68;
+            default:    goto yy65;
+            }
+yy70:
+            YYSKIP ();
+            yych = YYPEEK ();
+yy71:
+            switch (yych) {
+            case '.':    goto yy76;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy70;
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy72;
+            case 'E':
+            case 'e':    goto yy75;
+            default:    goto yy21;
+            }
+yy72:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy72;
+            default:    goto yy74;
+            }
+yy74:
+#line 617 "input_custom_mjson.--input(custom).re"
+            {
+                context->token = TOK_INVALID;
+                return;
+            }
+#line 1566 "<stdout>"
+yy75:
+            yyaccept = 2;
+            YYSKIP ();
+            YYBACKUP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '+':
+            case '-':    goto yy87;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy88;
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy72;
+            default:    goto yy74;
+            }
+yy76:
+            yyaccept = 1;
+            YYSKIP ();
+            YYBACKUP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 'E':
+            case 'e':    goto yy79;
+            default:    goto yy78;
+            }
+yy77:
+            yyaccept = 1;
+            YYSKIP ();
+            YYBACKUP ();
+            yych = YYPEEK ();
+yy78:
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy77;
+            case 'E':
+            case 'e':    goto yy83;
+            default:    goto yy65;
+            }
+yy79:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '+':
+            case '-':    goto yy80;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy81;
+            default:    goto yy36;
+            }
+yy80:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy81;
+            default:    goto yy36;
+            }
+yy81:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy81;
+            default:    goto yy65;
+            }
+yy83:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '+':
+            case '-':    goto yy84;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy85;
+            default:    goto yy36;
+            }
+yy84:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy85;
+            default:    goto yy36;
+            }
+yy85:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy85;
+            default:    goto yy65;
+            }
+yy87:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy90;
+            default:    goto yy36;
+            }
+yy88:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy88;
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy72;
+            default:    goto yy65;
+            }
+yy90:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy90;
+            default:    goto yy65;
+            }
+yy92:
+            yyaccept = 3;
+            YYSKIP ();
+            YYBACKUP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '.':    goto yy76;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy97;
+            case 'E':
+            case 'e':    goto yy96;
+            default:    goto yy21;
+            }
+yy93:
+            yyaccept = 3;
+            YYSKIP ();
+            YYBACKUP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '.':    goto yy76;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy93;
+            case 'E':
+            case 'e':    goto yy96;
+            default:    goto yy21;
+            }
+yy95:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy63;
+            default:    goto yy36;
+            }
+yy96:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '+':
+            case '-':    goto yy87;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy90;
+            default:    goto yy36;
+            }
+yy97:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '.':    goto yy76;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy97;
+            case 'E':
+            case 'e':    goto yy96;
+            default:    goto yy36;
+            }
+yy99:
+            YYSKIP ();
+            yych = YYPEEK ();
+yy100:
+            switch (yych) {
+            case '.':    goto yy76;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':    goto yy99;
+            case '8':
+            case '9':    goto yy102;
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy72;
+            case 'E':
+            case 'e':    goto yy75;
+            default:    goto yy101;
+            }
+yy101:
+#line 562 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_OCT_NUMBER;
+                goto done;
+            }
+#line 2044 "<stdout>"
+yy102:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '.':    goto yy76;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':    goto yy102;
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy72;
+            case 'E':
+            case 'e':    goto yy75;
+            default:    goto yy74;
+            }
+yy104:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy106;
+            default:    goto yy74;
+            }
+yy105:
+            YYSKIP ();
+            yych = YYPEEK ();
+yy106:
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':    goto yy105;
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case '_':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':    goto yy72;
+            default:    goto yy107;
+            }
+yy107:
+#line 567 "input_custom_mjson.--input(custom).re"
+            {
+                token = TOK_HEX_NUMBER;
+                goto done;
+            }
+#line 2260 "<stdout>"
+yy108:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 0x00:    goto yy36;
+            case '*':    goto yy114;
+            default:    goto yy108;
+            }
+yy110:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 0x00:    goto yy36;
+            case '\n':    goto yy112;
+            default:    goto yy110;
+            }
+yy112:
+            YYSKIP ();
+#line 519 "input_custom_mjson.--input(custom).re"
+            {
+                continue; 
+            }
+#line 2283 "<stdout>"
+yy114:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '*':    goto yy117;
+            case '/':    goto yy119;
+            default:    goto yy116;
+            }
+yy115:
+            YYSKIP ();
+            yych = YYPEEK ();
+yy116:
+            switch (yych) {
+            case 0x00:    goto yy36;
+            case '*':    goto yy122;
+            default:    goto yy115;
+            }
+yy117:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 0x00:    goto yy36;
+            case '*':    goto yy117;
+            case '/':    goto yy121;
+            default:    goto yy115;
+            }
+yy119:
+            YYSKIP ();
+yy120:
+#line 523 "input_custom_mjson.--input(custom).re"
+            {
+                continue; 
+            }
+#line 2317 "<stdout>"
+yy121:
+            yyaccept = 4;
+            YYSKIP ();
+            YYBACKUP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 0x00:    goto yy120;
+            case '*':    goto yy122;
+            default:    goto yy115;
+            }
+yy122:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 0x00:    goto yy36;
+            case '*':    goto yy123;
+            case '/':    goto yy119;
+            default:    goto yy115;
+            }
+yy123:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case 0x00:    goto yy36;
+            case '*':    goto yy123;
+            case '/':    goto yy121;
+            default:    goto yy115;
+            }
+yy125:
+            YYSKIP ();
+            yych = YYPEEK ();
+yy126:
+            switch (yych) {
+            case '\t':
+            case '\n':
+            case '\r':
+            case ' ':    goto yy125;
+            default:    goto yy3;
+            }
+        }
+#line 626 "input_custom_mjson.--input(custom).re"
+
+    }
+
+done:
+    context->token = token;
+    context->start = s;
+    context->next  = c;
+
+#undef YYREADINPUT
+#undef YYCTYPE           
+#undef YYCURSOR          
+#undef YYMARKER          
+}
+
+static int parse_number(mjson_parser_t *context)
+{
+    int            num_parsed;
+    uint8_t        bjson_id;
+    const char*    format;
+    mjson_entry_t* bdata;
+
+    switch(context->token)
+    {
+        case TOK_OCT_NUMBER:
+            bjson_id = MJSON_ID_SINT32;
+            format   = "%o";
+            break;
+        case TOK_HEX_NUMBER:
+            bjson_id = MJSON_ID_SINT32;
+            format   = "%x";
+            break;
+        case TOK_DEC_NUMBER:
+            bjson_id = MJSON_ID_SINT32;
+            format   = "%d";
+            break;
+        case TOK_FLOAT_NUMBER:
+            bjson_id = MJSON_ID_FLOAT32;
+            format   = "%f";
+            break;
+        default:
+            assert(!"unknown token");
+    }
+
+    bdata = (mjson_entry_t*)parsectx_allocate_output(context, (ptrdiff_t)sizeof(mjson_entry_t));
+
+    if (!bdata) return 0;
+
+    bdata->id = bjson_id;
+    num_parsed = sscanf((char*)context->start, format, &bdata->val_u32);
+    assert(num_parsed == 1);
+
+    parsectx_next_token(context);
+    return 1;
+}
+
+static int parse_string(mjson_parser_t *context, uint32_t id)
+{
+#define YYREADINPUT(c) (c>=e?0:*c)
+#define YYCTYPE        uint8_t
+#define YYCURSOR       c
+#define YYMARKER       m
+
+    uint8_t* c = context->start+1;
+    uint8_t* e = context->next;
+    uint8_t* m = NULL;
+    uint8_t* s;
+
+    mjson_entry_t* bdata;
+    uint32_t       ch = 0;
+    uint8_t*       str_dst;
+    const uint8_t* str_src;
+    ptrdiff_t      str_len;
+    size_t         len;
+    int            num_parsed;
+
+    assert(
+        context->token == TOK_STRING       ||
+        context->token == TOK_NOESC_STRING ||
+        context->token == TOK_IDENTIFIER
+    );
+    
+    bdata = (mjson_entry_t*)parsectx_allocate_output(context, (ptrdiff_t)sizeof(mjson_entry_t));
+    
+    if (!bdata) return 0;
+    
+    bdata->id = id;
+
+    if (context->token != TOK_STRING)
+    {
+        str_src = context->start;
+        str_len = context->next - context->start;
+
+        if (context->token==TOK_NOESC_STRING)
+        {
+            str_src += 1;
+            str_len -= 2;
+        }
+        
+        bdata->val_u32 = str_len;
+
+        str_dst = (uint8_t*)parsectx_allocate_output(context, str_len + 1);
+
+        if (!str_dst) return 0;
+
+        memcpy(str_dst, str_src, str_len);
+        str_dst[str_len] = 0;
+
+        parsectx_align4_output(context);
+
+        parsectx_next_token(context);
+
+        return 1;
+    }
+
+    while (TRUE)
+    {
+        s = c;
+
+
+#line 2478 "<stdout>"
+        {
+            YYCTYPE yych;
+            yych = YYPEEK ();
+            switch (yych) {
+            case 0x00:    goto yy135;
+            case '"':    goto yy133;
+            case '\\':    goto yy131;
+            default:    goto yy129;
+            }
+yy129:
+            YYSKIP ();
+            yych = YYPEEK ();
+            goto yy146;
+yy130:
+#line 745 "input_custom_mjson.--input(custom).re"
+            {
+                str_dst = (uint8_t*)parsectx_allocate_output(context, c - s);
+                
+                if (!str_dst) return 0;
+                
+                memcpy(str_dst, s, c - s);
+
+                continue;
+            }
+#line 2503 "<stdout>"
+yy131:
+            YYSKIP ();
+            YYBACKUP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '"':
+            case '/':
+            case '\\':
+            case 'b':
+            case 'f':
+            case 'n':
+            case 'r':
+            case 't':    goto yy138;
+            case 'u':    goto yy136;
+            default:    goto yy132;
+            }
+yy132:
+#line 810 "input_custom_mjson.--input(custom).re"
+            { 
+                assert(!"reachable");
+            }
+#line 2525 "<stdout>"
+yy133:
+            YYSKIP ();
+#line 801 "input_custom_mjson.--input(custom).re"
+            {
+                bdata->val_u32 = context->bjson - (uint8_t*)(bdata + 1);
+                *context->bjson++ = 0;
+                parsectx_align4_output(context);
+                parsectx_next_token(context);
+
+                return 1;
+            }
+#line 2537 "<stdout>"
+yy135:
+            YYSKIP ();
+            yych = YYPEEK ();
+            goto yy132;
+yy136:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':    goto yy140;
+            default:    goto yy137;
+            }
+yy137:
+            YYRESTORE ();
+            goto yy132;
+yy138:
+            YYSKIP ();
+#line 756 "input_custom_mjson.--input(custom).re"
+            {
+                char decoded = s[1];
+                
+                switch (s[1])
+                {
+                    case 'b':
+                        decoded = '\b';
+                        break;
+                    case 'n':
+                        decoded = '\n';
+                        break;
+                    case 'r':
+                        decoded = '\r';
+                        break;
+                    case 't':
+                        decoded = '\t';
+                        break;
+                    case 'f':
+                        decoded = '\f';
+                        break;
+                }
+                
+                str_dst = (uint8_t*)parsectx_allocate_output(context, 1);
+                
+                if (!str_dst) return 0;
+                
+                *str_dst = decoded;
+                
+                continue;
+            }
+#line 2606 "<stdout>"
+yy140:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':    goto yy141;
+            default:    goto yy137;
+            }
+yy141:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':    goto yy142;
+            default:    goto yy137;
+            }
+yy142:
+            YYSKIP ();
+            yych = YYPEEK ();
+            switch (yych) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':    goto yy143;
+            default:    goto yy137;
+            }
+yy143:
+            YYSKIP ();
+#line 787 "input_custom_mjson.--input(custom).re"
+            {
+                str_dst = (uint8_t*)parsectx_reserve_output(context, 6);
+
+                if (!str_dst) return 0;
+
+                num_parsed = sscanf((char*)(s + 2), "%4x", &ch);
+                assert(num_parsed == 1);
+                unicode_cp_to_utf8(ch, str_dst, &len);
+
+                parsectx_advance_output(context, len);
+
+                continue;
+            }
+#line 2707 "<stdout>"
+yy145:
+            YYSKIP ();
+            yych = YYPEEK ();
+yy146:
+            switch (yych) {
+            case 0x00:
+            case '"':
+            case '\\':    goto yy130;
+            default:    goto yy145;
+            }
+        }
+#line 813 "input_custom_mjson.--input(custom).re"
+
+    }
+
+#undef YYREADINPUT
+#undef YYCTYPE           
+#undef YYCURSOR          
+#undef YYMARKER 
+
+    assert(!"reachable");
+    return 0;
+}
+
+static int parse_simple(mjson_parser_t *context)
+{
+    uint32_t* id;
+
+    assert(
+        context->token == TOK_NULL  ||
+        context->token == TOK_FALSE ||
+        context->token == TOK_TRUE
+    );
+
+    id = (uint32_t*)parsectx_allocate_output(context, sizeof(uint32_t));
+    if (!id) return 0;
+
+    switch (context->token)
+    {
+        case TOK_NULL:
+            *id = MJSON_ID_NULL;
+            break;
+        case TOK_FALSE:
+            *id = MJSON_ID_FALSE;
+            break;
+        case TOK_TRUE:
+            *id = MJSON_ID_TRUE;
+            break;
+    }
+
+    parsectx_next_token(context);
+    return 1;
+}
+
+static int parse_value(mjson_parser_t *context)
+{
+    assert(context);
+    switch (context->token)
+    {
+        case TOK_NULL:
+        case TOK_FALSE:
+        case TOK_TRUE:
+            return parse_simple(context);
+
+        case TOK_OCT_NUMBER:
+        case TOK_HEX_NUMBER:
+        case TOK_DEC_NUMBER:
+        case TOK_FLOAT_NUMBER:
+            return parse_number(context);
+
+        case TOK_NOESC_STRING:
+        case TOK_STRING:
+            return parse_string(context, MJSON_ID_UTF8_STRING32);
+
+        case TOK_LEFT_CURLY_BRACKET:
+            parsectx_next_token(context);
+            return parse_key_value_pair(context, TOK_RIGHT_CURLY_BRACKET);
+
+        case TOK_LEFT_BRACKET:
+            parsectx_next_token(context);
+            return parse_value_list(context);
+    }
+
+    return 0;
+}
+
+static int parse_value_list(mjson_parser_t *context)
+{
+    mjson_entry_t* array;
+    uint8_t*       data_start;
+    int            expect_separator;
+
+    assert(context);
+
+    array = (mjson_entry_t*)parsectx_allocate_output(context, sizeof(mjson_entry_t));
+
+    if (!array) return 0;
+    
+    array->id  = MJSON_ID_ARRAY32;
+    data_start = context->bjson;
+
+    expect_separator = FALSE;
+
+    while (context->token != TOK_RIGHT_BRACKET)
+    {
+        if (expect_separator && context->token == TOK_COMMA)
+            parsectx_next_token(context);
+        else
+            expect_separator = TRUE;
+
+        if (!parse_value(context))
+            return 0;
+    }
+
+    array->val_u32 = context->bjson - data_start;
+
+    assert((array->val_u32 & 3) == 0);
+
+    parsectx_next_token(context);
+
+    return 1;
+}
+
+static int parse_key_value_pair(mjson_parser_t* context, int stop_token)
+{
+    mjson_entry_t* dictionary;
+    uint8_t*       data_start;
+    int            expect_separator;
+    assert(context);
+
+    dictionary = (mjson_entry_t*)parsectx_allocate_output(context, sizeof(mjson_entry_t));
+    
+    if (!dictionary) return 0;
+    
+    dictionary->id = MJSON_ID_DICT32;
+    data_start     = context->bjson;
+    
+    expect_separator = FALSE;
+    while (context->token != stop_token)
+    {
+        if (expect_separator && context->token == TOK_COMMA)
+            parsectx_next_token(context);
+        else
+            expect_separator = TRUE;
+
+        switch (context->token)
+        {
+            case TOK_IDENTIFIER:
+            case TOK_NOESC_STRING:
+                if (!parse_string(context, MJSON_ID_UTF8_KEY32))
+                    return 0;
+                break;        
+            default:
+                return 0;
+        }
+
+        if (context->token != TOK_COLON && context->token != TOK_EQUAL)
+            return 0;
+
+        parsectx_next_token(context);
+
+        if (!parse_value(context))
+            return 0;
+    }
+
+    dictionary->val_u32 = context->bjson - data_start;
+    
+    assert((dictionary->val_u32 & 3) == 0);
+    
+    parsectx_next_token(context);
+
+    return 1;
+}
diff --git a/re2c/test/input_custom_mjson.--input(custom).re b/re2c/test/input_custom_mjson.--input(custom).re
new file mode 100644 (file)
index 0000000..53d0d59
--- /dev/null
@@ -0,0 +1,975 @@
+#include <assert.h>
+#include <memory.h>
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+
+/** 
+ * mjson - modified json parser
+ * syntax changes:
+ *   - no {} needed around the whole file
+ *   - "=" is allowed instead of ":"
+ *   - quotes around the key are optional
+ *   - commas after values are optional 
+ *   - and c-style comments allowed
+ *
+ * intermediate storage is based on ideas from BJSON specification: http://bjson.org
+ *
+ * some code ideas are borrowed from another json parser: https://github.com/megous/sjson
+ */
+
+#ifndef __MJSON_H_INCLUDED__
+#define __MJSON_H_INCLUDED__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct _mjson_entry_t;
+
+typedef const struct _mjson_entry_t* mjson_element_t;
+
+enum mjson_element_id_t
+{
+    MJSON_ID_NULL           =  0,
+    MJSON_ID_FALSE          =  1,
+    MJSON_ID_EMPTY_STRING   =  2,
+    MJSON_ID_TRUE           =  3,
+
+    MJSON_ID_UINT32         =  4,
+    MJSON_ID_UINT64         =  5,
+
+    MJSON_ID_SINT32         =  6,
+    MJSON_ID_SINT64         =  7,
+
+    MJSON_ID_FLOAT32        =  8,
+    MJSON_ID_FLOAT64        =  9,
+
+    MJSON_ID_UTF8_KEY32     = 10,
+    MJSON_ID_UTF8_KEY64     = 11,
+
+    MJSON_ID_UTF8_STRING32  = 12,
+    MJSON_ID_UTF8_STRING64  = 13,
+
+    MJSON_ID_BINARY32       = 14,
+    MJSON_ID_BINARY64       = 15,
+
+    MJSON_ID_ARRAY32        = 16,
+    MJSON_ID_ARRAY64        = 17,
+
+    MJSON_ID_DICT32         = 18,
+    MJSON_ID_DICT64         = 19
+};
+
+int mjson_parse(const char *json_data, size_t json_data_size, void* storage_buf, size_t storage_buf_size, mjson_element_t* top_element);
+
+mjson_element_t   mjson_get_top_element(void* storage_buf, size_t storage_buf_size);
+
+mjson_element_t   mjson_get_element_first(mjson_element_t array);
+mjson_element_t   mjson_get_element_next (mjson_element_t array, mjson_element_t current_value);
+mjson_element_t   mjson_get_element      (mjson_element_t array, int index);
+
+mjson_element_t   mjson_get_member_first(mjson_element_t dictionary, mjson_element_t* value);
+mjson_element_t   mjson_get_member_next (mjson_element_t dictionary, mjson_element_t current_key, mjson_element_t* next_value);
+mjson_element_t   mjson_get_member      (mjson_element_t dictionary, const char* name);
+
+int mjson_get_type(mjson_element_t element);
+
+const char* mjson_get_string(mjson_element_t element, const char* fallback);
+int32_t     mjson_get_int   (mjson_element_t element, int32_t     fallback);
+float       mjson_get_float (mjson_element_t element, float       fallback);
+int         mjson_get_bool  (mjson_element_t element, int         fallback);
+int         mjson_is_null   (mjson_element_t element);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+enum mjson_token_t
+{
+    TOK_NONE,
+    TOK_IDENTIFIER,
+    TOK_NOESC_STRING,
+    TOK_STRING,
+    TOK_OCT_NUMBER,
+    TOK_HEX_NUMBER,
+    TOK_DEC_NUMBER,
+    TOK_FLOAT_NUMBER,
+    TOK_COMMA,
+    TOK_COLON,
+    TOK_EQUAL,
+    TOK_LEFT_BRACKET,
+    TOK_RIGHT_BRACKET,
+    TOK_LEFT_CURLY_BRACKET,
+    TOK_RIGHT_CURLY_BRACKET,
+    TOK_FALSE,
+    TOK_TRUE,
+    TOK_NULL,
+    TOK_WHITESPACE,
+    TOK_INVALID,
+    TOK_COUNT
+};
+
+struct _mjson_parser_t
+{
+    int token;
+    uint8_t* start;
+    uint8_t* next;
+    uint8_t* end;
+    uint8_t* bjson;
+    uint8_t* bjson_limit;
+};
+
+struct _mjson_entry_t
+{
+    uint32_t  id;
+    union
+    {
+        uint32_t val_u32;
+        int32_t  val_s32;
+        float    val_f32;
+    };
+};
+
+#define RETURN_VAL_IF_FAIL(cond, val) if (!(cond)) return (val)
+#define RETURN_IF_FAIL(cond) if (!(cond)) return
+#define MAX_UTF8_CHAR_LEN 6
+#define TRUE  1
+#define FALSE 0
+
+typedef struct _mjson_parser_t  mjson_parser_t;
+typedef struct _mjson_entry_t   mjson_entry_t;
+
+static void* parsectx_allocate_output(mjson_parser_t* ctx, ptrdiff_t size);
+
+static void parsectx_next_token    (mjson_parser_t* context);
+
+static int parse_value_list    (mjson_parser_t *context);
+static int parse_key_value_pair(mjson_parser_t *context, int stop_token);
+
+static mjson_element_t next_element(mjson_element_t element);
+
+int mjson_parse(const char *json_data, size_t json_data_size, void* storage_buf, size_t storage_buf_size, const mjson_entry_t** top_element)
+{
+    uint32_t* fourcc;
+    mjson_parser_t c = {
+        TOK_NONE, 0,
+        (uint8_t*)json_data,   (uint8_t*)json_data + json_data_size,
+        (uint8_t*)storage_buf, (uint8_t*)storage_buf + storage_buf_size
+    };
+    int stop_token = TOK_NONE;
+
+    *top_element = 0;
+
+    fourcc = (uint32_t*)parsectx_allocate_output(&c, (ptrdiff_t)sizeof(uint32_t));
+
+    if (!fourcc) return 0;
+
+    *fourcc = '23JB';
+
+    parsectx_next_token(&c);
+
+    if (c.token == TOK_LEFT_BRACKET)
+    {
+        parsectx_next_token(&c);
+        if (!parse_value_list(&c))
+            return 0;
+    }
+    else
+    {
+        if (c.token == TOK_LEFT_CURLY_BRACKET)
+        {
+            stop_token = TOK_RIGHT_CURLY_BRACKET;
+            parsectx_next_token(&c);
+        }
+
+        if (!parse_key_value_pair(&c, stop_token))
+            return 0;
+    }
+
+    if (c.token != TOK_NONE)
+        return 0;
+
+    *top_element = (mjson_entry_t*)(fourcc + 1);
+
+    return 1;
+}
+
+mjson_element_t mjson_get_top_element(void* storage_buf, size_t storage_buf_size)
+{
+    mjson_element_t top = (mjson_element_t)storage_buf;
+    
+    RETURN_VAL_IF_FAIL(top, NULL);
+    RETURN_VAL_IF_FAIL(top->id == MJSON_ID_DICT32 || top->id == MJSON_ID_ARRAY32, NULL);
+    RETURN_VAL_IF_FAIL(top->val_u32 <= storage_buf_size, NULL);
+    
+    return top;
+}
+
+mjson_element_t mjson_get_element_first(mjson_element_t array)
+{
+    RETURN_VAL_IF_FAIL(array, NULL);
+    RETURN_VAL_IF_FAIL(array->id == MJSON_ID_ARRAY32, NULL);
+    
+    return array + 1;
+}
+
+mjson_element_t mjson_get_element_next(mjson_element_t array, mjson_element_t current_value)
+{
+    mjson_element_t next = NULL;
+
+    RETURN_VAL_IF_FAIL(array, NULL);
+    RETURN_VAL_IF_FAIL(current_value, NULL);
+    RETURN_VAL_IF_FAIL(array->id == MJSON_ID_ARRAY32, NULL);
+    RETURN_VAL_IF_FAIL((uint8_t*)array + array->val_u32 > (uint8_t*)current_value, NULL);
+    
+    next = next_element(current_value);
+    
+    RETURN_VAL_IF_FAIL((uint8_t*)array + array->val_u32 > (uint8_t*)next, NULL);
+    
+    return next;
+}
+
+mjson_element_t mjson_get_element(mjson_element_t array, int index)
+{
+    mjson_element_t result;
+    
+    result = mjson_get_element_first(array);
+    while (result && index--)
+        result = mjson_get_element_next(array, result);
+    
+    return result;
+}
+
+mjson_element_t mjson_get_member_first(mjson_element_t dictionary, mjson_element_t* value)
+{
+    RETURN_VAL_IF_FAIL(dictionary, NULL);
+    RETURN_VAL_IF_FAIL(dictionary->id == MJSON_ID_DICT32, NULL);
+    RETURN_VAL_IF_FAIL((dictionary+1)->id == MJSON_ID_UTF8_KEY32, NULL);
+    
+    *value = next_element(dictionary+1);
+    
+    return dictionary + 1;
+}
+
+mjson_element_t mjson_get_member_next(mjson_element_t dictionary, mjson_element_t current_key, mjson_element_t* next_value)
+{
+    mjson_element_t next_key = NULL;
+
+    RETURN_VAL_IF_FAIL(dictionary, NULL);
+    RETURN_VAL_IF_FAIL(dictionary->id == MJSON_ID_DICT32, NULL);
+    RETURN_VAL_IF_FAIL(current_key, NULL);
+    RETURN_VAL_IF_FAIL((uint8_t*)dictionary + dictionary->val_u32 > (uint8_t*)current_key, NULL);
+    RETURN_VAL_IF_FAIL(current_key->id == MJSON_ID_UTF8_KEY32, NULL);
+    
+    next_key = next_element(current_key);
+    next_key = next_element(next_key);
+    
+    RETURN_VAL_IF_FAIL(next_key, NULL);
+    RETURN_VAL_IF_FAIL((uint8_t*)dictionary + dictionary->val_u32 > (uint8_t*)next_key, NULL);
+    RETURN_VAL_IF_FAIL(next_key->id == MJSON_ID_UTF8_KEY32, NULL);
+
+    *next_value = next_element(next_key);
+   
+    return next_key;    
+}
+
+mjson_element_t mjson_get_member(mjson_element_t dictionary, const char* name)
+{
+    mjson_element_t key, result;
+    
+    key = mjson_get_member_first(dictionary, &result);
+    while (key && strncmp(name, (char*)(key+1), key->val_u32) != 0)
+        result = mjson_get_member_next(dictionary, key, &result);
+    
+    return result;
+}
+
+int mjson_get_type(mjson_element_t element)
+{
+    RETURN_VAL_IF_FAIL(element, MJSON_ID_NULL);
+    
+    return element->id;
+}
+
+const char* mjson_get_string(mjson_element_t element, const char* fallback)
+{
+    RETURN_VAL_IF_FAIL(element, fallback);
+    RETURN_VAL_IF_FAIL(element->id == MJSON_ID_UTF8_STRING32 ||
+                       element->id == MJSON_ID_UTF8_KEY32,
+                       fallback);
+    
+    return (const char*)(element+1);
+}
+
+int32_t mjson_get_int(mjson_element_t element, int32_t fallback)
+{
+    RETURN_VAL_IF_FAIL(element, fallback);
+    RETURN_VAL_IF_FAIL(element->id == MJSON_ID_SINT32, fallback);
+    
+    return element->val_s32;
+}
+
+float mjson_get_float(mjson_element_t element, float fallback)
+{
+    RETURN_VAL_IF_FAIL(element, fallback);
+    RETURN_VAL_IF_FAIL(element->id == MJSON_ID_FLOAT32, fallback);
+    
+    return element->val_f32;
+}
+
+int mjson_get_bool(mjson_element_t element, int fallback)
+{
+    RETURN_VAL_IF_FAIL(element, fallback);
+    RETURN_VAL_IF_FAIL(element->id == MJSON_ID_TRUE || element->id == MJSON_ID_FALSE, fallback);
+    
+    return element->id == MJSON_ID_TRUE;
+}
+
+int mjson_is_null(mjson_element_t element)
+{
+    RETURN_VAL_IF_FAIL(element, TRUE);
+
+    return element->id == MJSON_ID_NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// API helpers
+/////////////////////////////////////////////////////////////////////////////
+
+static size_t element_size(mjson_element_t element)
+{
+    RETURN_VAL_IF_FAIL(element, 0);
+
+    switch(element->id)
+    {
+        case MJSON_ID_NULL:
+        case MJSON_ID_FALSE:
+        case MJSON_ID_EMPTY_STRING:
+        case MJSON_ID_TRUE:
+            return sizeof(uint32_t);
+
+        case MJSON_ID_UINT32:
+        case MJSON_ID_SINT32:
+        case MJSON_ID_FLOAT32:
+            return sizeof(mjson_entry_t);
+
+        case MJSON_ID_UTF8_KEY32:
+        case MJSON_ID_UTF8_STRING32:
+            return sizeof(mjson_entry_t) + ((element->val_u32 + 1 + 3) & (~3));
+
+        case MJSON_ID_BINARY32:
+        case MJSON_ID_ARRAY32:
+        case MJSON_ID_DICT32:
+            return sizeof(mjson_entry_t) + ((element->val_u32 + 3) & (~3));
+    };
+
+    return 0;
+}
+
+static mjson_element_t next_element(mjson_element_t element)
+{
+    size_t size;
+    
+    RETURN_VAL_IF_FAIL(element, 0);
+
+    size = element_size(element);
+    assert(size>0);
+    
+    return (mjson_element_t)((uint8_t*)element + size);
+}
+
+static void* parsectx_reserve_output(mjson_parser_t* ctx, ptrdiff_t size)
+{
+    return (ctx->bjson_limit - ctx->bjson < size) ? 0 : ctx->bjson;
+}
+
+static void parsectx_advance_output(mjson_parser_t* ctx, ptrdiff_t size)
+{
+    ctx->bjson += size;
+}
+
+static void* parsectx_allocate_output(mjson_parser_t* ctx, ptrdiff_t size)
+{
+    void* ptr;
+
+    if (ctx->bjson_limit - ctx->bjson < size)
+        return 0;
+
+    ptr = ctx->bjson;
+    ctx->bjson += size;
+
+    return ptr;
+}
+
+//TODO: what about 64 bit code????
+static void parsectx_align4_output(mjson_parser_t* ctx)
+{
+    ctx->bjson = (uint8_t*)(((ptrdiff_t)ctx->bjson + 3) & (~3));
+}
+
+static void unicode_cp_to_utf8(uint32_t uni_cp, uint8_t* utf8char/*[6]*/, size_t* charlen)
+{
+    uint32_t first, i;
+    
+    if (uni_cp < 0x80)
+    {
+        first   = 0;
+        *charlen = 1;
+    }
+    else if (uni_cp < 0x800)
+    {
+        first   = 0xc0;
+        *charlen = 2;
+    }
+    else if (uni_cp < 0x10000)
+    {
+        first   = 0xe0;
+        *charlen = 3;
+    }
+    else if (uni_cp < 0x200000)
+    {
+        first   = 0xf0;
+        *charlen = 4;
+    }
+    else if (uni_cp < 0x4000000)
+    {
+        first   = 0xf8;
+        *charlen = 5;
+    }
+    else
+    {
+        first   = 0xfc;
+        *charlen = 6;
+    }
+
+    for (i = *charlen - 1; i > 0; --i)
+    {
+        utf8char[i] = (uni_cp & 0x3f) | 0x80;
+        uni_cp >>= 6;
+    }
+    utf8char[0] = uni_cp | first;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Lexer+Parser code
+/////////////////////////////////////////////////////////////////////////////
+
+/*!re2c
+    re2c:yyfill:enable      = 0;
+    re2c:indent:top         = 2;
+    re2c:indent:string      = "    ";
+
+    WS = [ \t\n\r]+;
+
+    S = [+-];
+    O = [0-7];
+    D = [0-9];
+    H = [a-fA-F0-9];
+    L = [a-zA-Z_];
+    E = [Ee] [+-]? D+;
+
+    HEX_NUMBER = ("0" [xX] H+);
+    OCT_NUMBER = ("0" O+);
+    DEC_NUMBER = (S? ("0"|([1-9]D*)));
+
+    FLOAT_NUMBER = (S? D+ E) | (S? D* "." D+ E?) | (S? D+ "." D* E?);
+
+    CHAR               = [^\\"\000];
+    CTL                = "\\" ["\\/bfnrt];
+    UNICODE            = "\\u" H{4};
+    STRING             = "\"" (CHAR|CTL|UNICODE)* "\"";
+    NOESC_STRING       = "\"" (CHAR)* "\"";
+    IDENTIFIER         = L (L|D)*;
+    SINGLELINE_COMMENT = "//" [^\n\000]* "\n";
+    MULTILINE_COMMENT  = "\/*" [^*\000]* [*]+ ( [^\/\000] [^*\000]* [*]+ )* "\/";
+*/
+
+static void parsectx_next_token(mjson_parser_t* context)
+{
+#define YYCTYPE        uint8_t
+#define YYPEEK()       (c>=e?0:*c)
+#define YYSKIP()       ++c
+#define YYBACKUP()     m = c
+#define YYRESTORE()    c = m
+
+    uint8_t* c = context->next;
+    uint8_t* e = context->end;
+    uint8_t* m = NULL;
+    uint8_t* s;
+    int token = TOK_NONE;
+
+    assert(context);
+    RETURN_IF_FAIL(context->next != NULL);
+
+    while (TRUE)
+    {
+        s = c;
+
+/*!re2c
+            WS {
+                continue; 
+            }
+            
+            SINGLELINE_COMMENT {
+                continue; 
+            }
+            
+            MULTILINE_COMMENT {
+                continue; 
+            }
+            
+            "{" {
+                token = TOK_LEFT_CURLY_BRACKET;
+                goto done;
+            }
+    
+            "}" {
+                token = TOK_RIGHT_CURLY_BRACKET;
+                goto done;
+            }
+    
+            "[" {
+                token = TOK_LEFT_BRACKET;
+                goto done;
+            }
+    
+            "]" {
+                token = TOK_RIGHT_BRACKET;
+                goto done;
+            }
+    
+            ":" {
+                token = TOK_COLON;
+                goto done;
+            }
+    
+            "=" {
+                token = TOK_EQUAL;
+                goto done;
+            }
+
+            "," {
+                token = TOK_COMMA;
+                goto done;
+            }
+    
+            OCT_NUMBER {
+                token = TOK_OCT_NUMBER;
+                goto done;
+            }
+    
+            HEX_NUMBER {
+                token = TOK_HEX_NUMBER;
+                goto done;
+            }
+    
+            DEC_NUMBER {
+                token = TOK_DEC_NUMBER;
+                goto done;
+            }
+    
+            FLOAT_NUMBER {
+                token = TOK_FLOAT_NUMBER;
+                goto done;
+            }
+    
+            "true" {
+                token = TOK_TRUE;
+                goto done;
+            }
+    
+            "false" {
+                token = TOK_FALSE;
+                goto done;
+            }
+    
+            "null" {
+                token = TOK_NULL;
+                goto done;
+            }
+    
+            IDENTIFIER {
+                token = TOK_IDENTIFIER;
+                goto done;
+            }
+
+            NOESC_STRING {
+                token = TOK_NOESC_STRING;
+                goto done;
+            }
+    
+            STRING {
+                token = TOK_STRING;
+                goto done;
+            }
+    
+            [\000] { 
+                context->token = TOK_NONE;
+                return;
+            }
+    
+            (L|D)+ {
+                context->token = TOK_INVALID;
+                return;
+            }
+
+            . | "\n" {
+                context->token = TOK_INVALID;
+                return;
+            }
+*/
+    }
+
+done:
+    context->token = token;
+    context->start = s;
+    context->next  = c;
+
+#undef YYREADINPUT
+#undef YYCTYPE           
+#undef YYCURSOR          
+#undef YYMARKER          
+}
+
+static int parse_number(mjson_parser_t *context)
+{
+    int            num_parsed;
+    uint8_t        bjson_id;
+    const char*    format;
+    mjson_entry_t* bdata;
+
+    switch(context->token)
+    {
+        case TOK_OCT_NUMBER:
+            bjson_id = MJSON_ID_SINT32;
+            format   = "%o";
+            break;
+        case TOK_HEX_NUMBER:
+            bjson_id = MJSON_ID_SINT32;
+            format   = "%x";
+            break;
+        case TOK_DEC_NUMBER:
+            bjson_id = MJSON_ID_SINT32;
+            format   = "%d";
+            break;
+        case TOK_FLOAT_NUMBER:
+            bjson_id = MJSON_ID_FLOAT32;
+            format   = "%f";
+            break;
+        default:
+            assert(!"unknown token");
+    }
+
+    bdata = (mjson_entry_t*)parsectx_allocate_output(context, (ptrdiff_t)sizeof(mjson_entry_t));
+
+    if (!bdata) return 0;
+
+    bdata->id = bjson_id;
+    num_parsed = sscanf((char*)context->start, format, &bdata->val_u32);
+    assert(num_parsed == 1);
+
+    parsectx_next_token(context);
+    return 1;
+}
+
+static int parse_string(mjson_parser_t *context, uint32_t id)
+{
+#define YYREADINPUT(c) (c>=e?0:*c)
+#define YYCTYPE        uint8_t
+#define YYCURSOR       c
+#define YYMARKER       m
+
+    uint8_t* c = context->start+1;
+    uint8_t* e = context->next;
+    uint8_t* m = NULL;
+    uint8_t* s;
+
+    mjson_entry_t* bdata;
+    uint32_t       ch = 0;
+    uint8_t*       str_dst;
+    const uint8_t* str_src;
+    ptrdiff_t      str_len;
+    size_t         len;
+    int            num_parsed;
+
+    assert(
+        context->token == TOK_STRING       ||
+        context->token == TOK_NOESC_STRING ||
+        context->token == TOK_IDENTIFIER
+    );
+    
+    bdata = (mjson_entry_t*)parsectx_allocate_output(context, (ptrdiff_t)sizeof(mjson_entry_t));
+    
+    if (!bdata) return 0;
+    
+    bdata->id = id;
+
+    if (context->token != TOK_STRING)
+    {
+        str_src = context->start;
+        str_len = context->next - context->start;
+
+        if (context->token==TOK_NOESC_STRING)
+        {
+            str_src += 1;
+            str_len -= 2;
+        }
+        
+        bdata->val_u32 = str_len;
+
+        str_dst = (uint8_t*)parsectx_allocate_output(context, str_len + 1);
+
+        if (!str_dst) return 0;
+
+        memcpy(str_dst, str_src, str_len);
+        str_dst[str_len] = 0;
+
+        parsectx_align4_output(context);
+
+        parsectx_next_token(context);
+
+        return 1;
+    }
+
+    while (TRUE)
+    {
+        s = c;
+
+/*!re2c
+            CHAR+ {
+                str_dst = (uint8_t*)parsectx_allocate_output(context, c - s);
+                
+                if (!str_dst) return 0;
+                
+                memcpy(str_dst, s, c - s);
+
+                continue;
+            }
+            
+            
+            CTL {
+                char decoded = s[1];
+                
+                switch (s[1])
+                {
+                    case 'b':
+                        decoded = '\b';
+                        break;
+                    case 'n':
+                        decoded = '\n';
+                        break;
+                    case 'r':
+                        decoded = '\r';
+                        break;
+                    case 't':
+                        decoded = '\t';
+                        break;
+                    case 'f':
+                        decoded = '\f';
+                        break;
+                }
+                
+                str_dst = (uint8_t*)parsectx_allocate_output(context, 1);
+                
+                if (!str_dst) return 0;
+                
+                *str_dst = decoded;
+                
+                continue;
+            }
+
+            UNICODE {
+                str_dst = (uint8_t*)parsectx_reserve_output(context, 6);
+
+                if (!str_dst) return 0;
+
+                num_parsed = sscanf((char*)(s + 2), "%4x", &ch);
+                assert(num_parsed == 1);
+                unicode_cp_to_utf8(ch, str_dst, &len);
+
+                parsectx_advance_output(context, len);
+
+                continue;
+            }
+
+            "\"" {
+                bdata->val_u32 = context->bjson - (uint8_t*)(bdata + 1);
+                *context->bjson++ = 0;
+                parsectx_align4_output(context);
+                parsectx_next_token(context);
+
+                return 1;
+            }
+
+            . | "\n" | [\000] { 
+                assert(!"reachable");
+            }
+*/
+    }
+
+#undef YYREADINPUT
+#undef YYCTYPE           
+#undef YYCURSOR          
+#undef YYMARKER 
+
+    assert(!"reachable");
+    return 0;
+}
+
+static int parse_simple(mjson_parser_t *context)
+{
+    uint32_t* id;
+
+    assert(
+        context->token == TOK_NULL  ||
+        context->token == TOK_FALSE ||
+        context->token == TOK_TRUE
+    );
+
+    id = (uint32_t*)parsectx_allocate_output(context, sizeof(uint32_t));
+    if (!id) return 0;
+
+    switch (context->token)
+    {
+        case TOK_NULL:
+            *id = MJSON_ID_NULL;
+            break;
+        case TOK_FALSE:
+            *id = MJSON_ID_FALSE;
+            break;
+        case TOK_TRUE:
+            *id = MJSON_ID_TRUE;
+            break;
+    }
+
+    parsectx_next_token(context);
+    return 1;
+}
+
+static int parse_value(mjson_parser_t *context)
+{
+    assert(context);
+    switch (context->token)
+    {
+        case TOK_NULL:
+        case TOK_FALSE:
+        case TOK_TRUE:
+            return parse_simple(context);
+
+        case TOK_OCT_NUMBER:
+        case TOK_HEX_NUMBER:
+        case TOK_DEC_NUMBER:
+        case TOK_FLOAT_NUMBER:
+            return parse_number(context);
+
+        case TOK_NOESC_STRING:
+        case TOK_STRING:
+            return parse_string(context, MJSON_ID_UTF8_STRING32);
+
+        case TOK_LEFT_CURLY_BRACKET:
+            parsectx_next_token(context);
+            return parse_key_value_pair(context, TOK_RIGHT_CURLY_BRACKET);
+
+        case TOK_LEFT_BRACKET:
+            parsectx_next_token(context);
+            return parse_value_list(context);
+    }
+
+    return 0;
+}
+
+static int parse_value_list(mjson_parser_t *context)
+{
+    mjson_entry_t* array;
+    uint8_t*       data_start;
+    int            expect_separator;
+
+    assert(context);
+
+    array = (mjson_entry_t*)parsectx_allocate_output(context, sizeof(mjson_entry_t));
+
+    if (!array) return 0;
+    
+    array->id  = MJSON_ID_ARRAY32;
+    data_start = context->bjson;
+
+    expect_separator = FALSE;
+
+    while (context->token != TOK_RIGHT_BRACKET)
+    {
+        if (expect_separator && context->token == TOK_COMMA)
+            parsectx_next_token(context);
+        else
+            expect_separator = TRUE;
+
+        if (!parse_value(context))
+            return 0;
+    }
+
+    array->val_u32 = context->bjson - data_start;
+
+    assert((array->val_u32 & 3) == 0);
+
+    parsectx_next_token(context);
+
+    return 1;
+}
+
+static int parse_key_value_pair(mjson_parser_t* context, int stop_token)
+{
+    mjson_entry_t* dictionary;
+    uint8_t*       data_start;
+    int            expect_separator;
+    assert(context);
+
+    dictionary = (mjson_entry_t*)parsectx_allocate_output(context, sizeof(mjson_entry_t));
+    
+    if (!dictionary) return 0;
+    
+    dictionary->id = MJSON_ID_DICT32;
+    data_start     = context->bjson;
+    
+    expect_separator = FALSE;
+    while (context->token != stop_token)
+    {
+        if (expect_separator && context->token == TOK_COMMA)
+            parsectx_next_token(context);
+        else
+            expect_separator = TRUE;
+
+        switch (context->token)
+        {
+            case TOK_IDENTIFIER:
+            case TOK_NOESC_STRING:
+                if (!parse_string(context, MJSON_ID_UTF8_KEY32))
+                    return 0;
+                break;        
+            default:
+                return 0;
+        }
+
+        if (context->token != TOK_COLON && context->token != TOK_EQUAL)
+            return 0;
+
+        parsectx_next_token(context);
+
+        if (!parse_value(context))
+            return 0;
+    }
+
+    dictionary->val_u32 = context->bjson - data_start;
+    
+    assert((dictionary->val_u32 & 3) == 0);
+    
+    parsectx_next_token(context);
+
+    return 1;
+}