Skip to content

Commit 461f5a4

Browse files
authored
Merge pull request miloyip#52 from miloyip/draft
Add tutorial 05
2 parents deff395 + 54cb6fd commit 461f5a4

File tree

6 files changed

+939
-1
lines changed

6 files changed

+939
-1
lines changed

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
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 完成)。
4444
4. [Unicode](tutorial04/tutorial04.md)(2016/10/2 完成):Unicode 和 UTF-8 的基本知识、JSON string 的 unicode 处理。练习完成 JSON string 类型的解析。[Unicode 解答篇](tutorial04_answer/tutorial04_answer.md)(2016/10/6 完成)。
45-
5. [解析数组](tutorial05/tutorial05.md)(2016/10/7 完成):JSON array 的语法。练习完成 JSON array 类型的解析、相关内存释放。
45+
5. [解析数组](tutorial05/tutorial05.md)(2016/10/7 完成):JSON array 的语法。练习完成 JSON array 类型的解析、相关内存释放。[解析数组解答篇](tutorial05_answer/tutorial05_answer.md)(2016/10/13 完成)。
4646
6. 解析对象:JSON object 的语法、重构 string 解析函数。练习完成 JSON object 的解析、相关内存释放。
4747
7. 生成器:JSON 生成过程、注意事项。练习完成 JSON 生成器。
4848
8. 访问:JSON array/object 的访问及修改。练习完成相关功能。

tutorial05_answer/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)

