/* Generated by re2c */
#line 1 "input_custom_mjson.re"
// re2c $INPUT -o $OUTPUT  --input custom
#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 492 "input_custom_mjson.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 492 "input_custom_mjson.c"
        {
            YYCTYPE yych;
            unsigned int yyaccept = 0;
            yych = YYPEEK();
            switch (yych) {
                case 0x00: goto yy1;
                case '\t':
                case '\n':
                case '\r':
                case ' ': goto yy4;
                case '"': goto yy6;
                case '+':
                case '-': goto yy7;
                case ',': goto yy8;
                case '.': goto yy9;
                case '/': goto yy10;
                case '0': goto yy11;
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9': goto yy13;
                case ':': goto yy14;
                case '=': goto yy15;
                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 yy16;
                case '[': goto yy19;
                case ']': goto yy20;
                case 'f': goto yy21;
                case 'n': goto yy22;
                case 't': goto yy23;
                case '{': goto yy24;
                case '}': goto yy25;
                default: goto yy2;
            }
yy1:
            YYSKIP();
#line 613 "input_custom_mjson.re"
            { 
                context->token = TOK_NONE;
                return;
            }
#line 587 "input_custom_mjson.c"
yy2:
            YYSKIP();
yy3:
#line 623 "input_custom_mjson.re"
            {
                context->token = TOK_INVALID;
                return;
            }
#line 596 "input_custom_mjson.c"
yy4:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case '\t':
                case '\n':
                case '\r':
                case ' ': goto yy4;
                default: goto yy5;
            }
yy5:
#line 516 "input_custom_mjson.re"
            {
                continue; 
            }
#line 612 "input_custom_mjson.c"
yy6:
            yyaccept = 0;
            YYSKIP();
            YYBACKUP();
            yych = YYPEEK();
            if (yych <= 0x00) goto yy3;
            goto yy27;
yy7:
            yyaccept = 0;
            YYSKIP();
            YYBACKUP();
            yych = YYPEEK();
            switch (yych) {
                case '.': goto yy31;
                case '0': goto yy32;
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9': goto yy33;
                default: goto yy3;
            }
yy8:
            YYSKIP();
#line 558 "input_custom_mjson.re"
            {
                token = TOK_COMMA;
                goto done;
            }
#line 646 "input_custom_mjson.c"
yy9:
            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 yy34;
                default: goto yy3;
            }
yy10:
            yyaccept = 0;
            YYSKIP();
            YYBACKUP();
            yych = YYPEEK();
            switch (yych) {
                case '*': goto yy36;
                case '/': goto yy37;
                default: goto yy3;
            }
yy11:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                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 yy39;
                case 'X':
                case 'x': goto yy46;
                default: goto yy12;
            }
yy12:
#line 573 "input_custom_mjson.re"
            {
                token = TOK_DEC_NUMBER;
                goto done;
            }
#line 749 "input_custom_mjson.c"
yy13:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case '.': goto yy34;
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9': goto yy13;
                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 yy43;
                case 'E':
                case 'e': goto yy45;
                default: goto yy12;
            }
yy14:
            YYSKIP();
#line 548 "input_custom_mjson.re"
            {
                token = TOK_COLON;
                goto done;
            }
#line 827 "input_custom_mjson.c"
yy15:
            YYSKIP();
#line 553 "input_custom_mjson.re"
            {
                token = TOK_EQUAL;
                goto done;
            }
#line 835 "input_custom_mjson.c"
yy16:
            YYSKIP();
            yych = YYPEEK();
yy17:
            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 yy16;
                default: goto yy18;
            }
yy18:
#line 598 "input_custom_mjson.re"
            {
                token = TOK_IDENTIFIER;
                goto done;
            }
#line 912 "input_custom_mjson.c"
yy19:
            YYSKIP();
#line 538 "input_custom_mjson.re"
            {
                token = TOK_LEFT_BRACKET;
                goto done;
            }
#line 920 "input_custom_mjson.c"
yy20:
            YYSKIP();
#line 543 "input_custom_mjson.re"
            {
                token = TOK_RIGHT_BRACKET;
                goto done;
            }
#line 928 "input_custom_mjson.c"
yy21:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 'a': goto yy47;
                default: goto yy17;
            }
yy22:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 'u': goto yy48;
                default: goto yy17;
            }
yy23:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 'r': goto yy49;
                default: goto yy17;
            }
yy24:
            YYSKIP();
#line 528 "input_custom_mjson.re"
            {
                token = TOK_LEFT_CURLY_BRACKET;
                goto done;
            }
#line 957 "input_custom_mjson.c"
yy25:
            YYSKIP();
#line 533 "input_custom_mjson.re"
            {
                token = TOK_RIGHT_CURLY_BRACKET;
                goto done;
            }
