Skip to content

Commit 8073fc7

Browse files
committed
Add tutorial03 answer draft
1 parent ed2d210 commit 8073fc7

File tree

5 files changed

+706
-0
lines changed

5 files changed

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

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)