Skip to content

Commit a4ea3c9

Browse files
authored
Merge pull request miloyip#32 from miloyip/draft
Add tutorial04
2 parents dff6953 + 3b12a5a commit a4ea3c9

File tree

7 files changed

+727
-1
lines changed

7 files changed

+727
-1
lines changed

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
1. [启程](tutorial01/tutorial01.md)(2016/9/15 完成):编译环境、JSON 简介、测试驱动、解析器主要函数及各数据结构。练习 JSON 布尔类型的解析。[启程解答篇](tutorial01_answer/tutorial01_answer.md)(2016/9/17 完成)。
4242
2. [解析数字](tutorial02/tutorial02.md)(2016/9/18 完成):JSON number 的语法。练习 JSON number 类型的校验。[解析数字解答篇](tutorial02_answer/tutorial02_answer.md)(2016/9/20 完成)。
4343
3. [解析字符串](tutorial03/tutorial03.md)(2016/9/22 完成):使用 union 存储 variant、自动扩展的堆栈、JSON string 的语法、valgrind。练习最基本的 JSON string 类型的解析、内存释放。[解析字符串解答篇](tutorial03_answer/tutorial03_answer.md)(2016/9/27 完成)。
44-
4. Unicode:Unicode 和 UTF-8 的基本知识、JSON string 的 unicode 处理。练习完成 JSON string 类型的解析。
44+
4. [Unicode](tutorial04/tutorial04.md)(2016/10/2 完成):Unicode 和 UTF-8 的基本知识、JSON string 的 unicode 处理。练习完成 JSON string 类型的解析。
4545
5. 解析数组:JSON array 的语法。练习完成 JSON array 类型的解析、相关内存释放。
4646
6. 解析对象:JSON object 的语法、重构 string 解析函数。练习完成 JSON object 的解析、相关内存释放。
4747
7. 生成器:JSON 生成过程、注意事项。练习完成 JSON 生成器。

