From cbc9adb41855b66887e42208c339bcf8b48380e5 Mon Sep 17 00:00:00 2001 From: Heng Li Date: Sat, 29 Nov 2014 11:48:11 -0500 Subject: [PATCH] A light-weight JSON parser --- kson.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kson.h | 31 +++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 kson.c create mode 100644 kson.h diff --git a/kson.c b/kson.c new file mode 100644 index 0000000..8aa8fa1 --- /dev/null +++ b/kson.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include "kson.h" + +kson_node_t *kson_parse_core(const char *json, int *_n) +{ + int *stack = 0, top = 0, max = 0, n_a = 0, m_a = 0, i; + kson_node_t *a = 0, *u; + const char *p, *q; + +#define __push_back(y) do { \ + if (top == max) { \ + max = max? max<<1 : 4; \ + stack = (int*)realloc(stack, sizeof(int) * max); \ + } \ + stack[top++] = (y); \ + } while (0) + +#define __new_node(z) do { \ + if (n_a == m_a) { \ + int old_m = m_a; \ + m_a = m_a? m_a<<1 : 4; \ + a = (kson_node_t*)realloc(a, sizeof(kson_node_t) * m_a); \ + memset(a + old_m, 0, sizeof(kson_node_t) * (m_a - old_m)); \ + } \ + *(z) = &a[n_a++]; \ + } while (0) + + for (p = json; *p; ++p) { + while (*p && isblank(*p)) ++p; + if (*p == 0) break; + if (*p == ',') { // comma is somewhat redundant + } else if (*p == '[' || *p == '{') { + int t = *p == '['? -1 : -2; + if (top < 2 || stack[top-1] != -3) { // unnamed internal node + __push_back(n_a); + __new_node(&u); + __push_back(t); + } else stack[top-1] = t; // named internal node + } else if (*p == ']' || *p == '}') { + int i, start, t = *p == ']'? -1 : -2; + for (i = top - 1; i >= 0 && stack[i] != t; --i); + start = i; + u = &a[stack[start-1]]; + u->n = top - 1 - start; + u->v.child = (int*)malloc(u->n * sizeof(int)); + for (i = start + 1; i < top; ++i) + u->v.child[i - start - 1] = stack[i]; + u->type = *p == ']'? KSON_TYPE_ANGLE : KSON_TYPE_CURLY; + top = start; + } else if (*p == ':') { + if (top > 0) __push_back(-3); + } else { + int c = *p, type = c == '\''? KSON_TYPE_SGL_QUOTE : c == '"'? KSON_TYPE_DBL_QUOTE : KSON_TYPE_NO_QUOTE; + char *r; + + if (c == '\'' || c == '"') { + for (q = ++p; *q && *q != c; ++q) + if (*q == '\\') ++q; + } else { + for (q = p; *q && *q != ']' && *q != '}' && *q != ',' && *q != ':'; ++q) + if (*q == '\\') ++q; + } + r = malloc(q - p + 1); strncpy(r, p, q - p); r[q-p] = 0; // equivalent to r=strndup(p, q-p) + p = c == '\'' || c == '"'? q : q - 1; + + if (top >= 2 && stack[top-1] == -3) { // this string is a value + --top; + a[stack[top-1]].v.str = r; + a[stack[top-1]].type = type; + } else { // this string is a key + __push_back(n_a); + __new_node(&u); + u->key = r, u->type = type; + } + } + } + for (i = 0; i < n_a; ++i) // for arrays, move key to v.str + if (a[i].n == 0 && a[i].v.str == 0) + a[i].v.str = a[i].key, a[i].key = 0; + + free(stack); + *_n = n_a; + return a; +} + +void kson_print_recur(kson_node_t *nodes, kson_node_t *p) +{ + if (p->key) { + printf("\"%s\"", p->key); + if (p->v.str) putchar(':'); + } + if (p->n) { + int i; + putchar(p->type == KSON_TYPE_ANGLE? '[' : '{'); + for (i = 0; i < p->n; ++i) { + if (i) putchar(','); + kson_print_recur(nodes, &nodes[p->v.child[i]]); + } + putchar(p->type == KSON_TYPE_ANGLE? ']' : '}'); + } else if (p->v.str) { + if (p->type != KSON_TYPE_NO_QUOTE) + putchar(p->type == KSON_TYPE_SGL_QUOTE? '\'' : '"'); + printf("%s", p->v.str); + if (p->type != KSON_TYPE_NO_QUOTE) + putchar(p->type == KSON_TYPE_SGL_QUOTE? '\'' : '"'); + } +} + +#ifdef KSON_MAIN +int main(int argc, char *argv[]) +{ + kson_node_t *nodes; + int n_nodes; + nodes = kson_parse_core("{'a':1, 'b':[1,'c']}", &n_nodes); + kson_print_recur(nodes, &nodes[0]); + putchar('\n'); + return 0; +} +#endif diff --git a/kson.h b/kson.h new file mode 100644 index 0000000..a3702ec --- /dev/null +++ b/kson.h @@ -0,0 +1,31 @@ +#ifndef KSON_H +#define KSON_H + +#include + +#define KSON_TYPE_NO_QUOTE 1 +#define KSON_TYPE_SGL_QUOTE 2 +#define KSON_TYPE_DBL_QUOTE 3 +#define KSON_TYPE_ANGLE 4 +#define KSON_TYPE_CURLY 5 + +typedef struct { + uint64_t type:3, n:61; + char *key; + union { + int *child; + char *str; + } v; +} kson_node_t; + +#ifdef __cplusplus +extern "C" { +#endif + + kson_node_t *kson_parse_core(const char *json, int *n); + +#ifdef __cplusplus +} +#endif + +#endif -- 2.47.3