aboutsummaryrefslogtreecommitdiff
path: root/src/json-gram.y
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2015-12-18 17:33:16 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2015-12-18 18:27:03 +0200
commit9c0d1b58fd370bed9442ad8859d9c6e1f02cc643 (patch)
tree993dfff1d8236d6f1b81cd0de1325452b4ae84e6 /src/json-gram.y
parentd51a70af75b14720a1756d90ec53132596aa3ebf (diff)
downloadgrecs-9c0d1b58fd370bed9442ad8859d9c6e1f02cc643.tar.gz
grecs-9c0d1b58fd370bed9442ad8859d9c6e1f02cc643.tar.bz2
Add basic JSON support functions.
* src/Make-inst.am: Add json.h * src/Make-shared.am: Likewise. * src/Make-static.am: Likewise. * src/Make.am: Likewise. * src/json-gram.y: New file. * src/json-lex.l: New file. * src/json.h: New file. * src/yytrans: Translate json prefixes. * src/.gitignore: Update. * tests/json.c: New file. * tests/json00.at: New file. * tests/json01.at: New file. * tests/Makefile.am: Add new tests; build json * tests/testsuite.at: Add new tests. * tests/.gitignore: Update. * am/grecs.m4: New flag "json" * configure.ac (GRECS_SETUP): Require json * src/Make-inst.am (include_HEADERS): Assign GRECS_HDR value. * src/Make-shared.a [GRECS_COND_INSTALLHEADERS] (grecsinclude_HEADERS) [!GRECS_COND_INSTALLHEADERS] (noinst_HEADERS): Likewise. * src/Make-static.am (noinst_HEADERS): Likewise. * src/Make.am [GRECS_COND_JSON]: Define GRECS_JSON and GRECS_EXTRA_JSON.
Diffstat (limited to 'src/json-gram.y')
-rw-r--r--src/json-gram.y371
1 files changed, 371 insertions, 0 deletions
diff --git a/src/json-gram.y b/src/json-gram.y
new file mode 100644
index 0000000..e92ad35
--- /dev/null
+++ b/src/json-gram.y
@@ -0,0 +1,371 @@
+%{
+/* This file is part of Grecs.
+ Copyright (C) 2012-2015 Sergey Poznyakoff.
+
+ Grecs is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ Grecs is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Grecs. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "grecs.h"
+#include <grecs-locus.h>
+#include <string.h>
+#include "json-gram.h"
+#include "json.h"
+
+struct json_value *json_return_obj;
+
+extern int yylex(void);
+static int yyerror(char const *s);
+
+static void
+pairfree(void *ptr)
+{
+ struct json_pair *p = ptr;
+ free(p->k);
+ json_value_free(p->v);
+ free(p);
+}
+
+static void
+objfree(void *ptr)
+{
+ struct json_value *o = ptr;
+ json_value_free(o);
+}
+
+%}
+
+%error-verbose
+%locations
+
+%token <n> T_NUMBER
+%token <s> T_STRING
+%token <b> T_BOOL
+%token T_NULL T_ERR
+
+%type <a> array
+%type <list> objects objlist pairs pairlist
+%type <p> pair
+%type <obj> object
+%type <o> assoc
+
+%union {
+ int b;
+ double n;
+ char *s;
+ struct json_array *a;
+ struct grecs_symtab *o;
+ struct json_value *obj;
+ struct grecs_list *list;
+ struct json_pair *p;
+}
+%%
+
+input : object
+ {
+ json_return_obj = $1;
+ }
+ ;
+
+object : T_NUMBER
+ {
+ $$ = json_value_create(json_number);
+ $$->v.n = $1;
+ }
+ | T_STRING
+ {
+ $$ = json_value_create(json_string);
+ $$->v.s = $1;
+ }
+ | T_BOOL
+ {
+ $$ = json_value_create(json_bool);
+ $$->v.b = $1;
+ }
+ | T_NULL
+ {
+ $$ = json_value_create(json_null);
+ }
+ | array
+ {
+ $$ = json_value_create(json_arr);
+ $$->v.a = $1;
+ }
+ | assoc
+ {
+ $$ = json_value_create(json_object);
+ $$->v.o = $1;
+ }
+ ;
+
+array : '[' objects ']'
+ {
+ struct json_array *a = grecs_malloc(sizeof(*a));
+ if (!$2) {
+ a->oc = 0;
+ a->ov = NULL;
+ } else {
+ size_t i;
+ struct grecs_list_entry *ep;
+ a->oc = $2->count;
+ a->ov = grecs_calloc(a->oc, sizeof(a->ov));
+ for (i = 0, ep = $2->head; ep; i++, ep = ep->next) {
+ struct json_value *p = ep->data;
+ a->ov[i] = p;
+ }
+ }
+ $$ = a;
+ }
+ ;
+
+objects : /* empty */
+ {
+ $$ = NULL;
+ }
+ | objlist
+ ;
+
+objlist : object
+ {
+ $$ = grecs_list_create();
+ $$->free_entry = objfree;
+ grecs_list_append($$, $1);
+ }
+ | objlist ',' object
+ {
+ grecs_list_append($1, $3);
+ }
+ ;
+
+assoc : '{' pairs '}'
+ {
+ struct grecs_symtab *s;
+
+ s = json_assoc_create();
+ if ($2) {
+ struct grecs_list_entry *ep;
+ for (ep = $2->head; ep; ep = ep->next) {
+ struct json_pair *p = ep->data;
+ int install = 1;
+ grecs_symtab_lookup_or_install(s, p, &install);
+ if (install) {
+ p->k = NULL;
+ p->v = NULL;
+ }
+ }
+ grecs_list_free($2);
+ }
+ $$ = s;
+ }
+ ;
+
+pairs : /* empty */
+ {
+ $$ = NULL;
+ }
+ | pairlist
+ ;
+
+pairlist: pair
+ {
+ $$ = grecs_list_create();
+ $$->free_entry = pairfree;
+ grecs_list_append($$, $1);
+ }
+ | pairlist ',' pair
+ {
+ grecs_list_append($1, $3);
+ }
+ ;
+
+pair : T_STRING ':' object
+ {
+ struct json_pair *p = grecs_malloc(sizeof(*p));
+ p->k = $1;
+ p->v = $3;
+ $$ = p;
+ }
+ ;
+%%
+
+static int
+yyerror(char const *s)
+{
+ jsonlex_diag(s);
+ return 0;
+}
+
+struct json_value *
+json_value_create(int type)
+{
+ struct json_value *obj = grecs_zalloc(sizeof(*obj));
+ obj->type = type;
+ return obj;
+}
+
+void
+json_value_free(struct json_value *obj)
+{
+ size_t i;
+
+ if (!obj)
+ return;
+
+ switch (obj->type) {
+ case json_null:
+ case json_bool:
+ case json_number:
+ break;
+ case json_string:
+ free(obj->v.s);
+ break;
+ case json_arr:
+ for (i = 0; i < obj->v.a->oc; i++)
+ json_value_free(obj->v.a->ov[i]);
+ free(obj->v.a);
+ break;
+ case json_object:
+ grecs_symtab_free(obj->v.o);
+ }
+ free(obj);
+}
+
+static unsigned
+json_st_hash(void *data, unsigned long n_buckets)
+{
+ struct json_pair *p = data;
+ return grecs_hash_string(p->k, n_buckets);
+}
+
+static int
+json_st_cmp(const void *a, const void *b)
+{
+ struct json_pair const *pa = a;
+ struct json_pair const *pb = b;
+ return strcmp(pa->k, pb->k);
+}
+
+static int
+json_st_copy(void *a, void *b)
+{
+ struct json_pair *pa = a;
+ struct json_pair *pb = b;
+ memcpy(pa, pb, sizeof(*pa));
+ return 0;
+}
+
+static void
+json_st_free(void *ptr)
+{
+ struct json_pair *p = ptr;
+ free(p->k);
+ json_value_free(p->v);
+ free(p);
+}
+
+struct grecs_symtab *
+json_assoc_create()
+{
+ return grecs_symtab_create(sizeof(struct json_pair),
+ json_st_hash,
+ json_st_cmp,
+ json_st_copy,
+ NULL,
+ json_st_free);
+}
+
+struct json_value *
+json_parse_string(char const *input, size_t len)
+{
+ jsonlex_setup(input, len);
+ if (yyparse()) {
+ /* FIXME: error recovery */
+ return NULL;
+ }
+ return json_return_obj;
+}
+
+struct json_value *
+json_value_lookup(struct json_value *obj, const char *ident)
+{
+ char *qbuf = NULL;
+ size_t qlen = 0;
+
+ while (obj && *ident) {
+ char const *p;
+ char *q;
+ size_t l;
+
+ for (p = ident; *p; p++) {
+ if (*p == '\\')
+ ++p;
+ else if (*p == '.')
+ break;
+ }
+ l = p - ident + 1;
+ if (l > qlen) {
+ qlen = l;
+ qbuf = grecs_realloc(qbuf, qlen);
+ }
+ q = qbuf;
+ while (*ident) {
+ if (*ident == '\\') {
+ int c;
+ ++ident;
+ if (json_unescape(*ident, &c))
+ *q++ = *ident++;
+ else
+ *q++ = c;
+ } else if (*ident == '.') {
+ ++ident;
+ break;
+ } else
+ *q++ = *ident++;
+ }
+ *q = 0;
+
+ switch (obj->type) {
+ case json_null:
+ case json_bool:
+ case json_number:
+ case json_string:
+ obj = NULL;
+ break;
+ case json_arr:
+ l = strtoul(qbuf, &q, 10);
+ if (*q == 0 && l < obj->v.a->oc)
+ obj = obj->v.a->ov[l];
+ else
+ obj = NULL;
+ break;
+ case json_object: {
+ struct json_pair key, *match;
+ key.k = qbuf;
+ match = grecs_symtab_lookup_or_install(obj->v.o,
+ &key, NULL);
+ obj = match ? match->v : NULL;
+ }
+ }
+ }
+ if (*ident)
+ obj = NULL;
+ free(qbuf);
+ return obj;
+}
+
+
+
+
+

Return to:

Send suggestions and report system problems to the System administrator.