tutorial04/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
cmake_minimum_required (VERSION 2.6)
2+
project (leptjson_test C)
3+
4+
if (CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
5+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ansi -pedantic -Wall")
6+
endif()
7+
8+
add_library(leptjson leptjson.c)
9+
add_executable(leptjson_test test.c)
10+
target_link_libraries(leptjson_test leptjson)
36.8 KB
Loading

tutorial04/leptjson.c

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
#ifdef _WINDOWS
2+
#define _CRTDBG_MAP_ALLOC
3+
#include <crtdbg.h>
4+
#endif
5+
#include "leptjson.h"
6+
#include <assert.h> /* assert() */
7+
#include <errno.h> /* errno, ERANGE */
8+
#include <math.h> /* HUGE_VAL */
9+
#include <stdlib.h> /* NULL, malloc(), realloc(), free(), strtod() */
10+
#include <string.h> /* memcpy() */
11+
12+
#ifndef LEPT_PARSE_STACK_INIT_SIZE
13+
#define LEPT_PARSE_STACK_INIT_SIZE 256
14+
#endif
15+
16+
#define EXPECT(c, ch) do { assert(*c->json == (ch)); c->json++; } while(0)
17+
#define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9')
18+
#define ISDIGIT1TO9(ch) ((ch) >= '1' && (ch) <= '9')
19+
#define PUTC(c, ch) do { *(char*)lept_context_push(c, sizeof(char)) = (ch); } while(0)
20+
21+
typedef struct {
22+
const char* json;
23+
char* stack;
24+
size_t size, top;
25+
}lept_context;
26+
27+
static void* lept_context_push(lept_context* c, size_t size) {
28+
void* ret;
29+
assert(size > 0);
30+
if (c->top + size >= c->size) {
31+
if (c->size == 0)
32+
c->size = LEPT_PARSE_STACK_INIT_SIZE;
33+
while (c->top + size >= c->size)
34+
c->size += c->size >> 1; /* c->size * 1.5 */
35+
c->stack = (char*)realloc(c->stack, c->size);
36+
}
37+
ret = c->stack + c->top;
38+
c->top += size;
39+
return ret;
40+
}
41+
42+
static void* lept_context_pop(lept_context* c, size_t size) {
43+
assert(c->top >= size);
44+
return c->stack + (c->top -= size);
45+
}
46+
47+
static void lept_parse_whitespace(lept_context* c) {
48+
const char *p = c->json;
49+
while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')
50+
p++;
51+
c->json = p;
52+
}
53+
54+
static int lept_parse_literal(lept_context* c, lept_value* v, const char* literal, lept_type type) {
55+
size_t i;
56+
EXPECT(c, literal[0]);
57+
for (i = 0; literal[i + 1]; i++)
58+
if (c->json[i] != literal[i + 1])
59+
return LEPT_PARSE_INVALID_VALUE;
60+
c->json += i;
61+
v->type = type;
62+
return LEPT_PARSE_OK;
63+
}
64+
65+
static int lept_parse_number(lept_context* c, lept_value* v) {
66+
const char* p = c->json;
67+
if (*p == '-') p++;
68+
if (*p == '0') p++;
69+
else {
70+
if (!ISDIGIT1TO9(*p)) return LEPT_PARSE_INVALID_VALUE;
71+
for (p++; ISDIGIT(*p); p++);
72+
}
73+
if (*p == '.') {
74+
p++;
75+
if (!ISDIGIT(*p)) return LEPT_PARSE_INVALID_VALUE;
76+
for (p++; ISDIGIT(*p); p++);
77+
}
78+
if (*p == 'e' || *p == 'E') {
79+
p++;
80+
if (*p == '+' || *p == '-') p++;
81+
if (!ISDIGIT(*p)) return LEPT_PARSE_INVALID_VALUE;
82+
for (p++; ISDIGIT(*p); p++);
83+
}
84+
errno = 0;
85+
v->u.n = strtod(c->json, NULL);
86+
if (errno == ERANGE && (v->u.n == HUGE_VAL || v->u.n == -HUGE_VAL))
87+
return LEPT_PARSE_NUMBER_TOO_BIG;
88+
v->type = LEPT_NUMBER;
89+
c->json = p;
90+
return LEPT_PARSE_OK;
91+
}
92+
93+
static const char* lept_parse_hex4(const char* p, unsigned* u) {
94+
/* \TODO */
95+
return p;
96+
}
97+
98+
static void lept_encode_utf8(lept_context* c, unsigned u) {
99+
/* \TODO */
100+
}
101+
102+
#define STRING_ERROR(ret) do { c->top = head; return ret; } while(0)
103+
104+
static int lept_parse_string(lept_context* c, lept_value* v) {
105+
size_t head = c->top, len;
106+
unsigned u;
107+
const char* p;
108+
EXPECT(c, '\"');
109+
p = c->json;
110+
for (;;) {
111+
char ch = *p++;
112+
switch (ch) {
113+
case '\"':
114+
len = c->top - head;
115+
lept_set_string(v, (const char*)lept_context_pop(c, len), len);
116+
c->json = p;
117+
return LEPT_PARSE_OK;
118+
case '\\':
119+
switch (*p++) {
120+
case '\"': PUTC(c, '\"'); break;
121+
case '\\': PUTC(c, '\\'); break;
122+
case '/': PUTC(c, '/' ); break;
123+
case 'b': PUTC(c, '\b'); break;
124+
case 'f': PUTC(c, '\f'); break;
125+
case 'n': PUTC(c, '\n'); break;
126+
case 'r': PUTC(c, '\r'); break;
127+
case 't': PUTC(c, '\t'); break;
128+
case 'u':
129+
if (!(p = lept_parse_hex4(p, &u)))
130+
STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX);
131+
/* \TODO surrogate handling */
132+
lept_encode_utf8(c, u);
133+
break;
134+
default:
135+
STRING_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE);
136+
}
137+
break;
138+
case '\0':
139+
STRING_ERROR(LEPT_PARSE_MISS_QUOTATION_MARK);
140+
default:
141+
if ((unsigned char)ch < 0x20)
142+
STRING_ERROR(LEPT_PARSE_INVALID_STRING_CHAR);
143+
PUTC(c, ch);
144+
}
145+
}
146+
}
147+
148+
static int lept_parse_value(lept_context* c, lept_value* v) {
149+
switch (*c->json) {
150+
case 't': return lept_parse_literal(c, v, "true", LEPT_TRUE);
151+
case 'f': return lept_parse_literal(c, v, "false", LEPT_FALSE);
152+
case 'n': return lept_parse_literal(c, v, "null", LEPT_NULL);
153+
default: return lept_parse_number(c, v);
154+
case '"': return lept_parse_string(c, v);
155+
case '\0': return LEPT_PARSE_EXPECT_VALUE;
156+
}
157+
}
158+
159+
int lept_parse(lept_value* v, const char* json) {
160+
lept_context c;
161+
int ret;
162+
assert(v != NULL);
163+
c.json = json;
164+
c.stack = NULL;
165+
c.size = c.top = 0;
166+
lept_init(v);
167+
lept_parse_whitespace(&c);
168+
if ((ret = lept_parse_value(&c, v)) == LEPT_PARSE_OK) {
169+
lept_parse_whitespace(&c);
170+
if (*c.json != '\0') {
171+
v->type = LEPT_NULL;
172+
ret = LEPT_PARSE_ROOT_NOT_SINGULAR;
173+
}
174+
}
175+
assert(c.top == 0);
176+
free(c.stack);
177+
return ret;
178+
}
179+
180+
void lept_free(lept_value* v) {
181+
assert(v != NULL);
182+
if (v->type == LEPT_STRING)
183+
free(v->u.s.s);
184+
v->type = LEPT_NULL;
185+
}
186+
187+
lept_type lept_get_type(const lept_value* v) {
188+
assert(v != NULL);
189+
return v->type;
190+
}
191+
192+
int lept_get_boolean(const lept_value* v) {
193+
assert(v != NULL && (v->type == LEPT_TRUE || v->type == LEPT_FALSE));
194+
return v->type == LEPT_TRUE;
195+
}
196+
197+
void lept_set_boolean(lept_value* v, int b) {
198+
lept_free(v);
199+
v->type = b ? LEPT_TRUE : LEPT_FALSE;
200+
}
201+
202+
double lept_get_number(const lept_value* v) {
203+
assert(v != NULL && v->type == LEPT_NUMBER);
204+
return v->u.n;
205+
}
206+
207+
void lept_set_number(lept_value* v, double n) {
208+
lept_free(v);
209+
v->u.n = n;
210+
v->type = LEPT_NUMBER;
211+
}
212+
213+
const char* lept_get_string(const lept_value* v) {
214+
assert(v != NULL && v->type == LEPT_STRING);
215+
return v->u.s.s;
216+
}
217+
218+
size_t lept_get_string_length(const lept_value* v) {
219+
assert(v != NULL && v->type == LEPT_STRING);
220+
return v->u.s.len;
221+
}
222+
223+
void lept_set_string(lept_value* v, const char* s, size_t len) {
224+
assert(v != NULL && (s != NULL || len == 0));
225+
lept_free(v);
226+
v->u.s.s = (char*)malloc(len + 1);
227+
memcpy(v->u.s.s, s, len);
228+
v->u.s.s[len] = '\0';
229+
v->u.s.len = len;
230+
v->type = LEPT_STRING;
231+
}

