Skip to main content
  1. Posts/

leptjson note2

·2 mins·

leptjson note2 #

从零开始的 JSON 库教程 笔记.

重构 #

使用宏的方式简化重复部分高的函数.

JSON 数字语法 #

JSON number 类型的语法如下:

number = [ "-" ] int [ frac ] [ exp ]
int = "0" / digit1-9 *digit
frac = "." 1*digit
exp = ("e" / "E") ["-" / "+"] 1*digit

number 以十进制表示, 由四部分组成:

  • 负号, 注意这部分里正号是不合法的
  • 整数, 这部分是必需的
  • 小数
  • 指数, 指数部分由大写 E 或小写 e 开始, 之后可有正负号, 之后是一或多个数字 (0-9)

数字表示方式 #

用双精度浮点数存储 JSON 中的数字. 为 lept_value 添加成员:

typedef struct {
    double n;
    lept_type type;
}lept_value;

只有当 type == LEPT_NUMBER 时, n 才表示 JSON 数字的数值. 因此, 获取该值的 API 如下:

double lept_get_number(const lept_value* v) {
    assert(v != NULL && v->type == LEPT_NUMBER);
    return v->n;
}

用断言来保证调用 API 时类型正确.

单元测试 #

十进制转换至二进制 #

把十进制表示的字符串转换为二进制的 double . 为了简单起见, 使用标准库的 strtod 来进行转换.

  • C 库函数 double strtod(const char *str, char **endptr) 把参数 str 所指向的字符串转换为一个浮点数 (类型为 double 型) . 如果 endptr 不为空, 则指向转换中最后一个字符后的字符的指针会存储在 endptr 引用的位置.
  • 该函数返回转换后的双精度浮点数. 如果没有执行有效的转换, 则返回零 (0.0) .

strtod 可转换 JSON 所要求的格式, 但一些 JSON 不容许的格式, strtod 也可转换, 因此需要自行进行格式校验.

# include <stdlib.h>  /* NULL, strtod() */

static int lept_parse_number(lept_context* c, lept_value* v) {
    char* end;
    /* \TODO validate number */
    v->n = strtod(c->json, &end);
    if (c->json == end) // end 指向位置与原指针相同, 转换失败 
        return LEPT_PARSE_INVALID_VALUE;
    c->json = end; // 指向数字后的字符串
    v->type = LEPT_NUMBER;
    return LEPT_PARSE_OK;
}

由于 lept_parse_number() 内部将会校验输入是否正确的值, 因此 lept_parse_value() 可以这样编写:

static int lept_parse_value(lept_context* c, lept_value* v) {
    switch (*c->json) {
        case 't':  return lept_parse_true(c, v);
        case 'f':  return lept_parse_false(c, v);
        case 'n':  return lept_parse_null(c, v);
        default:   return lept_parse_number(c, v);
        case '\0': return LEPT_PARSE_EXPECT_VALUE;
    }
}