tutorial05_answer/leptjson.c

Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
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+
int i;
95+
*u = 0;
96+
for (i = 0; i < 4; i++) {
97+
char ch = *p++;
98+
*u <<= 4;
99+
if (ch >= '0' && ch <= '9') *u |= ch - '0';
100+
else if (ch >= 'A' && ch <= 'F') *u |= ch - ('A' - 10);
101+
else if (ch >= 'a' && ch <= 'f') *u |= ch - ('a' - 10);
102+
else return NULL;
103+
}
104+
return p;
105+
}
106+
107+
static void lept_encode_utf8(lept_context* c, unsigned u) {
108+
if (u <= 0x7F)
109+
PUTC(c, u & 0xFF);
110+
else if (u <= 0x7FF) {
111+
PUTC(c, 0xC0 | ((u >> 6) & 0xFF));
112+
PUTC(c, 0x80 | ( u & 0x3F));
113+
}
114+
else if (u <= 0xFFFF) {
115+
PUTC(c, 0xE0 | ((u >> 12) & 0xFF));
116+
PUTC(c, 0x80 | ((u >> 6) & 0x3F));
117+
PUTC(c, 0x80 | ( u & 0x3F));
118+
}
119+
else {
120+
assert(u <= 0x10FFFF);
121+
PUTC(c, 0xF0 | ((u >> 18) & 0xFF));
122+
PUTC(c, 0x80 | ((u >> 12) & 0x3F));
123+
PUTC(c, 0x80 | ((u >> 6) & 0x3F));
124+
PUTC(c, 0x80 | ( u & 0x3F));
125+
}
126+
}
127+
128+
#define STRING_ERROR(ret) do { c->top = head; return ret; } while(0)
129+
130+
static int lept_parse_string(lept_context* c, lept_value* v) {
131+
size_t head = c->top, len;
132+
unsigned u, u2;
133+
const char* p;
134+
EXPECT(c, '\"');
135+
p = c->json;
136+
for (;;) {
137+
char ch = *p++;
138+
switch (ch) {
139+
case '\"':
140+
len = c->top - head;
141+
lept_set_string(v, (const char*)lept_context_pop(c, len), len);
142+
c->json = p;
143+
return LEPT_PARSE_OK;
144+
case '\\':
145+
switch (*p++) {
146+
case '\"': PUTC(c, '\"'); break;
147+
case '\\': PUTC(c, '\\'); break;
148+
case '/': PUTC(c, '/' ); break;
149+
case 'b': PUTC(c, '\b'); break;
150+
case 'f': PUTC(c, '\f'); break;
151+
case 'n': PUTC(c, '\n'); break;
152+
case 'r': PUTC(c, '\r'); break;
153+
case 't': PUTC(c, '\t'); break;
154+
case 'u':
155+
if (!(p = lept_parse_hex4(p, &u)))
156+
STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX);
157+
if (u >= 0xD800 && u <= 0xDBFF) { /* surrogate pair */
158+
if (*p++ != '\\')
159+
STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE);
160+
if (*p++ != 'u')
161+
STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE);
162+
if (!(p = lept_parse_hex4(p, &u2)))
163+
STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX);
164+
if (u2 < 0xDC00 || u2 > 0xDFFF)
165+
STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE);
166+
u = (((u - 0xD800) << 10) | (u2 - 0xDC00)) + 0x10000;
167+
}
168+
lept_encode_utf8(c, u);
169+
break;
170+
default:
171+
STRING_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE);
172+
}
173+
break;
174+
case '\0':
175+
STRING_ERROR(LEPT_PARSE_MISS_QUOTATION_MARK);
176+
default:
177+
if ((unsigned char)ch < 0x20)
178+
STRING_ERROR(LEPT_PARSE_INVALID_STRING_CHAR);
179+
PUTC(c, ch);
180+
}
181+
}
182+
}
183+
184+
static int lept_parse_value(lept_context* c, lept_value* v);
185+
186+
static int lept_parse_array(lept_context* c, lept_value* v) {
187+
size_t i, size = 0;
188+
int ret;
189+
EXPECT(c, '[');
190+
lept_parse_whitespace(c);
191+
if (*c->json == ']') {
192+
c->json++;
193+
v->type = LEPT_ARRAY;
194+
v->u.a.size = 0;
195+
v->u.a.e = NULL;
196+
return LEPT_PARSE_OK;
197+
}
198+
for (;;) {
199+
lept_value e;
200+
lept_init(&e);
201+
if ((ret = lept_parse_value(c, &e)) != LEPT_PARSE_OK)
202+
break;
203+
memcpy(lept_context_push(c, sizeof(lept_value)), &e, sizeof(lept_value));
204+
size++;
205+
lept_parse_whitespace(c);
206+
if (*c->json == ',') {
207+
c->json++;
208+
lept_parse_whitespace(c);
209+
}
210+
else if (*c->json == ']') {
211+
c->json++;
212+
v->type = LEPT_ARRAY;
213+
v->u.a.size = size;
214+
size *= sizeof(lept_value);
215+
memcpy(v->u.a.e = (lept_value*)malloc(size), lept_context_pop(c, size), size);
216+
return LEPT_PARSE_OK;
217+
}
218+
else {
219+
ret = LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET;
220+
break;
221+
}
222+
}
223+
/* Pop and free values on the stack */
224+
for (i = 0; i < size; i++)
225+
lept_free((lept_value*)lept_context_pop(c, sizeof(lept_value)));
226+
return ret;
227+
}
228+
229+
static int lept_parse_value(lept_context* c, lept_value* v) {
230+
switch (*c->json) {
231+
case 't': return lept_parse_literal(c, v, "true", LEPT_TRUE);
232+
case 'f': return lept_parse_literal(c, v, "false", LEPT_FALSE);
233+
case 'n': return lept_parse_literal(c, v, "null", LEPT_NULL);
234+
default: return lept_parse_number(c, v);
235+
case '"': return lept_parse_string(c, v);
236+
case '[': return lept_parse_array(c, v);
237+
case '\0': return LEPT_PARSE_EXPECT_VALUE;
238+
}
239+
}
240+
241+
int lept_parse(lept_value* v, const char* json) {
242+
lept_context c;
243+
int ret;
244+
assert(v != NULL);
245+
c.json = json;
246+
c.stack = NULL;
247+
c.size = c.top = 0;
248+
lept_init(v);
249+
lept_parse_whitespace(&c);
250+
if ((ret = lept_parse_value(&c, v)) == LEPT_PARSE_OK) {
251+
lept_parse_whitespace(&c);
252+
if (*c.json != '\0') {
253+
v->type = LEPT_NULL;
254+
ret = LEPT_PARSE_ROOT_NOT_SINGULAR;
255+
}
256+
}
257+
assert(c.top == 0);
258+
free(c.stack);
259+
return ret;
260+
}
261+
262+
void lept_free(lept_value* v) {
263+
size_t i;
264+
assert(v != NULL);
265+
switch (v->type) {
266+
case LEPT_STRING:
267+
free(v->u.s.s);
268+
break;
269+
case LEPT_ARRAY:
270+
for (i = 0; i < v->u.a.size; i++)
271+
lept_free(&v->u.a.e[i]);
272+
free(v->u.a.e);
273+
break;
274+
default: break;
275+
}
276+
v->type = LEPT_NULL;
277+
}
278+
279+
lept_type lept_get_type(const lept_value* v) {
280+
assert(v != NULL);
281+
return v->type;
282+
}
283+
284+
int lept_get_boolean(const lept_value* v) {
285+
assert(v != NULL && (v->type == LEPT_TRUE || v->type == LEPT_FALSE));
286+
return v->type == LEPT_TRUE;
287+
}
288+
289+
void lept_set_boolean(lept_value* v, int b) {
290+
lept_free(v);
291+
v->type = b ? LEPT_TRUE : LEPT_FALSE;
292+
}
293+
294+
double lept_get_number(const lept_value* v) {
295+
assert(v != NULL && v->type == LEPT_NUMBER);
296+
return v->u.n;
297+
}
298+
299+
void lept_set_number(lept_value* v, double n) {
300+
lept_free(v);
301+
v->u.n = n;
302+
v->type = LEPT_NUMBER;
303+
}
304+
305+
const char* lept_get_string(const lept_value* v) {
306+
assert(v != NULL && v->type == LEPT_STRING);
307+
return v->u.s.s;
308+
}
309+
310+
size_t lept_get_string_length(const lept_value* v) {
311+
assert(v != NULL && v->type == LEPT_STRING);
312+
return v->u.s.len;
313+
}
314+
315+
void lept_set_string(lept_value* v, const char* s, size_t len) {
316+
assert(v != NULL && (s != NULL || len == 0));
317+
lept_free(v);
318+
v->u.s.s = (char*)malloc(len + 1);
319+
memcpy(v->u.s.s, s, len);
320+
v->u.s.s[len] = '\0';
321+
v->u.s.len = len;
322+
v->type = LEPT_STRING;
323+
}
324+
325+
size_t lept_get_array_size(const lept_value* v) {
326+
assert(v != NULL && v->type == LEPT_ARRAY);
327+
return v->u.a.size;
328+
}
329+
330+
lept_value* lept_get_array_element(const lept_value* v, size_t index) {
331+
assert(v != NULL && v->type == LEPT_ARRAY);
332+
assert(index < v->u.a.size);
333+
return &v->u.a.e[index];
334+
}

0 commit comments

Comments
 (0)