tutorial04/leptjson.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#ifndef LEPTJSON_H__
2+
#define LEPTJSON_H__
3+
4+
#include <stddef.h> /* size_t */
5+
6+
typedef enum { LEPT_NULL, LEPT_FALSE, LEPT_TRUE, LEPT_NUMBER, LEPT_STRING, LEPT_ARRAY, LEPT_OBJECT } lept_type;
7+
8+
typedef struct {
9+
union {
10+
struct { char* s; size_t len; }s; /* string: null-terminated string, string length */
11+
double n; /* number */
12+
}u;
13+
lept_type type;
14+
}lept_value;
15+
16+
enum {
17+
LEPT_PARSE_OK = 0,
18+
LEPT_PARSE_EXPECT_VALUE,
19+
LEPT_PARSE_INVALID_VALUE,
20+
LEPT_PARSE_ROOT_NOT_SINGULAR,
21+
LEPT_PARSE_NUMBER_TOO_BIG,
22+
LEPT_PARSE_MISS_QUOTATION_MARK,
23+
LEPT_PARSE_INVALID_STRING_ESCAPE,
24+
LEPT_PARSE_INVALID_STRING_CHAR,
25+
LEPT_PARSE_INVALID_UNICODE_HEX,
26+
LEPT_PARSE_INVALID_UNICODE_SURROGATE
27+
};
28+
29+
#define lept_init(v) do { (v)->type = LEPT_NULL; } while(0)
30+
31+
int lept_parse(lept_value* v, const char* json);
32+
33+
void lept_free(lept_value* v);
34+
35+
lept_type lept_get_type(const lept_value* v);
36+
37+
#define lept_set_null(v) lept_free(v)
38+
39+
int lept_get_boolean(const lept_value* v);
40+
void lept_set_boolean(lept_value* v, int b);
41+
42+
double lept_get_number(const lept_value* v);
43+
void lept_set_number(lept_value* v, double n);
44+
45+
const char* lept_get_string(const lept_value* v);
46+
size_t lept_get_string_length(const lept_value* v);
47+
void lept_set_string(lept_value* v, const char* s, size_t len);
48+
49+
#endif /* LEPTJSON_H__ */

0 commit comments

Comments
 (0)