json解析器

json格式

json 分为种类型 一种是包含键值对的对象 一种是值的序列,即是数组 具体可以分为从此例子可看出,JSON 是树状结构,而 JSON 只包含 6 种数据类型:
null: 表示为 null
boolean: 表示为 true 或 false
number: 一般的浮点数表示方式
string: 表示为 “…”
array: 表示为 [ … ]
object: 表示为 { … }

json库的需求:
(1) 把 JSON 文本解析为一个树状数据结构
(2) 提供接口访问该数据结构
(3) 把数据结构转换成 JSON 文本

提供一个向下递归的解析器 解析的规则如下所示:
n ➔ null
t ➔ true
f ➔ false
“ ➔ string
0-9/- ➔ number
[ ➔ array
{ ➔ object

unicode是一种编码方式,映射字符为码点,utf-8/16/32是计算机内部对unicode的三种存储方式,utf-8是可变长度编码,与ASCII兼容。如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的字节数,其余各字节均以10开头。

解析null true false

判断字符串的开始字符 ‘n’ ‘t’ ‘f’ 并进行相应操作

static int wizz_parse_literal(wizz_context *c, wizz_value* v, const char* literal, wizz_type type){
expect(c,literal[0]);
size_t i;
for(i=0;literal[i+1];i++)
{
    if(c->json[i]!=literal[i+1])
        return WIZZ_PARSE_INVALID_VALUE;
}

c->json += i;
v->type = type;
return WIZZ_PARSE_OK;}

解析数字

strtod (const char* str, char**endptr); 

Convert string to double str目标字符串 endptr 转换成功返回数字字符串最后一位的后一位

使用strtod函数解析数字:

static int wizz_parse_number(wizz_context* c, wizz_value* v)
{
    char *end;
    v->n = strtod(c->json, &end);

    if(c->json == end)
        return WIZZ_PARSE_INVALID_VALUE;
     c->json = end;
     v->type = WIZZ_NUMBER;
     return WIZZ_PARSE_OK;}

利用stack存储字符串 判断“作为字符串开始 另一个”作为结束 判断转移字符

static void put_ch(wizz_context* c, char ch)
{
    *(char*)wizz_context_push(c, sizeof(char)) = ch;
}

static int wizz_parse_string(wizz_context* c, wizz_value* v){
expect(c, '\"');
size_t head=c->top, len;
const char* p = c->json;
while(true)
{
    char ch = *p++;
    switch (ch) {
    case '\"':
        len = c->top - head;
        wizz_set_string(v, (const char*)wizz_context_pop(c, len), len);
        c->json = p;
        return WIZZ_PARSE_OK;
    case '\0':
        c->top = head;
        return WIZZ_PARSE_MISS_QUOTATION_MARK;
    case '\\':
        switch (*p++) {
            case '\"': put_ch(c, '\"'); break;
            case '\\': put_ch(c, '\\'); break;
            case '/':  put_ch(c, '/' ); break;
            case 'b':  put_ch(c, '\b'); break;
            case 'f':  put_ch(c, '\f'); break;
            case 'n':  put_ch(c, '\n'); break;
            case 'r':  put_ch(c, '\r'); break;
            case 't':  put_ch(c, '\t'); break;
            default:
                 c->top = head;
                 return WIZZ_PARSE_INVALID_STRING_ESCAPE;
            }
            break;
    default:
        put_ch(c, ch);
    }

}}

解析数组

利用栈存储数组元素 遇到’[‘进入数组解析 开始解析元素,解析’,’前的元素 遇到’]’出栈 将栈中所有元素存储为数组元素,具体代码如下所示:

static int wizz_parse_array(wizz_context* c, wizz_value* v){
size_t size = 0;
int ret;

expect(c, '[');
wizz_parse_whitespace(c);
if(*c->json == ']')
{
    c->json++;
    v->type = WIZZ_ARRAY;
    v->u.a.size = 0;
    v->u.a.e = NULL;
    return WIZZ_PARSE_OK;
}

while(true)
{
    wizz_value e;
    wizz_init(&e);
    if((ret = wizz_parse_value(c, &e)) != WIZZ_PARSE_OK)
        break;
    wizz_parse_whitespace(c);
    printf("value type:%d\n", e.type);
    memcpy(wizz_context_push(c, sizeof(wizz_value)), &e, sizeof(wizz_value));
    size++;

    if(*c->json==',')
    {
        c->json++;
        wizz_parse_whitespace(c);
    }
    else if(*c->json == ']'){
        c->json++;
        v->type = WIZZ_ARRAY;
        v->u.a.size = size;
        size *= sizeof(wizz_value);
        memcpy(v->u.a.e=(wizz_value* )malloc(size), wizz_context_pop(c, size),size);
        return WIZZ_PARSE_OK;
    }
    else{

        ret = WIZZ_PARSE_MISS_COMMA_OR_SQUARE_BRACKET;
        break;
    }
}
// avoid memory leak
for(size_t i=0;i<size;i++)
{
    wizz_free((wizz_value*)wizz_context_pop(c, sizeof(wizz_value)));
}

return ret;}

解析对象

使用动态数组存储键 使用自定义的wizz_value(解析数字 数组等)作为值

object = %x7B ws [ member *( ws %x2C ws member ) ] ws %x7D

根据上述格式进行递归

static int wizz_parse_object(wizz_context* c, wizz_value* v){
expect(c, '{');
wizz_member m;
int ret;
size_t size;
wizz_parse_whitespace(c);
if(*c->json=='}')
{
    c->json++;
    v->type = WIZZ_OBJECT;
    v->u.o.size = 0;
    v->u.o.m = 0;
    return WIZZ_PARSE_OK;
}

m.k = NULL;
size = 0;

while(true)
{
    wizz_init(&m.v);
    char* str;

    if(*c->json!='"')
    {
        ret = WIZZ_PARSE_MISS_KEY;
        break;
    }
    if((ret=wizz_parse_string_raw(c,&str,&m.klen))!=WIZZ_PARSE_OK)
        break;

    memcpy(m.k=(char*)malloc(m.klen+1), str, m.klen);
    m.k[m.klen] = '\0';
    wizz_parse_whitespace(c);
    if(*c->json!=':')
    {
        ret = WIZZ_PARSE_MISS_COLON;
        break;
    }
    c->json++;
    wizz_parse_whitespace(c);

    if((ret=wizz_parse_value(c,&m.v))!=WIZZ_PARSE_OK)
        break;
    memcpy(wizz_context_push(c, sizeof(wizz_member)), &m, sizeof(wizz_member));
    size++;

    // prepare for the next parse
    m.k = NULL;

    wizz_parse_whitespace(c);
    if(*c->json == ',')
    {
        c->json++;
        wizz_parse_whitespace(c);

    }else if(*c->json == '}')
    {
        c->json++;
        v->type = WIZZ_OBJECT;
        v->u.o.size = size;
        size_t s = sizeof(wizz_member)*size;
        memcpy(v->u.o.m = (wizz_member*)malloc(s),wizz_context_pop(c, s),s);
        return WIZZ_PARSE_OK;
    }else{
        ret = WIZZ_PARSE_MISS_COMMA_OR_CURLY_BRACKET;
        break;
    }
}

free(m.k);
for(size_t i=0;i<size;i++)
{
    wizz_member* tmp = (wizz_member*)wizz_context_push(c, sizeof(wizz_member));
    free(tmp->k);
    wizz_free(&tmp->v);
}
v->type = WIZZ_NULL;
return ret;}

生成器

json解析的逆过程 将存储在wizz_value的数据根据类型存储到栈中 将栈的字符串弹出 即是原始字符串

解析字符串

static void wizz_stringify_string(wizz_context* c, const char* s, size_t len) {
size_t i;
assert(s != NULL);
put_ch(c, '"');
for (i = 0; i < len; i++) {
    unsigned char ch = (unsigned char)s[i];
    switch (ch) {
        case '\"': put_s(c, "\\\"", 2); break;
        case '\\': put_s(c, "\\\\", 2); break;
        case '\b': put_s(c, "\\b",  2); break;
        case '\f': put_s(c, "\\f",  2); break;
        case '\n': put_s(c, "\\n",  2); break;
        case '\r': put_s(c, "\\r",  2); break;
        case '\t': put_s(c, "\\t",  2); break;
        default:
            if (ch < 0x20) {
                char buffer[7];
                sprintf(buffer, "\\u%04X", ch);
                put_s(c, buffer, 6);
            }
            else
                put_ch(c, s[i]);
    }
}
put_ch(c, '"');}

解析函数 结果存储在json

int wizz_stringify( wizz_value* v,char** json, size_t* length){
assert(v!=NULL);
assert(json!=NULL);
wizz_context c;
int ret;
c.stack= (char*)malloc(c.size = WIZZ_PARSE_STRINGIFY_INIT_SIZE);
c.top = 0;
if((ret=wizz_stringify_value(&c,v)) != WIZZ_STRINGIFY_OK)
{
    free(c.stack);
    *json = NULL;
    return ret;
}
put_ch(&c, '\0');
if(length)
    *length = c.top - 1;
*json = c.stack;
return WIZZ_STRINGIFY_OK;}

根据不同类型 选择不同方式将内容入栈

int wizz_stringify_value(wizz_context *c, wizz_value *v){
switch (v->type) {
case WIZZ_NULL:
    put_s(c,"null",4);
    break;
case WIZZ_TRUE:
    put_s(c, "true",4);
    break;
case WIZZ_FALSE:
    put_s(c, "false",5);
    break;
case WIZZ_NUMBER:
{
    char* buffer = (char *)wizz_context_push(c, 32);
    int length = sprintf(buffer, "%.17g", v->u.n);
    c->top -=32-length;
}
    break;
case WIZZ_STRING:
    wizz_stringify_string(c,v->u.s.s, v->u.s.len);
    break;
case WIZZ_ARRAY:
{
    put_ch(c, '[');

    for(size_t i= 0;i<v->u.a.size;i++)
    {
        if(i>0)
            put_ch(c, ',');
        wizz_stringify_value(c,&v->u.a.e[i]);
    }

    put_ch(c, ']');
}
    break;
case WIZZ_OBJECT:
{
    put_ch(c, '{');

    for(size_t i = 0;i<v->u.o.size;i++)
    {
        if(i>0)
            put_ch(c, ',');
        wizz_stringify_string(c, v->u.o.m[i].k, v->u.o.m[i].klen);
        put_ch(c, ':');
        wizz_stringify_value(c, &v->u.o.m[i].v);
    }
    put_ch(c,'}');
}
    break;
}

return WIZZ_STRINGIFY_OK;}

参考: https://zhuanlan.zhihu.com/json-tutorial