Skip to content

pench3r/Simple-Json-Library

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Simple-Json-Library

主要通过https://github.com/miloyip/json-tutorial中的文档进行指引开发的

目标:

  • 熟悉一个独立项目的构建过程
  • 学习测试驱动开发(test driven development, TDD)
  • API设计
  • 数据结构设计

1. 解析true,false,null语法

json-text = ws value ws
ws = *(%x20 / %x09 / %x0a / %x0d)
value = null / true / false
null = "null"
true = "true"
false = "false"

其中%xh代表十六禁止,/代表或的意思,*代表0至多,()代表为一组

第一行代表由3部分组成第一部分ws,第二部分value,第三部分为ws

第二行代表什么为ws,有0至多个空格符(space U+0020)、制表符(tab U+0009)、换行符(LF U+000A)、回车符(CR U+000D)所组成

第三行表示value目前的表示为null、true、false,而剩下的内容则是表明它们都是依次通过对应的literal来表示

2. 解析number语法

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

number主要是由四部分组成,第一部分符号位是否为负数,缺省为整数,第二部分为int代表的数字,第三部分为小数点部分的值,第四部分代表科学计数法的表示

第二行表示int的组成为2种形式开头如果为0,那么只有一个0;另外一种形式为非零开头后面带着0至多个数字

第三行表示小数点部分的组成为以.开头并附带1至多的数字

第四行表示科学计数法的组成方式,第一部分为必须存在的e或者E,第二部分为可存在的-或者+,第三部分为固定的1至多个数字

同时添加了SIMPLEJ_PARSE_NUMBER_TOO_BIG的解析错误,主要是依靠strtod转换时的返回值来判断,超出范围的话会返回HUGE_VAL或者-HUGE_VAL,并且会将errno设置为ERANGE

3. 解析string语法

string = quotation-mark *char quotation-mark
char = unescaped /
   escape (
       %x22 /          ; "    quotation mark  U+0022
       %x5C /          ; \    reverse solidus U+005C
       %x2F /          ; /    solidus         U+002F
       %x62 /          ; b    backspace       U+0008
       %x66 /          ; f    form feed       U+000C
       %x6E /          ; n    line feed       U+000A
       %x72 /          ; r    carriage return U+000D
       %x74 /          ; t    tab             U+0009
       %x75 4HEXDIG )  ; uXXXX                U+XXXX
escape = %x5C          ; \
quotation-mark = %x22  ; "
unescaped = %x20-21 / %x23-5B / %x5D-10FFFF

string是由双引号所包围的,在测试的时候传入json测试字符串时为"\"hello\""格式,期望解析到的为"hello".

对于char的值主要分为转义和非转义的,非法的字符为小于0x20的.

还有针对与\uxxxx格式的需要先转化成为对应的码点,然后使用utf8的编码进行保存.

涉及到的数据结构,在接收解析结果的数据结构SIMPLEJ_VALUE中添加保存字符串的字段,这里为了节省内存,使用union添加字符串保存的字段,定义如下:

typedef struct simplej_value {
	struct union {
		struct union { char *s; size_t len; }s;
		double number;
	}u;
	SIMPLEJ_TYPE sj_type;
}

在解析字符串的时候,使用了类似栈的方式进行字符串每个字符的解析结果存储,思路是通过判断每个字符然后依次压栈,并更新相应的长度;当遇到\"时则根据长度将字符串弹出栈;通过simplejson_context_push将字符串保存到SIMPLEJ_VALUE结构体中;在SIMPLEJ_CONTEXT中新增了stacktop进行栈的功能实现.

新增的解析错误类型: SIMPLEJ_PARSE_INVALID_STRING_CHARSIMPLEJ_PARSE_INVALID_MISS_QUOTATION_MARKSIMPLEJ_PARSE_INVALID_ESCAPE.

4. 解析JSON数组语法

JSON数组是一种复合类型的结构,语法如下:

array = %x5B ws [ value *( ws %x2C ws value ) ] ws %x5D

包含的value为null、false、true、string、number、array等类型,每个value以,间隔;

首先了解我们如何去解析和保存array.这里依然使用解析string时使用的动态栈,由于array中的每个元素都是可以使用SIMPLEJ_VALUE来保存,因此在解析的过程中使用stack(这里使用simplejson_context_push来进行保存,函数的定义可以满足任何类型数据的保存,以为需要自己传入len这样的设计复用性很高)来依次保存解析出来的每个SIMPLEJ_VALUE;在保存的时候根据解析出来的VALUE个数再去动态创建SIMPLEJ_VALUE数组,这样就节省空间以及提升效率;

涉及的数据结构:

typedef struct { union { struct { SIMPLEJ_VALUE element; size_t size;}a; struct { char s; size_t len;}s; double number; }u; }

对于context中的结构不需要变动即可满足需求,在解析array时使用递归的方式调用simplejson_parse_value来识别各种类型的值.

错误类型添加了: SIMPLEJ_PARSE_MISS_COMMA_OR_SQUARE_BRACKET

5. 解析object语法

object主要是由{}进行包围的键值对,键为字符串,值为之前对应的各种类型,语法如下:

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

这里解析的思路与数组相同,也是在解析的过程以每个member进行解析,分为两部分先解析key的字符串,接着解析对应的value并判断是否以:为间隔符;

相关的数据结构:

struct SIMPLEJ_VALUE {
	union {
		struct {SIMPLEJ_MEMBER *member; size_t size;}o;
		...	
	}u;
	...
};

stuct SIMPLEJ_MEMBER {
	char *key; size_t klen;
	SIMPLEJ_VALUE value;
}

添加的错误类型: SIMPLEJ_PARSE_MISS_KEYSIMPLEJ_PARSE_MISS_COLONSIMPLEJ_PARSE_MISS_COMMA_OR_CURLY_BRACKET

中间遇到的一些问题

  • 在宏中想尝试根据不同的type来返回不同的字符串,这时由于参数的类型不固定,导致编译不通过,必须通过强制类型转换才能保证编译通过,因为C是强类型的语言
  • 在解析字符串时,最后需要使用utf8的编码函数将对应的码点解析成相应的十六进制然后每个字节再进行保存
  • 在调试array中碰到的一个bug,解析string时,在调用set_simplejson_string时引用的参数地址没有符合函数的需求,导致在test时出现了诡异的错误
  • 只有c99以上的标准才支持size_t的格式化字符输出%zu

About

A Simple Json Library

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published