#line 965 "input_custom_mjson.c"
yy26:
            YYSKIP();
            yych = YYPEEK();
yy27:
            switch (yych) {
                case 0x00: goto yy28;
                case '"': goto yy29;
                case '\\': goto yy30;
                default: goto yy26;
            }
yy28:
            YYRESTORE();
            switch (yyaccept) {
                case 0: goto yy3;
                case 1: goto yy12;
                case 2: goto yy35;
                case 3: goto yy42;
                default: goto yy69;
            }
yy29:
            YYSKIP();
#line 603 "input_custom_mjson.re"
            {
                token = TOK_NOESC_STRING;
                goto done;
            }
#line 992 "input_custom_mjson.c"
yy30:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case '"':
                case '/':
                case '\\':
                case 'b':
                case 'f':
                case 'n':
                case 'r':
                case 't': goto yy50;
                case 'u': goto yy51;
                default: goto yy28;
            }
yy31:
            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 yy34;
                default: goto yy28;
            }
yy32:
            yyaccept = 1;
            YYSKIP();
            YYBACKUP();
            yych = YYPEEK();
            switch (yych) {
                case '.': goto yy34;
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9': goto yy52;
                case 'E':
                case 'e': goto yy53;
                default: goto yy12;
            }
yy33:
            yyaccept = 1;
            YYSKIP();
            YYBACKUP();
            yych = YYPEEK();
            switch (yych) {
                case '.': goto yy34;
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9': goto yy33;
                case 'E':
                case 'e': goto yy53;
                default: goto yy12;
            }
yy34:
            yyaccept = 2;
            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 yy34;
                case 'E':
                case 'e': goto yy53;
                default: goto yy35;
            }
yy35:
#line 578 "input_custom_mjson.re"
            {
                token = TOK_FLOAT_NUMBER;
                goto done;
            }
#line 1092 "input_custom_mjson.c"
yy36:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 0x00: goto yy28;
                case '*': goto yy54;
                default: goto yy36;
            }
yy37:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 0x00: goto yy28;
                case '\n': goto yy55;
                default: goto yy37;
            }
yy38:
            YYSKIP();
            yych = YYPEEK();
yy39:
            switch (yych) {
                case '.': goto yy34;
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7': goto yy38;
                case '8':
                case '9': goto yy41;
                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 yy43;
                case 'E':
                case 'e': goto yy45;
                default: goto yy40;
            }
yy40:
#line 563 "input_custom_mjson.re"
            {
                token = TOK_OCT_NUMBER;
                goto done;
            }
#line 1186 "input_custom_mjson.c"
yy41:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case '.': goto yy34;
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9': goto yy41;
                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 yy43;
                case 'E':
                case 'e': goto yy45;
                default: goto yy42;
            }
yy42:
#line 618 "input_custom_mjson.re"
            {
                context->token = TOK_INVALID;
                return;
            }
#line 1263 "input_custom_mjson.c"
yy43:
            YYSKIP();
            yych = YYPEEK();
yy44:
            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 yy43;
                default: goto yy42;
            }
yy45:
            yyaccept = 3;
            YYSKIP();
            YYBACKUP();
            yych = YYPEEK();
            switch (yych) {
                case '+':
                case '-': goto yy56;
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9': goto yy57;
                default: goto yy44;
            }
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 '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 yy59;
                default: goto yy42;
            }
yy47:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 'l': goto yy61;
                default: goto yy17;
            }
yy48:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 'l': goto yy62;
                default: goto yy17;
            }
yy49:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 'u': goto yy63;
                default: goto yy17;
            }
yy50:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 0x00: goto yy28;
                case '"': goto yy64;
                case '\\': goto yy30;
                default: goto yy50;
            }
yy51:
            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 yy65;
                default: goto yy28;
            }
yy52:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case '.': goto yy34;
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9': goto yy52;
                case 'E':
                case 'e': goto yy53;
                default: goto yy28;
            }
yy53:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case '+':
                case '-': goto yy56;
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9': goto yy66;
                default: goto yy28;
            }
yy54:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 0x00: goto yy28;
                case '*': goto yy67;
                case '/': goto yy68;
                default: goto yy36;
            }
yy55:
            YYSKIP();
#line 520 "input_custom_mjson.re"
            {
                continue; 
            }
#line 1533 "input_custom_mjson.c"
yy56:
            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 yy66;
                default: goto yy28;
            }
yy57:
            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 yy57;
                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 yy43;
                default: goto yy35;
            }
yy58:
            YYSKIP();
            yych = YYPEEK();
yy59:
            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 yy58;
                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 yy43;
                default: goto yy60;
            }
