Skip to content

Commit 1f33067

Browse files
authored
Merge pull request miloyip#30 from miloyip/draft
Tutorial 03 answer
2 parents ed2d210 + b3f9de6 commit 1f33067

File tree

5 files changed

+751
-0
lines changed

5 files changed

+751
-0
lines changed

tutorial03_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)

tutorial03_answer/leptjson.c

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
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 int lept_parse_string(lept_context* c, lept_value* v) {
94+
size_t head = c->top, len;
95+
const char* p;
96+
EXPECT(c, '\"');
97+
p = c->json;
98+
for (;;) {
99+
char ch = *p++;
100+
switch (ch) {
101+
case '\"':
102+
len = c->top - head;
103+
lept_set_string(v, lept_context_pop(c, len), len);
104+
c->json = p;
105+
return LEPT_PARSE_OK;
106+
case '\\':
107+
switch (*p++) {
108+
case '\"': PUTC(c, '\"'); break;
109+
case '\\': PUTC(c, '\\'); break;
110+
case '/': PUTC(c, '/' ); break;
111+
case 'b': PUTC(c, '\b'); break;
112+
case 'f': PUTC(c, '\f'); break;
113+
case 'n': PUTC(c, '\n'); break;
114+
case 'r': PUTC(c, '\r'); break;
115+
case 't': PUTC(c, '\t'); break;
116+
default:
117+
c->top = head;
118+
return LEPT_PARSE_INVALID_STRING_ESCAPE;
119+
}
120+
break;
121+
case '\0':
122+
c->top = head;
123+
return LEPT_PARSE_MISS_QUOTATION_MARK;
124+
default:
125+
if ((unsigned char)ch < 0x20) {
126+
c->top = head;
127+
return LEPT_PARSE_INVALID_STRING_CHAR;
128+
}
129+
PUTC(c, ch);
130+
}
131+
}
132+
}
133+
134+
static int lept_parse_value(lept_context* c, lept_value* v) {
135+
switch (*c->json) {
136+
case 't': return lept_parse_literal(c, v, "true", LEPT_TRUE);
137+
case 'f': return lept_parse_literal(c, v, "false", LEPT_FALSE);
138+
case 'n': return lept_parse_literal(c, v, "null", LEPT_NULL);
139+
default: return lept_parse_number(c, v);
140+
case '"': return lept_parse_string(c, v);
141+
case '\0': return LEPT_PARSE_EXPECT_VALUE;
142+
}
143+
}
144+
145+
int lept_parse(lept_value* v, const char* json) {
146+
lept_context c;
147+
int ret;
148+
assert(v != NULL);
149+
c.json = json;
150+
c.stack = NULL;
151+
c.size = c.top = 0;
152+
lept_init(v);
153+
lept_parse_whitespace(&c);
154+
if ((ret = lept_parse_value(&c, v)) == LEPT_PARSE_OK) {
155+
lept_parse_whitespace(&c);
156+
if (*c.json != '\0') {
157+
v->type = LEPT_NULL;
158+
ret = LEPT_PARSE_ROOT_NOT_SINGULAR;
159+
}
160+
}
161+
assert(c.top == 0);
162+
free(c.stack);
163+
return ret;
164+
}
165+
166+
void lept_free(lept_value* v) {
167+
assert(v != NULL);
168+
if (v->type == LEPT_STRING)
169+
free(v->u.s.s);
170+
v->type = LEPT_NULL;
171+
}
172+
173+
lept_type lept_get_type(const lept_value* v) {
174+
assert(v != NULL);
175+
return v->type;
176+
}
177+
178+
int lept_get_boolean(const lept_value* v) {
179+
assert(v != NULL && (v->type == LEPT_TRUE || v->type == LEPT_FALSE));
180+
return v->type == LEPT_TRUE;
181+
}
182+
183+
void lept_set_boolean(lept_value* v, int b) {
184+
lept_free(v);
185+
v->type = b ? LEPT_TRUE : LEPT_FALSE;
186+
}
187+
188+
double lept_get_number(const lept_value* v) {
189+
assert(v != NULL && v->type == LEPT_NUMBER);
190+
return v->u.n;
191+
}
192+
193+
void lept_set_number(lept_value* v, double n) {
194+
lept_free(v);
195+
v->u.n = n;
196+
v->type = LEPT_NUMBER;
197+
}
198+
199+
const char* lept_get_string(const lept_value* v) {
200+
assert(v != NULL && v->type == LEPT_STRING);
201+
return v->u.s.s;
202+
}
203+
204+
size_t lept_get_string_length(const lept_value* v) {
205+
assert(v != NULL && v->type == LEPT_STRING);
206+
return v->u.s.len;
207+
}
208+
209+
void lept_set_string(lept_value* v, const char* s, size_t len) {
210+
assert(v != NULL && (s != NULL || len == 0));
211+
lept_free(v);
212+
v->u.s.s = (char*)malloc(len + 1);
213+
memcpy(v->u.s.s, s, len);
214+
v->u.s.s[len] = '\0';
215+
v->u.s.len = len;
216+
v->type = LEPT_STRING;
217+
}

tutorial03_answer/leptjson.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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+
};
26+
27+
#define lept_init(v) do { (v)->type = LEPT_NULL; } while(0)
28+
29+
int lept_parse(lept_value* v, const char* json);
30+
31+
void lept_free(lept_value* v);
32+
33+
lept_type lept_get_type(const lept_value* v);
34+
35+
#define lept_set_null(v) lept_free(v)
36+
37+
int lept_get_boolean(const lept_value* v);
38+
void lept_set_boolean(lept_value* v, int b);
39+
40+
double lept_get_number(const lept_value* v);
41+
void lept_set_number(lept_value* v, double n);
42+
43+
const char* lept_get_string(const lept_value* v);
44+
size_t lept_get_string_length(const lept_value* v);
45+
void lept_set_string(lept_value* v, const char* s, size_t len);
46+
47+
#endif /* LEPTJSON_H__ */

0 commit comments

Comments
 (0)