From b72a1e91b9565251a9775bb4e7c884bfde76c78b Mon Sep 17 00:00:00 2001 From: Kray-G Date: Thu, 7 Nov 2019 16:43:22 +0900 Subject: [PATCH 1/4] issue #22: added my own json parser. --- .gitignore | 2 + Makefile.msc | 9 +- kccrt/include/_builtin.h | 6 +- kccrt/include/kcc/json.h | 87 +++ kccrt/libsrc/kcc/json.y | 1007 ++++++++++++++++++++++++++ samples/json.c | 15 + samples/sample.json | 14 + utility/myacc.c | 1466 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 2604 insertions(+), 2 deletions(-) create mode 100644 kccrt/include/kcc/json.h create mode 100644 kccrt/libsrc/kcc/json.y create mode 100644 samples/json.c create mode 100644 samples/sample.json create mode 100644 utility/myacc.c diff --git a/.gitignore b/.gitignore index 9e82379..41787f7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ test.c result.txt timeit.dat sample.db +kccrt/libsrc/kcc/ext_json.c +json.output diff --git a/Makefile.msc b/Makefile.msc index b66a2bb..5e89f9d 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -90,7 +90,7 @@ EXTOBJ = \ .SUFFIXES : .SUFFIXES : .c .obj -all: libs $(NAME).exe $(NAME)bltin.dll $(NAME)jit.dll kccext.dll +all: ext_json.c libs $(NAME).exe $(NAME)bltin.dll $(NAME)jit.dll kccext.dll test: all test\test-8cc\test.cmd @@ -104,6 +104,13 @@ test: all test\test-picoc\test.cmd -j test\test-picoc\csmith.cmd -j +ext_json.c: myacc.exe kccrt\libsrc\kcc\json.y + myacc -y __json_yy -Y JSON_YY kccrt\libsrc\kcc\json.y + move /y y.tab.c kccrt\libsrc\kcc\ext_json.c + +myacc.exe: + $(CC) $(CFLAGS) /Femyacc.exe utility\myacc.c + libs: onig_s.lib onig_s.lib: diff --git a/kccrt/include/_builtin.h b/kccrt/include/_builtin.h index 68d3b47..52dddea 100644 --- a/kccrt/include/_builtin.h +++ b/kccrt/include/_builtin.h @@ -1,10 +1,14 @@ #ifndef KCC__BUILTIN_H #define KCC__BUILTIN_H -#define NULL ((void*)0) typedef unsigned long long uint64_t; +#if defined(__KCC__) typedef unsigned long size_t; typedef int ptrdiff_t; +#endif +#if !defined(NULL) +#define NULL ((void*)0) +#endif void __kcc_builtin_onstart(void); void __kcc_builtin_onexit(void); diff --git a/kccrt/include/kcc/json.h b/kccrt/include/kcc/json.h new file mode 100644 index 0000000..0127b59 --- /dev/null +++ b/kccrt/include/kcc/json.h @@ -0,0 +1,87 @@ +#ifndef JSON_H +#define JSON_H + +#include <_ext.h> +#include +#include +#include + +typedef enum { + JSON_UNKNWON, + JSON_OBJECT, + JSON_ARRAY, + JSON_PAIR, + JSON_TEXT, + JSON_BOOLEAN, + JSON_INTEGER, + JSON_REAL, + JSON_NULL +} __json_type_t; + +struct __json_object_; + +typedef union __json_value_ { + int b; /* boolean */ + int64_t i; /* integer */ + double d; /* real */ + string_t t; /* text */ + struct __json_object_ *o; /* object/array */ +} __json_value_t; + +typedef struct __json_object_ { + __json_type_t type; + struct __json_object_ *link; /* for object management */ + struct __json_object_ *root; /* easy to access to the root */ + struct __json_object_ *mgr; /* easy to access to the manager */ + + struct __json_object_ *prop; /* next element of object */ + struct __json_object_ *lobj; /* last element of object */ + struct __json_object_ *next; /* next element of array */ + struct __json_object_ *lary; /* last element of array */ + + string_t key; /* key if exists */ + __json_value_t value; /* value of json object */ +} __json_object_t; + +extern __json_object_t *__json_parse(const char *str); +extern __json_object_t *__json_parse_file(const char *filename); +extern const char *__json_error_message(void); + +extern __json_object_t *__json_set_top(__json_object_t *j); +extern __json_object_t *__json_gen_object(void); +extern __json_object_t *__json_append_pair(__json_object_t *j1, __json_object_t *j2); +extern __json_object_t *__json_gen_pair(__json_object_t *j1, __json_object_t *j2); +extern __json_object_t *__json_gen_array(void); +extern __json_object_t *__json_append_value(__json_object_t *j1, __json_object_t *j2); +extern __json_object_t *__json_gen_double_object(double d); +extern __json_object_t *__json_gen_integer_object(int64_t i); +extern __json_object_t *__json_gen_text_object(string_t s); +extern __json_object_t *__json_make_boolean(int); +extern __json_object_t *__json_make_null(void); + +/* extension of calculation */ +extern __json_object_t *__json_bit_or(__json_object_t *j1, __json_object_t *j2); +extern __json_object_t *__json_bit_xor(__json_object_t *j1, __json_object_t *j2); +extern __json_object_t *__json_bit_and(__json_object_t *j1, __json_object_t *j2); +extern __json_object_t *__json_add(__json_object_t *j1, __json_object_t *j2); +extern __json_object_t *__json_sub(__json_object_t *j1, __json_object_t *j2); +extern __json_object_t *__json_mul(__json_object_t *j1, __json_object_t *j2); +extern __json_object_t *__json_div(__json_object_t *j1, __json_object_t *j2); +extern __json_object_t *__json_mod(__json_object_t *j1, __json_object_t *j2); +extern __json_object_t *__json_neg(__json_object_t *j); + +typedef __json_object_t json_object_t; +#define json_yyin __json_yyin +#define json_parse __json_parse +#define json_parse_file __json_parse_file +#define json_pretty_print __json_pretty_print +#define json_free_all __json_free_all +#define json_error_message __json_error_message + +#ifndef KCC_NO_IMPORT +#if defined(__KCC_JIT__) || defined(__KCC__) +#include <../libsrc/kcc/ext_json.c> +#endif +#endif + +#endif /* JSON_H */ diff --git a/kccrt/libsrc/kcc/json.y b/kccrt/libsrc/kcc/json.y new file mode 100644 index 0000000..b7d471b --- /dev/null +++ b/kccrt/libsrc/kcc/json.y @@ -0,0 +1,1007 @@ +%{ +#include +#include +#include +#include + +int __json_yylex(); +typedef union __json_yyin_ { + FILE *fp; + const char *str; +} __json_yyin_t; +__json_yyin_t __json_yyin; +%} + +%union { + __json_object_t *object; +} + +%type JsonStart +%type JsonMaterial +%type JsonObject +%type JsonArray +%type JsonMembers +%type JsonValue +%type JsonPair +%type JsonElements +%type JsonLogicalOrExpression +%type JsonLogicalAndExpression +%type JsonBitOrExpression +%type JsonBitXorExpression +%type JsonBitAndExpression +%type JsonExpression +%type JsonTerm +%type JsonPrefixExpression +%type JsonFactor + +%token JSON_OP_LOR +%token JSON_OP_LAND +%token JSON_OP_OR +%token JSON_OP_XOR +%token JSON_OP_AND +%token JSON_OP_ADD +%token JSON_OP_SUB +%token JSON_OP_MUL +%token JSON_OP_DIV +%token JSON_OP_MOD +%token JSON_TOKEN_OBEG +%token JSON_TOKEN_OEND +%token JSON_TOKEN_ABEG +%token JSON_TOKEN_AEND +%token JSON_TOKEN_LB +%token JSON_TOKEN_RB +%token JSON_TOKEN_LP +%token JSON_TOKEN_RP +%token JSON_TOKEN_COMMA +%token JSON_TOKEN_COLON +%token JSON_TOKEN_STR +%token JSON_TOKEN_INT +%token JSON_TOKEN_DBL +%token JSON_TOKEN_NULL +%token JSON_TOKEN_TRUE +%token JSON_TOKEN_FALSE +%token JSON_TOKEN_ERROR +%token JSON_TOKEN_END + +%start JsonStart + +%% + +JsonStart + : JsonMaterial { $$ = __json_set_top($1); } + ; + +JsonMaterial + : JsonObject + | JsonArray + ; + +JsonObject + : JSON_TOKEN_OBEG JSON_TOKEN_OEND { $$ = __json_gen_object(); } + | JSON_TOKEN_OBEG JsonMembers JsonComma_opt JSON_TOKEN_OEND { $$ = $2; } + ; + +JsonMembers + : JsonPair { $$ = __json_append_pair(NULL, $1); } + | JsonMembers JSON_TOKEN_COMMA JsonPair { $$ = __json_append_pair($1, $3); } + ; + +JsonPair + : JSON_TOKEN_STR JSON_TOKEN_COLON JsonValue { $$ = __json_gen_pair($1, $3); } + ; + +JsonArray + : JSON_TOKEN_ABEG JSON_TOKEN_AEND { $$ = __json_gen_array(); } + | JSON_TOKEN_ABEG JsonElements JsonComma_opt JSON_TOKEN_AEND { $$ = $2; } + ; + +JsonElements + : JsonValue { $$ = __json_append_value(NULL, $1); } + | JsonElements JSON_TOKEN_COMMA JsonValue { $$ = __json_append_value($1, $3); } + ; + +JsonComma_opt + : + | JSON_TOKEN_COMMA + ; + +JsonValue + : JsonLogicalOrExpression + ; + +JsonLogicalOrExpression + : JsonLogicalAndExpression + | JsonLogicalOrExpression JSON_OP_LOR JsonLogicalAndExpression { if ($1) { $$ = $1; } else if ($3) { $$ = $3; } else { $$ = __json_make_null(); } } + ; + +JsonLogicalAndExpression + : JsonBitOrExpression + | JsonLogicalAndExpression JSON_OP_LAND JsonBitOrExpression { if (!$1) { $$ = __json_make_null(); } else { $$ = $3; } } + ; + +JsonBitOrExpression + : JsonBitXorExpression + | JsonBitOrExpression JSON_OP_OR JsonBitXorExpression { $$ = __json_bit_or($1, $3); } + ; + +JsonBitXorExpression + : JsonBitAndExpression + | JsonBitXorExpression JSON_OP_XOR JsonBitAndExpression { $$ = __json_bit_xor($1, $3); } + ; + +JsonBitAndExpression + : JsonExpression + | JsonBitAndExpression JSON_OP_AND JsonExpression { $$ = __json_bit_and($1, $3); } + ; + +JsonExpression + : JsonTerm + | JsonExpression JSON_OP_ADD JsonTerm { $$ = __json_add($1, $3); } + | JsonExpression JSON_OP_SUB JsonTerm { $$ = __json_sub($1, $3); } + ; + +JsonTerm + : JsonPrefixExpression + | JsonTerm JSON_OP_MUL JsonPrefixExpression { $$ = __json_mul($1, $3); } + | JsonTerm JSON_OP_DIV JsonPrefixExpression { $$ = __json_div($1, $3); } + | JsonTerm JSON_OP_MOD JsonPrefixExpression { $$ = __json_mod($1, $3); } + ; + +JsonPrefixExpression + : JsonFactor + | JSON_OP_ADD JsonFactor { $$ = $2; } + | JSON_OP_SUB JsonFactor { $$ = __json_neg($2); } + ; + +JsonFactor + : JsonMaterial + | JSON_TOKEN_STR + | JSON_TOKEN_INT + | JSON_TOKEN_DBL + | JSON_TOKEN_NULL { $$ = __json_make_null(); } + | JSON_TOKEN_TRUE { $$ = __json_make_boolean(1); } + | JSON_TOKEN_FALSE { $$ = __json_make_boolean(0); } + | JSON_TOKEN_LB JsonValue JSON_TOKEN_RB { $$ = $2; } + ; + +%% + +static int __g_json_parser_ch = 0; +static string_t __json_string_alloc(const char *s); +static void __json_string_free(string_t *s); +static void (*__json_lex_next)(void); + +static int __json_status = 0; +static int __json_line = 1; +static int __json_pos = 0; +static int __json_object_allocated = 0; +static int __json_string_allocated = 0; +static __json_object_t *__json_mgr = NULL; +static __json_object_t *__json_root = NULL; +static void __json_pretty_print(__json_object_t *j, int indent, int comma, int contd); + +void __json_setup(void) +{ + __json_status = 0; + __json_line = 1; + __json_pos = 0; + __json_mgr = NULL; + __json_root = NULL; + __json_lex_next(); +} + +void __json_lex_next_from_string(void) +{ + if (__g_json_parser_ch != EOF) { + __g_json_parser_ch = *__json_yyin.str++; + ++__json_pos; + if (__g_json_parser_ch == '\n') { + ++__json_line; + __json_pos = 0; + } + } +} + +void __json_lex_next_from_file(void) +{ + __g_json_parser_ch = fgetc(__json_yyin.fp); + ++__json_pos; + if (__g_json_parser_ch == EOF) { + __g_json_parser_ch = 0; + } + if (__g_json_parser_ch == '\n') { + ++__json_line; + __json_pos = 0; + } +} + +int __json_is_whitespace(void) +{ + return + __g_json_parser_ch == ' ' || + __g_json_parser_ch == '\t' || + __g_json_parser_ch == '\r' || + __g_json_parser_ch == '\n' + ; +} + +int __json_is_number(void) +{ + return '0' <= __g_json_parser_ch && __g_json_parser_ch <= '9'; +} + +int __json_is_oct_number(void) +{ + return '0' <= __g_json_parser_ch && __g_json_parser_ch <= '7'; +} + +int __json_is_hex_number(void) +{ + return + ('0' <= __g_json_parser_ch && __g_json_parser_ch <= '9') || + ('a' <= __g_json_parser_ch && __g_json_parser_ch <= 'f') || + ('A' <= __g_json_parser_ch && __g_json_parser_ch <= 'F') + ; +} + +int __json_lex_make_number(void) +{ + int is_real = 0; + int is_hex = 0; + int is_oct = 0; + int is_zero = __g_json_parser_ch == '0'; + char str[2] = { __g_json_parser_ch, 0 }; + string_t s = __json_string_alloc(str); + + __json_lex_next(); + if (is_zero) { + is_oct = 1; + } else if (__g_json_parser_ch == '.') { + str[0] = __g_json_parser_ch; + string_append_cstr(&s, str); + __json_lex_next(); + is_real = 1; + } else if (__g_json_parser_ch == 'x') { + str[0] = __g_json_parser_ch; + string_append_cstr(&s, str); + __json_lex_next(); + is_hex = 1; + } + + if (is_real) { + while (__json_is_number()) { + str[0] = __g_json_parser_ch; + string_append_cstr(&s, str); + __json_lex_next(); + } + __json_yylval.object = __json_gen_double_object(strtod(s.cstr, NULL)); + __json_string_free(&s); + return JSON_TOKEN_DBL; + } else if (is_hex) { + while (__json_is_hex_number()) { + str[0] = __g_json_parser_ch; + string_append_cstr(&s, str); + __json_lex_next(); + } + __json_yylval.object = __json_gen_integer_object(strtoll(s.cstr, NULL, 16)); + __json_string_free(&s); + return JSON_TOKEN_INT; + } else if (is_oct) { + while (__json_is_oct_number()) { + str[0] = __g_json_parser_ch; + string_append_cstr(&s, str); + __json_lex_next(); + } + __json_yylval.object = __json_gen_integer_object(strtoll(s.cstr, NULL, 8)); + __json_string_free(&s); + return JSON_TOKEN_INT; + } + + while (__json_is_number()) { + str[0] = __g_json_parser_ch; + string_append_cstr(&s, str); + __json_lex_next(); + } + __json_yylval.object = __json_gen_integer_object(strtoll(s.cstr, NULL, 10)); + __json_string_free(&s); + return JSON_TOKEN_INT; +} + +int __json_is_begin_keyword(void) +{ + return + __g_json_parser_ch == '_' || + ('a' <= __g_json_parser_ch && __g_json_parser_ch <= 'z') || + ('A' <= __g_json_parser_ch && __g_json_parser_ch <= 'Z') + ; +} + +int __json_lex_make_keyword(void) +{ + char str[2] = { __g_json_parser_ch, 0 }; + string_t s = __json_string_alloc(str); + + __json_lex_next(); + while (__json_is_begin_keyword() || __json_is_number()) { + str[0] = __g_json_parser_ch; + string_append_cstr(&s, str); + __json_lex_next(); + } + + if (!strcmp(s.cstr, "null")) { + __json_string_free(&s); + return JSON_TOKEN_NULL; + } else if (!strcmp(s.cstr, "true")) { + __json_string_free(&s); + return JSON_TOKEN_TRUE; + } else if (!strcmp(s.cstr, "false")) { + __json_string_free(&s); + return JSON_TOKEN_FALSE; + } + + __json_yylval.object = __json_gen_text_object(s); + return JSON_TOKEN_STR; +} + +int __json_lex_make_string() +{ + if (__g_json_parser_ch == '"') { + __json_lex_next(); + } + if (__g_json_parser_ch == '"') { + __json_lex_next(); + __json_yylval.object = __json_gen_text_object(__json_string_alloc("")); + return JSON_TOKEN_STR; + } + + char str[2] = { __g_json_parser_ch, 0 }; + string_t s = __json_string_alloc(str); + + __json_lex_next(); + while (__g_json_parser_ch != '"') { + if (__g_json_parser_ch == '\\') { + __json_lex_next(); + } + str[0] = __g_json_parser_ch; + string_append_cstr(&s, str); + __json_lex_next(); + } + + __json_yylval.object = __json_gen_text_object(s); + __json_lex_next(); + return JSON_TOKEN_STR; +} + +int __json_yylex_impl() +{ + while (__json_is_whitespace()) { + __json_lex_next(); + } + if (!__g_json_parser_ch) { + return 0; + } + + if (__json_is_number()) { + return __json_lex_make_number(); + } else if (__json_is_begin_keyword()) { + return __json_lex_make_keyword(); + } + switch (__g_json_parser_ch) { + case '{': + __json_lex_next(); + return JSON_TOKEN_OBEG; + case '}': + __json_lex_next(); + return JSON_TOKEN_OEND; + case '[': + __json_lex_next(); + return JSON_TOKEN_ABEG; + case ']': + __json_lex_next(); + return JSON_TOKEN_AEND; + case '(': + __json_lex_next(); + return JSON_TOKEN_LB; + case ')': + __json_lex_next(); + return JSON_TOKEN_RB; + case ',': + __json_lex_next(); + return JSON_TOKEN_COMMA; + case ':': + __json_lex_next(); + return JSON_TOKEN_COLON; + case '|': + __json_lex_next(); + if (__g_json_parser_ch == '|') { + __json_lex_next(); + return JSON_OP_LOR; + } + return JSON_OP_OR; + case '^': + __json_lex_next(); + return JSON_OP_XOR; + case '&': + __json_lex_next(); + if (__g_json_parser_ch == '&') { + __json_lex_next(); + return JSON_OP_LAND; + } + return JSON_OP_AND; + case '+': + __json_lex_next(); + return JSON_OP_ADD; + case '-': + __json_lex_next(); + return JSON_OP_SUB; + case '*': + __json_lex_next(); + return JSON_OP_MUL; + case '/': + __json_lex_next(); + return JSON_OP_DIV; + case '%': + __json_lex_next(); + return JSON_OP_MOD; + case '"': + __json_lex_make_string(); + return JSON_TOKEN_STR; + } + + return JSON_TOKEN_ERROR; +} + +int __json_yylex() +{ + #ifndef JSON_PARSER_DEBUG + return __json_yylex_impl(); + #else + int r = __json_yylex_impl(); + switch (r) { + case JSON_OP_LOR: + printf("%%input JSON_OP_LOR\n"); + break; + case JSON_OP_LAND: + printf("%%input JSON_OP_LAND\n"); + break; + case JSON_OP_OR: + printf("%%input JSON_OP_OR\n"); + break; + case JSON_OP_XOR: + printf("%%input JSON_OP_XOR\n"); + break; + case JSON_OP_AND: + printf("%%input JSON_OP_AND\n"); + break; + case JSON_OP_ADD: + printf("%%input JSON_OP_ADD\n"); + break; + case JSON_OP_SUB: + printf("%%input JSON_OP_SUB\n"); + break; + case JSON_OP_MUL: + printf("%%input JSON_OP_MUL\n"); + break; + case JSON_OP_DIV: + printf("%%input JSON_OP_DIV\n"); + break; + case JSON_OP_MOD: + printf("%%input JSON_OP_MOD\n"); + break; + case JSON_TOKEN_OBEG: + printf("%%input JSON_TOKEN_OBEG\n"); + break; + case JSON_TOKEN_OEND: + printf("%%input JSON_TOKEN_OEND\n"); + break; + case JSON_TOKEN_ABEG: + printf("%%input JSON_TOKEN_ABEG\n"); + break; + case JSON_TOKEN_AEND: + printf("%%input JSON_TOKEN_AEND\n"); + break; + case JSON_TOKEN_LB: + printf("%%input JSON_TOKEN_LB\n"); + break; + case JSON_TOKEN_RB: + printf("%%input JSON_TOKEN_RB\n"); + break; + case JSON_TOKEN_LP: + printf("%%input JSON_TOKEN_LP\n"); + break; + case JSON_TOKEN_RP: + printf("%%input JSON_TOKEN_RP\n"); + break; + case JSON_TOKEN_COMMA: + printf("%%input JSON_TOKEN_COMMA\n"); + break; + case JSON_TOKEN_COLON: + printf("%%input JSON_TOKEN_COLON\n"); + break; + case JSON_TOKEN_STR: + printf("%%input JSON_TOKEN_STR: %s\n", __json_yylval.object->value.t.cstr); + break; + case JSON_TOKEN_INT: + printf("%%input JSON_TOKEN_INT: %d\n", __json_yylval.object->value.i); + break; + case JSON_TOKEN_DBL: + printf("%%input JSON_TOKEN_DBL: %f\n", __json_yylval.object->value.d); + break; + case JSON_TOKEN_NULL: + printf("%%input JSON_TOKEN_NULL\n"); + break; + case JSON_TOKEN_TRUE: + printf("%%input JSON_TOKEN_TRUE\n"); + break; + case JSON_TOKEN_FALSE: + printf("%%input JSON_TOKEN_FALSE\n"); + break; + case JSON_TOKEN_ERROR: + printf("%%input JSON_TOKEN_ERROR\n"); + break; + case JSON_TOKEN_END: + printf("%%input JSON_TOKEN_END\n"); + break; + } + return r; + #endif +} + +static string_t __json_string_alloc(const char *s) +{ + ++__json_string_allocated; + return string_init(s); +} + +static void __json_string_free(string_t *s) +{ + string_free(s); + --__json_string_allocated; +} + +static __json_object_t *__json_alloc(__json_type_t type) +{ + __json_object_t * j = (__json_object_t *)calloc(1, sizeof(__json_object_t)); + if (!__json_mgr) { + __json_mgr = j; + } else { + j->link = __json_mgr->link; + __json_mgr->link = j; + } + j->type = type; + j->mgr = __json_mgr; + ++__json_object_allocated; + return j; +} + +static void __json_free_one(__json_object_t *j) +{ + if (!j) { + return; + } + + switch (j->type) { + case JSON_TEXT: + __json_string_free(&j->value.t); + break; + case JSON_PAIR: + __json_string_free(&j->key); + break; + } + --__json_object_allocated; + free(j); +} + +static void __json_free_all(__json_object_t *j) +{ + if (!j) { + return; + } + + __json_object_t *p = j->mgr ? j->mgr : j; + while (p) { + __json_object_t *n = p->link; + __json_free_one(p); + p = n; + } + #ifdef JSON_PARSER_DEBUG + printf("[freed] %d elems and %d strings\n", __json_object_allocated, __json_string_allocated); + #endif + + assert(__json_object_allocated == 0); + assert(__json_string_allocated == 0); + __json_mgr = NULL; +} + +static void __json_print_indent(int indent) +{ + if (indent > 0) { + for (int i = 0; i < indent; ++i) { + printf(" "); + } + } +} + +static void __json_pretty_print(__json_object_t *j, int indent, int comma, int contd) +{ + __json_object_t *n; + int cr = 1; + if (!contd) { + __json_print_indent(indent); + } + switch (j->type) { + case JSON_UNKNWON: + printf("(unknown)"); + break; + case JSON_OBJECT: + printf("{"); + n = j->prop; + if (n) { + printf("\n"); + while (n) { + __json_object_t *prop = n->prop; + __json_pretty_print(n, indent+1, prop ? 1 : 0, 0); + n = prop; + } + __json_print_indent(indent); + } + printf("}"); + break; + case JSON_ARRAY: + printf("["); + n = j->next; + if (n) { + printf("\n"); + while (n) { + __json_object_t *next = n->next; + __json_pretty_print(n, indent+1, next ? 1 : 0, 0); + n = next; + } + __json_print_indent(indent); + } + printf("]"); + break; + case JSON_PAIR: + printf("\"%s\": ", j->key.cstr); + __json_pretty_print(j->value.o, indent, comma, 1); + cr = 0; + comma = 0; + break; + case JSON_TEXT: + printf("\"%s\"", j->value.t.cstr); + break; + case JSON_BOOLEAN: + printf("%s", j->value.b ? "true" : "false"); + break; + case JSON_INTEGER: + printf("%d", j->value.i); + break; + case JSON_REAL: + printf("%f", j->value.d); + break; + case JSON_NULL: + printf("null"); + break; + } + if (comma) { + printf(","); + } + if (cr) { + printf("\n"); + } +} + +__json_object_t *__json_set_top(__json_object_t *j) +{ + __json_object_t *p = j->mgr; + while (p) { + p->root = j; + p = p->link; + } + __json_root = j; + #ifdef JSON_PARSER_DEBUG + printf("[constructed] %d elems and %d strings\n", __json_object_allocated, __json_string_allocated); + #endif + return j; +} + +__json_object_t *__json_gen_object(void) +{ + return __json_alloc(JSON_OBJECT); +} + +__json_object_t *__json_append_pair(__json_object_t *j1, __json_object_t *j2) +{ + if (!j1) { + j1 = __json_gen_object(); + } + assert(j1->type == JSON_OBJECT); + assert(j2->type == JSON_PAIR); + if (j1->lobj) { + j1->lobj->prop = j2; + j1->lobj = j2; + } else { + j1->prop = j1->lobj = j2; + } + return j1; +} + +__json_object_t *__json_gen_pair(__json_object_t *j1, __json_object_t *j2) +{ + if (j1->type == JSON_TEXT) { + j1->type = JSON_PAIR; + j1->key = __json_string_alloc(j1->value.t.cstr); + __json_string_free(&(j1->value.t)); + j1->value.o = j2; + } + return j1; +} + +__json_object_t *__json_gen_array(void) +{ + return __json_alloc(JSON_ARRAY); +} + +__json_object_t *__json_append_value(__json_object_t *j1, __json_object_t *j2) +{ + if (!j1) { + j1 = __json_gen_array(); + } + assert(j1->type == JSON_ARRAY); + if (j1->lary) { + j1->lary->next = j2; + j1->lary = j2; + } else { + j1->next = j1->lary = j2; + } + return j1; +} + +__json_object_t *__json_bit_or(__json_object_t *j1, __json_object_t *j2) +{ + if (j1->type == JSON_INTEGER && j2->type == JSON_INTEGER) { + j1->value.i |= j2->value.i; + } + return j1; +} + +__json_object_t *__json_bit_xor(__json_object_t *j1, __json_object_t *j2) +{ + if (j1->type == JSON_INTEGER && j2->type == JSON_INTEGER) { + j1->value.i ^= j2->value.i; + } + return j1; +} + +__json_object_t *__json_bit_and(__json_object_t *j1, __json_object_t *j2) +{ + if (j1->type == JSON_INTEGER && j2->type == JSON_INTEGER) { + j1->value.i &= j2->value.i; + } + return j1; +} + +__json_object_t *__json_add(__json_object_t *j1, __json_object_t *j2) +{ + switch (j1->type) { + case JSON_INTEGER: + switch (j2->type) { + case JSON_INTEGER: + j1->value.i = j1->value.i + j2->value.i; + break; + case JSON_REAL: + j1->type = JSON_REAL; + j1->value.d = (double)j1->value.i + j2->value.d; + break; + } + break; + case JSON_REAL: + switch (j2->type) { + case JSON_INTEGER: + j1->value.d = j1->value.d + (double)j2->value.i; + break; + case JSON_REAL: + j1->value.d = j1->value.d + j2->value.d; + break; + } + break; + } + return j1; +} + +__json_object_t *__json_sub(__json_object_t *j1, __json_object_t *j2) +{ + switch (j1->type) { + case JSON_INTEGER: + switch (j2->type) { + case JSON_INTEGER: + j1->value.i = j1->value.i - j2->value.i; + break; + case JSON_REAL: + j1->type = JSON_REAL; + j1->value.d = (double)j1->value.i - j2->value.d; + break; + } + break; + case JSON_REAL: + switch (j2->type) { + case JSON_INTEGER: + j1->value.d = j1->value.d - (double)j2->value.i; + break; + case JSON_REAL: + j1->value.d = j1->value.d - j2->value.d; + break; + } + break; + } + return j1; +} + +__json_object_t *__json_mul(__json_object_t *j1, __json_object_t *j2) +{ + switch (j1->type) { + case JSON_INTEGER: + switch (j2->type) { + case JSON_INTEGER: + j1->value.i = j1->value.i * j2->value.i; + break; + case JSON_REAL: + j1->type = JSON_REAL; + j1->value.d = (double)j1->value.i * j2->value.d; + break; + } + break; + case JSON_REAL: + switch (j2->type) { + case JSON_INTEGER: + j1->value.d = j1->value.d * (double)j2->value.i; + break; + case JSON_REAL: + j1->value.d = j1->value.d * j2->value.d; + break; + } + break; + } + return j1; +} + +__json_object_t *__json_div(__json_object_t *j1, __json_object_t *j2) +{ + switch (j1->type) { + case JSON_INTEGER: + switch (j2->type) { + case JSON_INTEGER: + j1->value.i = j1->value.i / j2->value.i; + break; + case JSON_REAL: + j1->type = JSON_REAL; + j1->value.d = (double)j1->value.i / j2->value.d; + break; + } + break; + case JSON_REAL: + switch (j2->type) { + case JSON_INTEGER: + j1->value.d = j1->value.d / (double)j2->value.i; + break; + case JSON_REAL: + j1->value.d = j1->value.d / j2->value.d; + break; + } + break; + } + return j1; +} + +__json_object_t *__json_mod(__json_object_t *j1, __json_object_t *j2) +{ + switch (j1->type) { + case JSON_INTEGER: + switch (j2->type) { + case JSON_INTEGER: + j1->value.i %= j2->value.i; + break; + case JSON_REAL: + j1->type = JSON_REAL; + j1->value.d = fmod((double)j1->value.i, j2->value.d); + break; + } + break; + case JSON_REAL: + switch (j2->type) { + case JSON_INTEGER: + j1->value.d = fmod(j1->value.d, (double)j2->value.i); + break; + case JSON_REAL: + j1->value.d = fmod(j1->value.d, j2->value.d); + break; + } + break; + } + return j1; +} + +__json_object_t *__json_neg(__json_object_t *j) +{ + switch (j->type) { + case JSON_INTEGER: + j->value.i = -j->value.i; + break; + case JSON_REAL: + j->value.d = -j->value.d; + break; + } + return j; +} + +__json_object_t *__json_gen_double_object(double d) +{ + __json_object_t *j = __json_alloc(JSON_REAL); + j->value.d = d; + return j; +} + +__json_object_t *__json_gen_integer_object(int64_t i) +{ + __json_object_t *j = __json_alloc(JSON_INTEGER); + j->value.i = i; + return j; +} + +__json_object_t *__json_gen_text_object(string_t s) +{ + __json_object_t *j = __json_alloc(JSON_TEXT); + j->value.t = s; + return j; +} + +__json_object_t *__json_make_boolean(int i) +{ + __json_object_t *j = __json_alloc(JSON_BOOLEAN); + j->value.b = i; + return j; +} + +__json_object_t *__json_make_null(void) +{ + return __json_alloc(JSON_NULL); +} + +__json_object_t *__json_parse(const char *str) +{ + __json_lex_next = __json_lex_next_from_string; + __json_yyin.str = str; + __json_setup(); + __json_status = __json_yyparse(); + if (__json_status == 0) { + return __json_root; + } + __json_free_all(__json_mgr); + return NULL; +} + +__json_object_t *__json_parse_file(const char *filename) +{ + __json_lex_next = __json_lex_next_from_file; + __json_yyin.fp = fopen(filename, "r"); + if (__json_yyin.fp) { + __json_setup(); + __json_status = __json_yyparse(); + fclose(__json_yyin.fp); + if (__json_status == 0) { + return __json_root; + } + __json_free_all(__json_mgr); + } + return NULL; +} + +const char *__json_status_message(void) +{ + if (__json_status) { + static char buf[256] = {0}; + sprintf(buf, "Error near the line %d.", __json_line); + return buf; + } + return "No errors."; +} diff --git a/samples/json.c b/samples/json.c new file mode 100644 index 0000000..a150c59 --- /dev/null +++ b/samples/json.c @@ -0,0 +1,15 @@ +#include +#include + +int main() +{ + json_object_t *j = json_parse_file("samples/sample.json"); + if (j) { + json_pretty_print(j, 0, 0, 0); + json_free_all(j); + } else { + printf("Parse Error: %s\n", __json_status_message()); + } + return 0; +} + diff --git a/samples/sample.json b/samples/sample.json new file mode 100644 index 0000000..f1df4e4 --- /dev/null +++ b/samples/sample.json @@ -0,0 +1,14 @@ +[ + "Sample", + { + "x": 410, + "y": 150, + "type": "link", + "path": "/Applications" + }, + { + "x": 130, + "y": 150, + "type": "file" + } +] diff --git a/utility/myacc.c b/utility/myacc.c new file mode 100644 index 0000000..eb0b5cf --- /dev/null +++ b/utility/myacc.c @@ -0,0 +1,1466 @@ +/*% clang -g -Wall -Wextra % -o # + * miniyacc - LALR(1) grammars for C + * See LICENSE for copyright and license details. + */ +#include +#include +#include +#include +#include + +/* + $ cl /O2 utility\myacc.c +*/ +#ifndef SMYY +#define SMYY "${yy_enough_long_space_to_replace}" +#endif +#ifndef LGYY +#define LGYY "${YY_enough_long_space_to_replace}" +#endif + +const char *smyy = "yy"; +const char *lgyy = "YY"; + +/* + Replacing string without allocation, buffer size must be enough. +*/ +char *replace(char *str, const char *src, const char *dst) +{ + char *src_pos; + if (!str || !src || !dst || !*src) { + return str; + } + if ((src_pos = strstr(str, src)) == NULL) { + return str; + } + + const int src_len = strlen(src); + const int dst_len = strlen(dst); + const char *remain = src_pos + src_len; + memmove(src_pos + dst_len, remain, strlen(remain) + 1); + memcpy(src_pos, dst, dst_len); + return str; +} + +char *replace_all(char *str, const char *src, const char *dst) +{ + if (!str || !src || !dst || !*src) { + return str; + } + char *src_pos = str; + const int src_len = strlen(src); + const int dst_len = strlen(dst); + while ((src_pos = strstr(src_pos, src)) != NULL) { + const char *remain = src_pos + src_len; + memmove(src_pos + dst_len, remain, strlen(remain) + 1); + memcpy(src_pos, dst, dst_len); + } + return str; +} + +char *replace_yy(char *str) +{ + if (!str) { + return str; + } + if (strstr(str, SMYY) == 0 && strstr(str, LGYY) == 0) { + return str; + } + + static char buf[2048] = {0}; + memcpy(buf, str, 2000); + return replace_all(replace_all(buf, SMYY, smyy), LGYY, lgyy); +} + +typedef int Sym; +typedef struct Rule Rule; +typedef struct TSet TSet; +typedef struct Info Info; +typedef struct Term Term; +typedef struct Item Item; +typedef struct Row Row; + +#define S ((Sym) -1) +#define Red(n) (- (n+2)) /* involutive, Red(Red(x)) == x */ +#define GetBit(s,n) (s[n/32] & (1<<(n%32))) +#define SetBit(s,n) (s[n/32] |= 1<<(n%32)) + +enum { + IdntSz = 64, + MaxRhs = 32, + MaxTk = 500, + MaxNt = 500, + MaxRl = 800, + MaxTm = 1000, + + TSetSz = (MaxTk+31)/32, + Sym0 = MaxTk +}; + +struct Rule { + Sym lhs; + Sym rhs[MaxRhs]; + char *act; + int actln; + int prec; +}; + +struct TSet { + unsigned t[TSetSz]; +}; + +struct Info { + int nul; + TSet fst; + int prec; + enum { + ANone, + ALeft, + ARight, + ANonassoc + } assoc; + char name[IdntSz]; + char type[IdntSz]; +}; + +struct Term { + Rule *rule; + int dot; + TSet lk; +}; + +struct Item { + int id; + int nt; + Term ts[MaxTm]; + Item **gtbl; + int dirty; +}; + +struct Row { + int def; + int ndef; + int *t; +}; + +char srs[] = "shift/reduce conflict state %d token %s\n"; +char rrs[] = "reduce/reduce conflict state %d token %s\n"; + +Item i0; /* temporary item */ + +int nrl, nsy, nst, ntk; +Rule rs[MaxRl]; /* grammar rules (ordered, rcmp) */ +Info is[MaxTk+MaxNt]; /* symbol information */ +Item **st; /* LALR(1) states (ordered, icmp) */ +Row *as; /* action table [state][tok] */ +Row *gs; /* goto table [sym][state] */ +Sym sstart;/* start symbol */ +Item *ini; /* initial state */ +int doty; /* type-checking enabled */ + +int srconf, rrconf; +int actsz; +int *act; +int *chk; +int *adsp; +int *gdsp; + +int lineno = 1; +char *srca; +FILE *fin; +FILE *fout; +FILE *fgrm; +FILE *fhdr; + +void +die(char *s) +{ + fprintf(stderr, "%s (on line %d)\n", s, lineno); + exit(1); +} + +char *replace_sep(char *path) +{ + char *beg = path; + while (*path) { + if (*path == '\\') *path = '/'; + ++path; + } + return beg; +} + +void * +yalloc(size_t n, size_t o) +{ + void *p; + + p = calloc(n, o); + if (!p) + die("out of memory"); + return p; +} + +int +rcmp(const void *a, const void *b) +{ + return ((Rule *)a)->lhs - ((Rule *)b)->lhs; +} + +Rule * +rfind(Sym lhs) +{ + Rule *r; + Rule k; + + k.lhs = lhs; + r = bsearch(&k, rs, nrl, sizeof *r, rcmp); + if (r != 0) + while (r > rs && r[-1].lhs == lhs) + r--; + return r; +} + +int +slen(Sym *l) +{ + int n; + + for (n=0; *l!=S; n++, l++); + return n; +} + +void +tszero(TSet *ts) +{ + memset(ts, 0, sizeof *ts); +} + +int +tsunion(TSet *tsa, TSet *tsb) +{ + int n; + unsigned *a, *b, c, t; + + c = 0; + a = tsa->t; + b = tsb->t; + n = (31+ntk)/32; + while (n-- > 0) { + t = *a; + *a |= *b++; + c |= t ^ *a++; + } + return !!c; +} + +void +first(TSet *ts, Sym *stnc, TSet *last) +{ + Sym f; + + f = stnc[0]; + if (f == S) { + if (last) + tsunion(ts, last); + return; + } + if (f < ntk) { + SetBit(ts->t, f); + return; + } + if (is[f].nul) + first(ts, stnc+1, last); + tsunion(ts, &is[f].fst); +} + +void +ginit() +{ + int chg; + Rule *r; + Info *i; + Sym *s; + TSet ts; + + do { + chg = 0; + for (r=rs; r-rslhs]; + for (s=r->rhs; *s!=S; s++) + if (!is[*s].nul) + goto nonul; + chg |= i->nul == 0; + i->nul = 1; + nonul: + tszero(&ts); + first(&ts, r->rhs, 0); + chg |= tsunion(&i->fst, &ts); + } + } while (chg); +} + +int +tcmp(Term *a, Term *b) +{ + int c; + + c = a->rule - b->rule; + if (c==0) + c = a->dot - b->dot; + return c; +} + +int +tcmpv(const void *a, const void *b) +{ + return tcmp((Term *)a, (Term *)b); +} + +void +iclose(Item *i) +{ + int smap[MaxNt]; + Rule *r; + Term *t, t1; + Sym s, *rem; + int chg, n, m; + + t1.dot = 0; + memset(smap, 0, sizeof smap); + for (n=0; nnt; n++) { + t = &i->ts[n]; + s = t->rule->lhs-Sym0; + if (t->dot==0) + if (smap[s]==0) + smap[s] = n; + } + do { + chg = 0; + for (n=0; nnt; n++) { + t = &i->ts[n]; + rem = &t->rule->rhs[t->dot]; + s = *rem++; + if (s < Sym0 || s == S) + continue; + r = rfind(s); + if (!r) + die("some non-terminals are not defined"); + tszero(&t1.lk); + first(&t1.lk, rem, &t->lk); + m = smap[s-Sym0]; + if (m) + for (; r-rslhs==s; r++, m++) + chg |= tsunion(&i->ts[m].lk, &t1.lk); + else { + m = i->nt; + smap[s-Sym0] = m; + for (; r-rslhs==s; r++, m++) { + if (m>=MaxTm) + die("too many terms in item"); + t1.rule = r; + i->ts[m] = t1; + } + i->nt = m; + chg = 1; + } + } + } while (chg); +} + +void +igoto(Item *i, Sym s) +{ + Term *t, *t1; + int n; + + i0.nt = 0; + for (n=0, t=i->ts; nnt; n++, t++) { + if (t->rule->rhs[t->dot] != s) + continue; + t1 = &i0.ts[i0.nt++]; + *t1 = *t; + t1->dot++; + } + qsort(i0.ts, i0.nt, sizeof i0.ts[0], tcmpv); +} + +int +icmp(Item *a, Item *b) +{ + Term *ta, *tb, *ma, *mb; + int c; + + ta = a->ts; + tb = b->ts; + ma = ta+a->nt; + mb = tb+b->nt; + for (;;) { + if (ta==ma || ta->dot==0) + return -(tbdot); + if (tb==mb || tb->dot==0) + return +(tadot); + if ((c=tcmp(ta++, tb++))) + return c; + } +} + +int +stadd(Item **pi) +{ + Item *i, *i1; + int lo, hi, mid, n, chg; + + /* http://www.iq0.com/duffgram/bsearch.c */ + i = *pi; + lo = 0; + hi = nst - 1; + if (hi<0 || icmp(i, st[hi])>0) + hi++; + else if (icmp(i, st[lo])<=0) + hi = lo; + else + while (hi-lo!=1) { + mid = (lo+hi)/2; + if (icmp(st[mid], i)<0) + lo = mid; + else + hi = mid; + } + if (hint; n++) + chg |= tsunion(&i1->ts[n].lk, &i->ts[n].lk); + i1->dirty |= chg; + *pi = i1; + return chg; + } else { + st = realloc(st, ++nst * sizeof st[0]); + if (!st) + die("out of memory"); + memmove(&st[hi+1], &st[hi], (nst-1 - hi) * sizeof st[0]); + i->gtbl = yalloc(nsy, sizeof i->gtbl[0]); + i->dirty = 1; + i1 = yalloc(1, sizeof *i1); + *i1 = *i; + *pi = st[hi] = i1; + return 1; + } +} + +void +stgen() +{ + Sym s; + Rule *r; + Item *i, *i1; + Term tini; + int n, chg; + + ini = &i0; + r = rfind(Sym0); + tini.rule = r; + tini.dot = 0; + tszero(&tini.lk); + SetBit(tini.lk.t, 0); + i0.nt = 0; + i0.ts[i0.nt++] = tini; + stadd(&ini); + do { + chg = 0; + for (n=0; ndirty) + continue; + i->dirty = 0; + iclose(i); + for (s=0; snt) { + i->gtbl[s] = 0; + continue; + } + chg |= stadd(&i1); + i->gtbl[s] = i1; + } + } + } while (chg); +} + +int +resolve(Rule *r, Sym s, int st) +{ + if (!r->prec || !is[s].prec) { + conflict: + if (fgrm) + fprintf(fgrm, srs, st, is[s].name); + srconf++; + return ARight; + } + if (r->prec==is[s].prec) { + if (is[s].assoc == ANone) + goto conflict; + return is[s].assoc; + } else + if (r->precrule->rhs[t->dot]; + if (s!=S) { + /* shift */ + if (s>=ntk) + return; + assert(i->gtbl[s]); + act = ARight; + if (tbl[s] && tbl[s] != i->gtbl[s]->id) { + assert(tbl[s]<=0); + act = resolve(&rs[Red(tbl[s])], s, i->id-1); + } + switch (act) { + case ARight: + tbl[s] = i->gtbl[s]->id; + break; + case ANonassoc: + tbl[s] = -1; + break; + } + } else + /* reduce */ + for (s=0; slk.t, s)) + continue; + /* default to shift if conflict occurs */ + if (!tbl[s]) + act = ALeft; + else if (tbl[s]<0) { + if (fgrm) + fprintf(fgrm, rrs, i->id-1, is[s].name); + rrconf++; + act = ARight; + } else + act = resolve(t->rule, s, i->id-1); + switch (act) { + case ALeft: + tbl[s] = Red(t->rule-rs); + break; + case ANonassoc: + tbl[s] = -1; + break; + } + } +} + +void +setdef(Row *r, int w, int top) +{ + int n, m, x, cnt, def, max; + + max = 0; + def = -1; + r->ndef = 0; + for (n=0; nt[n]; + if (x==0) + r->ndef++; + if (x>=top || x==0) + continue; + cnt = 1; + for (m=n+1; mt[m]==x) + cnt++; + if (cnt>max) { + def = x; + max = cnt; + } + } + r->def = def; + if (max!=0) + /* zero out the most frequent entry */ + for (n=0; nt[n]==def) { + r->t[n] = 0; + r->ndef++; + } +} + +void +tblgen() +{ + Row *r; + Item *i; + int n, m; + + for (n=0; nid = n+1; + as = yalloc(nst, sizeof as[0]); + gs = yalloc(nsy-MaxTk, sizeof gs[0]); + /* fill action table */ + for (n=0; nt = yalloc(ntk, sizeof r->t[0]); + for (i=st[n], m=0; mnt; m++) + tblset(r->t, i, &i->ts[m]); + setdef(r, ntk, -1); + r->def = Red(r->def); /* Red(-1) == -1 */ + } + /* fill goto table */ + for (n=MaxTk; nt = yalloc(nst, sizeof r->t[0]); + for (m=0; mgtbl[n]) + r->t[m] = st[m]->gtbl[n]->id; + setdef(r, nst, nst+1); + } +} + +int +prcmp(const void *a, const void *b) +{ + return (*(Row **)a)->ndef - (*(Row **)b)->ndef; +} + +void +actgen() +{ + Row **o, *r; + int n, m, t, dsp, nnt; + + actsz = 0; + o = yalloc(nst+nsy, sizeof o[0]); + act = yalloc(nst*nsy, sizeof act[0]); + chk = yalloc(nst*nsy, sizeof chk[0]); + adsp = yalloc(nst, sizeof adsp[0]); + for (n=0; nt[m]==0; m++) + dsp--; + retrya: + /* The invariant here is even + * trickier than it looks. + */ + for (t=0; t=0 && chk[m]>=0) + if ((r->t[t] && (chk[m]!=t || act[m]!=r->t[t])) + || (!r->t[t] && chk[m]==t)) { + dsp++; + goto retrya; + } + adsp[r-as] = dsp; + for (t=0; tt[t]) { + chk[dsp+t] = t; + act[dsp+t] = r->t[t]; + if (dsp+t>=actsz) + actsz = dsp+t+1; + } + } + /* fill in gotos */ + nnt = nsy-MaxTk; + gdsp = yalloc(nnt, sizeof gdsp[0]); + for (n=0; nt[m]==0; m++) + dsp--; + retryg: + for (t=m; t=0 && r->t[t]) { + dsp++; + goto retryg; + } + gdsp[r-gs] = dsp; + for (t=m; tt[t]) { + chk[dsp+t] = ntk+(r-gs); + act[dsp+t] = r->t[t]; + if (dsp+t>=actsz) + actsz = dsp+t+1; + } + } + free(o); +} + +void +aout(char *name, int *t, int n) +{ + int i; + + fprintf(fout, "short %s[] = {", name); + for (i=0; iid-1); + fprintf(fout, replace_yy("short " SMYY "ntoks = %d;\n"), ntk); + o = yalloc(nrl+nst+nsy, sizeof o[0]); + for (n=0; n0 || o[n]==-1); + if (o[n]>0) + o[n]--; + } + aout(replace_yy(SMYY "gdef"), o, nsy-MaxTk); + aout(replace_yy(SMYY "adsp"), adsp, nst); + aout(replace_yy(SMYY "gdsp"), gdsp, nsy-MaxTk); + for (n=0; n=0) + act[n]--; + aout(replace_yy(SMYY "act"), act, actsz); + aout(replace_yy(SMYY "chk"), chk, actsz); + for (n=0; n<128; n++) { + o[n] = 0; + for (m=0; m", (int)(r-rs), is[r->lhs].name); + for (s1=r->rhs; *s1!=S; s1++) + fprintf(fgrm, " %s", is[*s1].name); + } + fprintf(fgrm, "\n"); + for (m=0; mts; t-st[m]->tsnt; t++) { + r = t->rule; + d = t->dot; + if (d==0 && t!=st[m]->ts) + continue; + fprintf(fgrm, " %s ->", is[r->lhs].name); + for (s1=r->rhs; *s1!=S; s1++, d--) + fprintf(fgrm, " %s%s", d ? "" : ". ", is[*s1].name); + if (!d) + fprintf(fgrm, " ."); + fprintf(fgrm, "\n"); + } + fprintf(fgrm, "\n"); + ar = &as[m]; + for (n=0; nt[n]; + if (!act) + continue; + if (act==-1) + fprintf(fgrm, " %s error (nonassoc)\n", is[n].name); + else if (act<0) + fprintf(fgrm, " %s reduce with rule %d\n", is[n].name, Red(act)); + else + fprintf(fgrm, " %s shift and go to %d\n", is[n].name, act-1); + } + if (ar->def != -1) + fprintf(fgrm, " * reduce with rule %d\n", ar->def); + } +} + +enum { + TIdnt, + TTokchr, /* 'c' */ + TPP, /* %% */ + TLL, /* %{ */ + TLangle, /* < */ + TRangle, /* > */ + TSemi, /* ; */ + TBar, /* | */ + TColon, /* : */ + TLBrack, /* { */ + TUnion, + TType, + TToken, + TRight, + TLeft, + TNonassoc, + TPrec, + TStart, + TEof +}; + +struct { + char *name; + int tok; +} words[] = { + { "%%", TPP }, + { "%union", TUnion }, + { "%type", TType }, + { "%token", TToken }, + { "%right", TRight }, + { "%left", TLeft }, + { "%nonassoc", TNonassoc }, + { "%prec", TPrec }, + { "%start", TStart }, + { 0, 0 } +}; + +char idnt[IdntSz]; + +int +istok(int c) +{ + return isalnum(c) || c=='_' || c=='%'; +} + +int +nexttk() +{ + int n; + char c, *p; + + while (isspace(c=fgetc(fin))) + if (c == '\n') + lineno++; + switch (c) { + case '<': + return TLangle; + case '>': + return TRangle; + case ';': + return TSemi; + case '|': + return TBar; + case ':': + return TColon; + case '{': + return TLBrack; + case EOF: + return TEof; + case '\'': + idnt[0] = '\''; + idnt[1] = fgetc(fin); + idnt[2] = '\''; + idnt[3] = 0; + if (fgetc(fin)!='\'') + die("syntax error, invalid char token"); + return TTokchr; + } + p = idnt; + while (istok(c)) { + *p++ = c; + if (p-idnt >= IdntSz-1) + die("identifier too long"); + c = fgetc(fin); + } + if (p == idnt) + die("unknown token"); + *p = 0; + if (strcmp(idnt, "%")==0) + if (c=='{') + return TLL; + ungetc(c, fin); + for (n=0; words[n].name; n++) + if (strcmp(idnt, words[n].name) == 0) + return words[n].tok; + return TIdnt; +} + +char * +cpycode() +{ + int c, nest, in, len, pos; + char *s; + + len = 64; + s = yalloc(len+1, 1); + s[0] = '{'; + pos = 1; + nest = 1; + in = 0; + + while (nest) { + c = fgetc(fin); + if (in) { + if (c == in) + if (s[pos-1] != '\\') + in = 0; + } else { + if (c == '"' || c == '\'') + in = c; + if (c == '{') + nest++; + if (c == '}') + nest--; + if (c == EOF) + die("syntax error, unclosed code block"); + if (c == '\n') + lineno++; + } + if (pos>=len) + if (!(s=realloc(s, len=2*len+1))) + die("out of memory"); + s[pos++] = c; + } + s[pos] = 0; + return s; +} + +int +gettype(char *type) +{ + int tk; + + tk = nexttk(); + if (tk==TLangle) { + if (nexttk()!=TIdnt) + die("syntax error, ident expected after <"); + strcpy(type, idnt); + if (nexttk()!=TRangle) + die("syntax error, unclosed <"); + return nexttk(); + } else { + type[0] = 0; + return tk; + } +} + +Sym +findsy(char *name, int add) +{ + int n; + + for (n=0; n=MaxTk) + die("too many tokens"); + ntk++; + strcpy(is[n].name, name); + return n; + } + n = MaxTk; + } + if (strcmp(is[n].name, name)==0) + return n; + } + if (add) { + if (nsy>=MaxTk+MaxNt) + die("too many non-terminals"); + strcpy(is[nsy].name, name); + return nsy++; + } else + return nsy; +} + +void +getdecls() +{ + int tk, prec, p, a, c, c1, n; + Info *si; + char type[IdntSz], *s; + + strcpy(is[0].name, "$"); + ntk = 1; + strcpy(is[Sym0].name, "@start"); + nsy = MaxTk+1; + sstart = S; + prec = 0; + tk = nexttk(); + for (;;) + switch (tk) { + case TStart: + tk = nexttk(); + if (tk!=TIdnt) + die("syntax error, ident expected after %start"); + sstart = findsy(idnt, 1); + if (sstart 0) + fprintf(fout, "#line %d \"%s\"\n", lineno, replace_sep(srca)); + s = cpycode(); + fprintf(fout, replace_yy("typedef union %s " SMYY "union;\n"), s); + fprintf(fout, replace_yy("#define " LGYY "STYPE " SMYY "union\n")); + if (fhdr) { + fprintf(fhdr, replace_yy("typedef union %s " SMYY "union;\n"), s); + fprintf(fhdr, replace_yy("#define " LGYY "STYPE " SMYY "union\n")); + } + free(s); + doty = 1; + tk = nexttk(); + break; + case TLeft: + p = ++prec; + a = ALeft; + goto addtoks; + case TRight: + p = ++prec; + a = ARight; + goto addtoks; + case TNonassoc: + p = ++prec; + a = ANonassoc; + goto addtoks; + case TToken: + p = 0; + a = ANone; + addtoks: + tk = gettype(type); + while (tk==TIdnt || tk==TTokchr) { + si = 0; + n = findsy(idnt, 0); + if (n>=MaxTk && n=MaxTk) + die("too many tokens"); + n = ntk++; + } + si = &is[n]; + strcpy(si->name, idnt); + strcpy(si->type, type); + si->prec = p; + si->assoc = a; + tk = nexttk(); + } + break; + case TType: + tk = gettype(type); + if (type[0]==0) + die("syntax error, type expected"); + while (tk==TIdnt) { + si = 0; + n = findsy(idnt, 1); + if (nname, idnt); + strcpy(si->type, type); + tk = nexttk(); + } + break; + case TLL: + if (lineno > 0) + fprintf(fout, "#line %d \"%s\"\n", lineno, replace_sep(srca)); + for (;;) { + c = fgetc(fin); + if (c == EOF) + die("syntax error, unclosed %{"); + if (c == '%') { + c1 = fgetc(fin); + if (c1 == '}') { + fputs("\n", fout); + break; + } + ungetc(c1, fin); + } + if (c == '\n') + lineno++; + fputc(c, fout); + } + tk = nexttk(); + break; + case TPP: + return; + case TEof: + die("syntax error, unfinished declarations"); + default: + die("syntax error, declaration expected"); + } +} + +void +getgram() +{ + extern char *retcode; + int tk; + Sym hd, *p, s; + Rule *r; + + for (;;) { + tk = nexttk(); + if (tk==TPP || tk==TEof) { + if (sstart==S) + die("syntax error, empty grammar"); + r = &rs[nrl++]; + r->lhs = Sym0; + r->rhs[0] = sstart; + r->rhs[1] = 0; + r->rhs[2] = S; + r->act = retcode; + qsort(rs, nrl, sizeof rs[0], rcmp); + return; + } + if (tk!=TIdnt) + die("syntax error, production rule expected"); + if (nexttk()!=TColon) + die("syntax error, colon expected after production's head"); + hd = findsy(idnt, 1); + if (sstart==S) + sstart = hd; + do { + if (nrl>=MaxRl-1) + die("too many rules"); + r = &rs[nrl++]; + r->lhs = hd; + r->act = 0; + p = r->rhs; + while ((tk=nexttk())==TIdnt || tk==TTokchr || tk==TPrec) { + if (tk==TPrec) { + tk = nexttk(); + if (tk!=TIdnt + || (s=findsy(idnt, 0))>=ntk) + die("token expected after %prec"); + r->prec = is[s].prec; + continue; + } + s = findsy(idnt, 1); + *p++ = s; + if (s0) + r->prec = is[s].prec; + if (p-r->rhs >= MaxRhs-1) + die("production rule too long"); + } + *p = S; + if (tk==TLBrack) { + r->actln = lineno; + r->act = cpycode(); + tk = nexttk(); + } + } while (tk==TBar); + if (tk!=TSemi) + die("syntax error, ; or | expected"); + } +} + +void +actout(Rule *r) +{ + long l; + int i, ar; + char c, *p, *ty, tya[IdntSz]; + + ar = slen(r->rhs); + p = replace_yy(r->act); + i = r->actln; + if (!p) + return; + while ((c=*p++)) + switch (c) { + case '\n': + i++; + default: + fputc(c, fout); + break; + case '$': + c = *p++; + if (c == '$') { + fprintf(fout, replace_yy(SMYY "val")); + if (doty) { + ty = is[r->lhs].type; + if (!ty[0]) { + lineno = i; + die("$$ has no type"); + } + fprintf(fout, ".%s", ty); + } + } + else if (c == '<') { + ty = tya; + while (istok(*p) && ty-tya ar) { + lineno = i; + die("invalid $n"); + } + fprintf(fout, "ps[%d].val", (int)l); + if (doty) { + if (!ty && l>0) + ty = is[r->rhs[l-1]].type; + if (!ty || !ty[0]) { + lineno = i; + die("$n has no type"); + } + fprintf(fout, ".%s", ty); + } + } + else { + fputc('$', fout); + fputc(c, fout); + } + } + fputs("\n", fout); +} + +void +codeout() +{ + extern char *code0[], *code1[]; + char **p; + Rule *r; + int n, c; + + for (p=code0; *p; p++) + fputs(replace_yy(*p), fout); + for (n=0; nactln > 0) + fprintf(fout, "#line %d \"%s\"\n", r->actln, replace_sep(srca)); + actout(r); + fputs("\t\tbreak;\n", fout); + } + for (p=code1; *p; p++) + fputs(*p, fout); + if (lineno > 0) + fprintf(fout, "#line %d \"%s\"\n", lineno, replace_sep(srca)); + while ((c=fgetc(fin))!=EOF) + fputc(c, fout); +} + +void +init(int ac, char *av[]) +{ + int c, vf, df; + char *pref, buf[100], *opt; + + (void) ac; + pref = "y"; + vf = df = 0; + for (av++; av[0] && av[0][0]=='-'; av++) + for (opt = &av[0][1]; (c = *opt); opt++) + switch (c) { + case 'y': + if ((smyy = *++av)) + break; + break; + case 'Y': + if ((lgyy = *++av)) + break; + break; + case 'v': + vf = 1; + break; + case 'd': + df = 1; + break; + case 'b': + if ((pref = *++av)) + break; + default: + usage: + fputs("usage: myacc [-vd] [-b file_prefix] grammar\n", stderr); + exit(1); + } + + if (!(srca = *av)) + goto usage; + fin = fopen(srca, "r"); + if (strlen(pref) + 10 > sizeof buf) + die("-b prefix too long"); + sprintf(buf, "%s.tab.c", pref); + fout = fopen(buf, "w"); + if (vf) { + sprintf(buf, "%s.output", pref); + fgrm = fopen(buf, "w"); + } + if (df) { + sprintf(buf, "%s.tab.h", pref); + fhdr = fopen(buf, "w"); + if (fhdr) { + fprintf(fhdr, "#ifndef Y_TAB_H_\n"); + fprintf(fhdr, "#define Y_TAB_H_\n"); + } + } + if (!fin || !fout || (!fgrm && vf) || (!fhdr && df)) + die("cannot open work files"); +} + +int +main(int ac, char *av[]) +{ + + init(ac, av); + getdecls(); + getgram(); + ginit(); + stgen(); + tblgen(); + stdump(); + actgen(); + tblout(); + codeout(); + + if (srconf) + fprintf(stderr, "%d shift/reduce conflicts\n", srconf); + if (rrconf) + fprintf(stderr, "%d reduce/reduce conflicts\n", rrconf); + + exit(0); +} + +/* Glorious macros. + |sed 's|.*|"&\\n",|' +*/ + +char *retcode = "\t\t" SMYY "val = ps[1].val; return 0;"; + +char *code0[] = { +"\n", +"#ifndef " LGYY "STYPE\n", +"#define " LGYY "STYPE int\n", +"#endif\n", +LGYY "STYPE " SMYY "lval;\n", +"\n", +"int\n", +SMYY "parse()\n", +"{\n", +" enum {\n", +" StackSize = 100,\n", +" ActSz = sizeof " SMYY "act / sizeof " SMYY "act[0],\n", +" };\n", +" struct {\n", +" " LGYY "STYPE val;\n", +" int state;\n", +" } stk[StackSize], *ps;\n", +" int r, h, n, s, tk;\n", +" " LGYY "STYPE " SMYY "val;\n", +"\n", +" ps = stk;\n", +" ps->state = s = " SMYY "ini;\n", +" tk = -1;\n", +"loop:\n", +" n = " SMYY "adsp[s];\n", +" if (tk < 0 && n > -" SMYY "ntoks)\n", +" tk = " SMYY "trns[" SMYY "lex()];\n", +" n += tk;\n", +" if (n < 0 || n >= ActSz || " SMYY "chk[n] != tk) {\n", +" r = " SMYY "adef[s];\n", +" if (r < 0)\n", +" return -1;\n", +" goto reduce;\n", +" }\n", +" n = " SMYY "act[n];\n", +" if (n == -1)\n", +" return -1;\n", +" if (n < 0) {\n", +" r = - (n+2);\n", +" goto reduce;\n", +" }\n", +" tk = -1;\n", +" " SMYY "val = " SMYY "lval;\n", +"stack:\n", +" ps++;\n", +" if (ps-stk >= StackSize)\n", +" return -2;\n", +" s = n;\n", +" ps->state = s;\n", +" ps->val = " SMYY "val;\n", +" goto loop;\n", +"reduce:\n", +" ps -= " SMYY "r1[r];\n", +" h = " SMYY "r2[r];\n", +" s = ps->state;\n", +" n = " SMYY "gdsp[h] + s;\n", +" if (n < 0 || n >= ActSz || " SMYY "chk[n] != " SMYY "ntoks+h)\n", +" n = " SMYY "gdef[h];\n", +" else\n", +" n = " SMYY "act[n];\n", +" switch (r) {\n", +0 +}; + +char *code1[] = { +" }\n", +" goto stack;\n", +"}\n", +0 +}; From 540e8b3e8c74d6185f3e03c856f429509045681e Mon Sep 17 00:00:00 2001 From: Kray-G Date: Thu, 7 Nov 2019 16:48:17 +0900 Subject: [PATCH 2/4] issue #22: updated json parser. --- kccrt/include/kcc/json.h | 3 ++- kccrt/libsrc/kcc/json.y | 6 +++++- samples/json.c | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/kccrt/include/kcc/json.h b/kccrt/include/kcc/json.h index 0127b59..73b4992 100644 --- a/kccrt/include/kcc/json.h +++ b/kccrt/include/kcc/json.h @@ -46,6 +46,7 @@ typedef struct __json_object_ { extern __json_object_t *__json_parse(const char *str); extern __json_object_t *__json_parse_file(const char *filename); extern const char *__json_error_message(void); +extern void __json_pretty_print_all(__json_object_t *j); extern __json_object_t *__json_set_top(__json_object_t *j); extern __json_object_t *__json_gen_object(void); @@ -74,7 +75,7 @@ typedef __json_object_t json_object_t; #define json_yyin __json_yyin #define json_parse __json_parse #define json_parse_file __json_parse_file -#define json_pretty_print __json_pretty_print +#define json_pretty_print __json_pretty_print_all #define json_free_all __json_free_all #define json_error_message __json_error_message diff --git a/kccrt/libsrc/kcc/json.y b/kccrt/libsrc/kcc/json.y index b7d471b..32d4239 100644 --- a/kccrt/libsrc/kcc/json.y +++ b/kccrt/libsrc/kcc/json.y @@ -178,7 +178,6 @@ static int __json_object_allocated = 0; static int __json_string_allocated = 0; static __json_object_t *__json_mgr = NULL; static __json_object_t *__json_root = NULL; -static void __json_pretty_print(__json_object_t *j, int indent, int comma, int contd); void __json_setup(void) { @@ -691,6 +690,11 @@ static void __json_pretty_print(__json_object_t *j, int indent, int comma, int c } } +void __json_pretty_print_all(json_object_t *j) +{ + __json_pretty_print(j, 0, 0, 0); +} + __json_object_t *__json_set_top(__json_object_t *j) { __json_object_t *p = j->mgr; diff --git a/samples/json.c b/samples/json.c index a150c59..434f959 100644 --- a/samples/json.c +++ b/samples/json.c @@ -5,7 +5,7 @@ int main() { json_object_t *j = json_parse_file("samples/sample.json"); if (j) { - json_pretty_print(j, 0, 0, 0); + json_pretty_print(j); json_free_all(j); } else { printf("Parse Error: %s\n", __json_status_message()); From 28b4ce9570489dacc4a2d2132a819682fe7b8eff Mon Sep 17 00:00:00 2001 From: Kray-G Date: Thu, 7 Nov 2019 17:35:55 +0900 Subject: [PATCH 3/4] updated for JSON parser. --- README.md | 138 +++++++++++++++++++-------------------- kccrt/include/kcc/json.h | 34 ++++++++-- kccrt/libsrc/kcc/json.y | 112 +++++++++++++++++++++++++++++-- samples/json.c | 9 ++- samples/sample.json | 13 +++- 5 files changed, 222 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index f75411d..d298401 100644 --- a/README.md +++ b/README.md @@ -277,50 +277,49 @@ so it shows the fib function only. $ kcc -J fib.c ...(omitted)... fib -0000BCE6: 55 pushq %rbp -0000BCE7: 48 89 E5 movq %rsp, %rbp -0000BCEA: 53 pushq %rbx -0000BCEB: 41 54 pushq %r12 -0000BCED: 41 55 pushq %r13 -0000BCEF: 41 56 pushq %r14 -0000BCF1: 48 83 EC 10 subq $16, %rsp -0000BCF5: 89 7D D8 movl %edi, -40(%rbp) - .L2343 -0000BCF8: 83 7D D8 03 cmpl $3, -40(%rbp) -0000BCFC: 0F 8D 10 00 00 00 jge .L2345 - .L2344 -0000BD02: 8B 45 D8 movl -40(%rbp), %eax -0000BD05: 48 8D 65 E0 leaq -32(%rbp), %rsp -0000BD09: 41 5E popq %r14 -0000BD0B: 41 5D popq %r13 -0000BD0D: 41 5C popq %r12 -0000BD0F: 5B popq %rbx -0000BD10: C9 leave -0000BD11: C3 ret - .L2345 -0000BD12: 8B 45 D8 movl -40(%rbp), %eax -0000BD15: B9 02 00 00 00 movl $2, %ecx -0000BD1A: 29 C8 subl %ecx, %eax -0000BD1C: 89 C3 movl %eax, %ebx -0000BD1E: 89 DF movl %ebx, %edi -0000BD20: E8 C1 FF FF FF call fib -0000BD25: 41 89 C4 movl %eax, %r12d -0000BD28: 8B 45 D8 movl -40(%rbp), %eax -0000BD2B: B9 01 00 00 00 movl $1, %ecx -0000BD30: 29 C8 subl %ecx, %eax -0000BD32: 41 89 C5 movl %eax, %r13d -0000BD35: 44 89 EF movl %r13d, %edi -0000BD38: E8 A9 FF FF FF call fib -0000BD3D: 41 89 C6 movl %eax, %r14d -0000BD40: 44 89 F0 movl %r14d, %eax -0000BD43: 44 01 E0 addl %r12d, %eax -0000BD46: 48 8D 65 E0 leaq -32(%rbp), %rsp -0000BD4A: 41 5E popq %r14 -0000BD4C: 41 5D popq %r13 -0000BD4E: 41 5C popq %r12 -0000BD50: 5B popq %rbx -0000BD51: C9 leave -0000BD52: C3 ret +0000C2F3: 55 pushq %rbp +0000C2F4: 48 89 E5 movq %rsp, %rbp +0000C2F7: 53 pushq %rbx +0000C2F8: 41 54 pushq %r12 +0000C2FA: 41 55 pushq %r13 +0000C2FC: 41 56 pushq %r14 +0000C2FE: 48 83 EC 10 subq $16, %rsp +0000C302: 89 7D D8 movl %edi, -40(%rbp) + .L2453 +0000C305: 83 7D D8 03 cmpl $3, -40(%rbp) +0000C309: 0F 8D 10 00 00 00 jge .L2455 + .L2454 +0000C30F: 8B 45 D8 movl -40(%rbp), %eax +0000C312: 48 8D 65 E0 leaq -32(%rbp), %rsp +0000C316: 41 5E popq %r14 +0000C318: 41 5D popq %r13 +0000C31A: 41 5C popq %r12 +0000C31C: 5B popq %rbx +0000C31D: C9 leave +0000C31E: C3 ret + .L2455 +0000C31F: 8B 45 D8 movl -40(%rbp), %eax +0000C322: FF C8 decl %eax +0000C324: FF C8 decl %eax +0000C326: 89 C3 movl %eax, %ebx +0000C328: 89 DF movl %ebx, %edi +0000C32A: E8 C4 FF FF FF call fib +0000C32F: 41 89 C4 movl %eax, %r12d +0000C332: 8B 45 D8 movl -40(%rbp), %eax +0000C335: FF C8 decl %eax +0000C337: 41 89 C5 movl %eax, %r13d +0000C33A: 44 89 EF movl %r13d, %edi +0000C33D: E8 B1 FF FF FF call fib +0000C342: 41 89 C6 movl %eax, %r14d +0000C345: 44 89 F0 movl %r14d, %eax +0000C348: 44 01 E0 addl %r12d, %eax +0000C34B: 48 8D 65 E0 leaq -32(%rbp), %rsp +0000C34F: 41 5E popq %r14 +0000C351: 41 5D popq %r13 +0000C353: 41 5C popq %r12 +0000C355: 5B popq %rbx +0000C356: C9 leave +0000C357: C3 ret ...(omitted)... ``` @@ -331,30 +330,29 @@ $ kcc -X fib.c ...(omitted)... ---------------------------------------------------------------- fib - 7856: enter 32 - .L2295 - 7857: push(32) 3 (0x3) - 7858: push [BP-24] : n(i32) - 7859: gt (i32) - 7860: jnz * +15 <.L2296> - .L2297 - 7861: push [BP-24] : n(i32) - 7862: push(32) 2 (0x2) - 7863: sub (i32) - 7864: call * 7856 - 7865: cleanup (8) - 7866: pop [BP+8] : .t849(i32) - 7867: push [BP-24] : n(i32) - 7868: push(32) 1 (0x1) - 7869: sub (i32) - 7870: call * 7856 - 7871: cleanup (8) - 7872: push [BP+8] : .t849(i32) - 7873: add (i32) - 7874: ret (4) - .L2296 - 7875: push [BP-24] : n(i32) - 7876: ret (4) + 7979: enter 32 + .L2405 + 7980: push(32) 3 (0x3) + 7981: push [BP-24] : n(i32) + 7982: gt (i32) + 7983: jnz * +14 <.L2406> + .L2407 + 7984: push [BP-24] : n(i32) + 7985: dec (i32) + 7986: dec (i32) + 7987: call * 7979 + 7988: cleanup (8) + 7989: pop [BP+8] : .t945(i32) + 7990: push [BP-24] : n(i32) + 7991: dec (i32) + 7992: call * 7979 + 7993: cleanup (8) + 7994: push [BP+8] : .t945(i32) + 7995: add (i32) + 7996: ret (4) + .L2406 + 7997: push [BP-24] : n(i32) + 7998: ret (4) ...(omitted)... ``` @@ -366,9 +364,11 @@ I have a plan to do the followings when I have a time. * [ ] Providing all of Standard C Library. * [ ] Adding a library of XML Parser. -* [ ] Adding a library of JSON Parser. * [ ] Adding a library with libCurl. * [ ] Supporting encryption of Zip/Unzip. +* [ ] Adding [JSONPath][] for JSON parser. + +[JSONPath]: http://goessner.net/articles/JsonPath/ ## License diff --git a/kccrt/include/kcc/json.h b/kccrt/include/kcc/json.h index 73b4992..085a45e 100644 --- a/kccrt/include/kcc/json.h +++ b/kccrt/include/kcc/json.h @@ -71,13 +71,35 @@ extern __json_object_t *__json_div(__json_object_t *j1, __json_object_t *j2); extern __json_object_t *__json_mod(__json_object_t *j1, __json_object_t *j2); extern __json_object_t *__json_neg(__json_object_t *j); +/* accessors */ +extern int __json_get_type(__json_object_t *j); +extern __json_object_t *__json_get_property(__json_object_t *j, const char *key); +extern int __json_get_property_count(__json_object_t *j); +extern __json_object_t *__json_get_element(__json_object_t *j, int index); +extern int __json_get_element_count(__json_object_t *j); +extern int __json_get_boolean(__json_object_t *j); +extern int64_t __json_get_integer(__json_object_t *j); +extern double __json_get_real(__json_object_t *j); +extern string_t* __json_get_key(__json_object_t *j); +extern string_t* __json_get_string(__json_object_t *j); + typedef __json_object_t json_object_t; -#define json_yyin __json_yyin -#define json_parse __json_parse -#define json_parse_file __json_parse_file -#define json_pretty_print __json_pretty_print_all -#define json_free_all __json_free_all -#define json_error_message __json_error_message +#define json_yyin __json_yyin +#define json_parse __json_parse +#define json_parse_file __json_parse_file +#define json_pretty_print __json_pretty_print_all +#define json_free_all __json_free_all +#define json_error_message __json_error_message + +#define json_get_property __json_get_property +#define json_get_property_count __json_get_property_count +#define json_get_element __json_get_element +#define json_get_element_count __json_get_element_count +#define json_get_boolean __json_get_boolean +#define json_get_integer __json_get_integer +#define json_get_real __json_get_real +#define json_get_key __json_get_key +#define json_get_string __json_get_string #ifndef KCC_NO_IMPORT #if defined(__KCC_JIT__) || defined(__KCC__) diff --git a/kccrt/libsrc/kcc/json.y b/kccrt/libsrc/kcc/json.y index 32d4239..3b3b229 100644 --- a/kccrt/libsrc/kcc/json.y +++ b/kccrt/libsrc/kcc/json.y @@ -638,9 +638,9 @@ static void __json_pretty_print(__json_object_t *j, int indent, int comma, int c if (n) { printf("\n"); while (n) { - __json_object_t *prop = n->prop; - __json_pretty_print(n, indent+1, prop ? 1 : 0, 0); - n = prop; + __json_object_t *next = n->prop; + __json_pretty_print(n, indent+1, next ? 1 : 0, 0); + n = next; } __json_print_indent(indent); } @@ -1000,7 +1000,7 @@ __json_object_t *__json_parse_file(const char *filename) return NULL; } -const char *__json_status_message(void) +const char *__json_error_message(void) { if (__json_status) { static char buf[256] = {0}; @@ -1009,3 +1009,107 @@ const char *__json_status_message(void) } return "No errors."; } + +int __json_get_type(__json_object_t *j) +{ + return j ? j->type : JSON_UNKNWON; +} + +__json_object_t *__json_get_property(__json_object_t *j, const char *key) +{ + if (j && j->type == JSON_OBJECT) { + json_object_t *n = j->prop; + while (n) { + if (strcmp(n->key.cstr, key) == 0) { + return n; + } + n = n->prop; + } + } + return NULL; +} + +int __json_get_property_count(__json_object_t *j) +{ + int count = 0; + if (j && j->type == JSON_OBJECT) { + json_object_t *n = j->prop; + while (n) { + ++count; + n = n->prop; + } + } + return count; +} + +__json_object_t *__json_get_element(__json_object_t *j, int index) +{ + if (j && j->type == JSON_ARRAY) { + json_object_t *n = j->next; + for (int i = 0; n; ++i) { + if (i == index) { + return n; + } + n = n->next; + } + } + return NULL; +} + +int __json_get_element_count(__json_object_t *j) +{ + int count = 0; + if (j && j->type == JSON_ARRAY) { + json_object_t *n = j->next; + while (n) { + ++count; + n = n->next; + } + } + return count; +} + +int __json_get_boolean(__json_object_t *j) +{ + if (j && j->type == JSON_BOOLEAN) { + return j->value.b; + } + return 0; +} + +int64_t __json_get_integer(__json_object_t *j) +{ + if (j && j->type == JSON_INTEGER) { + return j->value.i; + } + return 0; +} + +double __json_get_real(__json_object_t *j) +{ + if (j && j->type == JSON_REAL) { + return j->value.d; + } + return 0; +} + +string_t* __json_get_key(__json_object_t *j) +{ + if (j && j->type == JSON_PAIR) { + return &j->key; + } + return 0; +} + +string_t* __json_get_string(__json_object_t *j) +{ + if (j) { + if (j->type == JSON_TEXT) { + return &j->value.t; + } + if (j->type == JSON_PAIR) { + return __json_get_string(j->value.o); + } + } + return 0; +} diff --git a/samples/json.c b/samples/json.c index 434f959..297efaf 100644 --- a/samples/json.c +++ b/samples/json.c @@ -6,10 +6,15 @@ int main() json_object_t *j = json_parse_file("samples/sample.json"); if (j) { json_pretty_print(j); + int count = json_get_element_count(j); + printf("element count = %d\n", count); + json_object_t *e = json_get_element(j, 1); + json_object_t *p = json_get_property(e, "path"); + string_t *s = json_get_string(p); + printf("json[1].path = %s\n", s ? s->cstr : ""); json_free_all(j); } else { - printf("Parse Error: %s\n", __json_status_message()); + printf("Parse Error: %s\n", json_error_message()); } return 0; } - diff --git a/samples/sample.json b/samples/sample.json index f1df4e4..c541405 100644 --- a/samples/sample.json +++ b/samples/sample.json @@ -7,8 +7,15 @@ "path": "/Applications" }, { - "x": 130, - "y": 150, - "type": "file" + "p1": { + "x": 130, + "y": 150, + "type": "file" + }, + "p2": { + "x": 230, + "y": 90, + "type": "directory" + } } ] From 3f7acc95495b511562a5bdbaf8c215d7a2434d6e Mon Sep 17 00:00:00 2001 From: Kray-G Date: Thu, 7 Nov 2019 17:57:46 +0900 Subject: [PATCH 4/4] issue #22: updated for Linux. --- Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3b27a2d..4a0b7eb 100644 --- a/Makefile +++ b/Makefile @@ -78,7 +78,7 @@ EXTSRC = \ src/_extdll/lib/sqlite3/sqlite3.c \ src/_extdll/lib/zip/miniz.c -all: $(TARGET) +all: ext_json.c $(TARGET) $(TARGET): bin/bootstrap/kcc bin/bootstrap/kccbltin.so bin/bootstrap/kccjit.so bin/bootstrap/kccext.so mkdir -p $(TARGETDIR) @@ -93,6 +93,13 @@ $(TARGET): bin/bootstrap/kcc bin/bootstrap/kccbltin.so bin/bootstrap/kccjit.so b cp -f bin/bootstrap/kccjit.so . cp -f bin/bootstrap/kccext.so . +ext_json.c: myacc kccrt/libsrc/kcc/json.y + ./myacc -y __json_yy -Y JSON_YY kccrt/libsrc/kcc/json.y + mv -f y.tab.c kccrt/libsrc/kcc/ext_json.c + +myacc: + $(CC) $(CFLAGS) -o myacc utility/myacc.c + bin/bootstrap/kcc: bin/bootstrap/libkcc.so @mkdir -p $(@D) $(CC) $(MAINSRC) -o $@ -Wl,-rpath,'$$ORIGIN' -L$(@D) -lkcc