yy60:
#line 568 "input_custom_mjson.re"
            {
                token = TOK_HEX_NUMBER;
                goto done;
            }
#line 1695 "input_custom_mjson.c"
yy61:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 's': goto yy70;
                default: goto yy17;
            }
yy62:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 'l': goto yy71;
                default: goto yy17;
            }
yy63:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 'e': goto yy73;
                default: goto yy17;
            }
yy64:
            YYSKIP();
#line 608 "input_custom_mjson.re"
            {
                token = TOK_STRING;
                goto done;
            }
#line 1724 "input_custom_mjson.c"
yy65:
            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 yy75;
                default: goto yy28;
            }
yy66:
            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 yy66;
                default: goto yy35;
            }
yy67:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 0x00: goto yy28;
                case '*': goto yy67;
                case '/': goto yy76;
                default: goto yy36;
            }
yy68:
            YYSKIP();
yy69:
#line 524 "input_custom_mjson.re"
            {
                continue; 
            }
#line 1785 "input_custom_mjson.c"
yy70:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 'e': goto yy77;
                default: goto yy17;
            }
yy71:
            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 yy16;
                default: goto yy72;
            }
yy72:
#line 593 "input_custom_mjson.re"
            {
                token = TOK_NULL;
                goto done;
            }
#line 1868 "input_custom_mjson.c"
yy73:
            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 yy16;
                default: goto yy74;
            }
yy74:
#line 583 "input_custom_mjson.re"
            {
                token = TOK_TRUE;
                goto done;
            }
#line 1944 "input_custom_mjson.c"
yy75:
            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 yy79;
                default: goto yy28;
            }
yy76:
            yyaccept = 4;
            YYSKIP();
            YYBACKUP();
            yych = YYPEEK();
            switch (yych) {
                case 0x00: goto yy69;
                case '*': goto yy54;
                default: goto yy36;
            }
yy77:
            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 yy16;
                default: goto yy78;
            }
yy78:
#line 588 "input_custom_mjson.re"
            {
                token = TOK_FALSE;
                goto done;
            }
#line 2058 "input_custom_mjson.c"
yy79:
            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 yy50;
                default: goto yy28;
            }
        }
#line 627 "input_custom_mjson.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 2208 "input_custom_mjson.c"
        {
            YYCTYPE yych;
            yych = YYPEEK();
            switch (yych) {
                case 0x00: goto yy81;
                case '"': goto yy85;
                case '\\': goto yy86;
                default: goto yy83;
            }
yy81:
            YYSKIP();
yy82:
#line 811 "input_custom_mjson.re"
            { 
                assert(!"reachable");
            }
#line 2225 "input_custom_mjson.c"
yy83:
            YYSKIP();
            yych = YYPEEK();
            switch (yych) {
                case 0x00:
                case '"':
                case '\\': goto yy84;
                default: goto yy83;
            }
yy84:
#line 746 "input_custom_mjson.re"
            {
                str_dst = (uint8_t*)parsectx_allocate_output(context, c - s);
                
                if (!str_dst) return 0;
                
                memcpy(str_dst, s, c - s);

                continue;
            }
#line 2246 "input_custom_mjson.c"
yy85:
            YYSKIP();
#line 802 "input_custom_mjson.re"
            {
                bdata->val_u32 = context->bjson - (uint8_t*)(bdata + 1);
                *context->bjson++ = 0;
                parsectx_align4_output(context);
                parsectx_next_token(context);

                return 1;
            }
#line 2258 "input_custom_mjson.c"
yy86:
            YYSKIP();
            YYBACKUP();
            yych = YYPEEK();
            switch (yych) {
                case '"':
                case '/':
                case '\\':
                case 'b':
                case 'f':
                case 'n':
                case 'r':
                case 't': goto yy87;
                case 'u': goto yy88;
                default: goto yy82;
            }
yy87:
            YYSKIP();
#line 757 "input_custom_mjson.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 2308 "input_custom_mjson.c"
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':
                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 yy90;
                default: goto yy89;
            }
yy89:
            YYRESTORE();
            goto yy82;
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':
                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 yy91;
                default: goto yy89;
            }
yy91:
            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 yy92;
                default: goto yy89;
            }
yy92:
            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 yy93;
                default: goto yy89;
            }
yy93:
            YYSKIP();
#line 788 "input_custom_mjson.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 2440 "input_custom_mjson.c"
        }
#line 814 "input_custom_mjson.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;
}
input_custom_mjson.re:491:26: warning: escape has no effect: '\/' [-Wuseless-escape]
input_custom_mjson.re:491:50: warning: escape has no effect: '\/' [-Wuseless-escape]
input_custom_mjson.re:491:77: warning: escape has no effect: '\/' [-Wuseless-escape]
