From: Ulya Trofimovich Date: Sun, 18 Jan 2015 13:47:51 +0000 (+0000) Subject: Added tests for "--input custom". X-Git-Tag: 0.14~14 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=46b9058de058ede07cff8c503dace53261e00105;p=re2c Added tests for "--input custom". 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. --- diff --git a/re2c/run_tests.sh.in b/re2c/run_tests.sh.in index 2ab4544f..9b6ad50c 100644 --- a/re2c/run_tests.sh.in +++ b/re2c/run_tests.sh.in @@ -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 index 00000000..7e31b807 --- /dev/null +++ b/re2c/test/input_custom_default.--input(custom).c @@ -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 "" +{ + 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 "" +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 "" +} +#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 index 00000000..933d7666 --- /dev/null +++ b/re2c/test/input_custom_default.--input(custom).re @@ -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 index 00000000..9e043915 --- /dev/null +++ b/re2c/test/input_custom_fgetc.--input(custom).c @@ -0,0 +1,184 @@ +/* Generated by re2c */ +#line 1 "input_custom_fgetc.--input(custom).re" +#include + +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 "" +{ + 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 "" +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 "" +} +#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 index 00000000..3116479a --- /dev/null +++ b/re2c/test/input_custom_fgetc.--input(custom).re @@ -0,0 +1,43 @@ +#include + +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 index 00000000..d40a354c --- /dev/null +++ b/re2c/test/input_custom_istringstream.--input(custom).c @@ -0,0 +1,168 @@ +/* Generated by re2c */ +#line 1 "input_custom_istringstream.--input(custom).re" +#include + +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 "" +{ + 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 "" +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 "" +} +#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 index 00000000..76197a2e --- /dev/null +++ b/re2c/test/input_custom_istringstream.--input(custom).re @@ -0,0 +1,27 @@ +#include + +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 index 00000000..3c230124 --- /dev/null +++ b/re2c/test/input_custom_mjson.--input(custom).c @@ -0,0 +1,2881 @@ +/* Generated by re2c */ +#line 1 "input_custom_mjson.--input(custom).re" +#include +#include +#include +#include +#include + +/** + * 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 + +#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 "" + { + 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 "" +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 "" +yy6: + YYSKIP (); +#line 527 "input_custom_mjson.--input(custom).re" + { + token = TOK_LEFT_CURLY_BRACKET; + goto done; + } +#line 614 "" +yy8: + YYSKIP (); +#line 532 "input_custom_mjson.--input(custom).re" + { + token = TOK_RIGHT_CURLY_BRACKET; + goto done; + } +#line 622 "" +yy10: + YYSKIP (); +#line 537 "input_custom_mjson.--input(custom).re" + { + token = TOK_LEFT_BRACKET; + goto done; + } +#line 630 "" +yy12: + YYSKIP (); +#line 542 "input_custom_mjson.--input(custom).re" + { + token = TOK_RIGHT_BRACKET; + goto done; + } +#line 638 "" +yy14: + YYSKIP (); +#line 547 "input_custom_mjson.--input(custom).re" + { + token = TOK_COLON; + goto done; + } +#line 646 "" +yy16: + YYSKIP (); +#line 552 "input_custom_mjson.--input(custom).re" + { + token = TOK_EQUAL; + goto done; + } +#line 654 "" +yy18: + YYSKIP (); +#line 557 "input_custom_mjson.--input(custom).re" + { + token = TOK_COMMA; + goto done; + } +#line 662 "" +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 "" +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 "" +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 "" +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 "" +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 "" +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 "" +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 "" +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 "" +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 "" +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 "" +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 "" +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 "" +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 "" +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 "" +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 "" + { + 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 "" +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 "" +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 "" +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 "" +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 "" +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 index 00000000..53d0d592 --- /dev/null +++ b/re2c/test/input_custom_mjson.--input(custom).re @@ -0,0 +1,975 @@ +#include +#include +#include +#include +#include + +/** + * 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 + +#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; +}