Skip to content

Commit 7be4615

Browse files
committed
(t2)solution
1 parent 2c596db commit 7be4615

File tree

3 files changed

+52
-37
lines changed

3 files changed

+52
-37
lines changed

tutorial02/leptjson.c

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
#include "leptjson.h"
22
#include <assert.h> /* assert() */
33
#include <stdlib.h> /* NULL, strtod() */
4+
#include <errno.h> /* errno, ERANGE */
5+
#include <math.h> /* HUGE_VAL */
46

57
#define EXPECT(c, ch) do { assert(*c->json == (ch)); c->json++; } while(0)
68

9+
#define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9')
10+
#define ISDIGIT1TO9(ch) ((ch) >= '1' && (ch) <= '9')
11+
712
typedef struct {
813
const char* json;
914
}lept_context;
@@ -15,49 +20,50 @@ static void lept_parse_whitespace(lept_context* c) {
1520
c->json = p;
1621
}
1722

18-
static int lept_parse_true(lept_context* c, lept_value* v) {
19-
EXPECT(c, 't');
20-
if (c->json[0] != 'r' || c->json[1] != 'u' || c->json[2] != 'e')
21-
return LEPT_PARSE_INVALID_VALUE;
22-
c->json += 3;
23-
v->type = LEPT_TRUE;
24-
return LEPT_PARSE_OK;
25-
}
26-
27-
static int lept_parse_false(lept_context* c, lept_value* v) {
28-
EXPECT(c, 'f');
29-
if (c->json[0] != 'a' || c->json[1] != 'l' || c->json[2] != 's' || c->json[3] != 'e')
30-
return LEPT_PARSE_INVALID_VALUE;
31-
c->json += 4;
32-
v->type = LEPT_FALSE;
33-
return LEPT_PARSE_OK;
34-
}
35-
36-
static int lept_parse_null(lept_context* c, lept_value* v) {
37-
EXPECT(c, 'n');
38-
if (c->json[0] != 'u' || c->json[1] != 'l' || c->json[2] != 'l')
39-
return LEPT_PARSE_INVALID_VALUE;
40-
c->json += 3;
41-
v->type = LEPT_NULL;
23+
static int lept_parse_literal(lept_context* c, lept_value* v, const char* literal, lept_type type) {
24+
size_t i;
25+
EXPECT(c, literal[0]);
26+
for (i = 0; i < literal[i + 1]; i++)
27+
if (c->json[i] != literal[i + 1])
28+
return LEPT_PARSE_INVALID_VALUE;
29+
c->json += i;
30+
v->type = type;
4231
return LEPT_PARSE_OK;
4332
}
4433

4534
static int lept_parse_number(lept_context* c, lept_value* v) {
46-
char* end;
47-
/* \TODO validate number */
48-
v->n = strtod(c->json, &end);
49-
if (c->json == end)
50-
return LEPT_PARSE_INVALID_VALUE;
51-
c->json = end;
35+
const char* p = c->json;
36+
if (*p == '-') p++;
37+
if (*p == '0') p++;
38+
else {
39+
if (!ISDIGIT1TO9(*p)) return LEPT_PARSE_INVALID_VALUE;
40+
for (p++; ISDIGIT(*p); p++);
41+
}
42+
if (*p == '.') {
43+
p++;
44+
if (!ISDIGIT(*p)) return LEPT_PARSE_INVALID_VALUE;
45+
for (p++; ISDIGIT(*p); p++);
46+
}
47+
if (*p == 'e' || *p == 'E') {
48+
p++;
49+
if (*p == '-' || *p == '+') p++;
50+
if (!ISDIGIT(*p)) return LEPT_PARSE_INVALID_VALUE;
51+
for (p++; ISDIGIT(*p); p++);
52+
}
53+
errno = 0;
54+
v->n = strtod(c->json, NULL);
55+
if (errno == ERANGE && (v->n == HUGE_VAL || v->n == -HUGE_VAL))
56+
return LEPT_PARSE_NUMBER_TOO_BIG;
5257
v->type = LEPT_NUMBER;
58+
c->json = p;
5359
return LEPT_PARSE_OK;
5460
}
5561

5662
static int lept_parse_value(lept_context* c, lept_value* v) {
5763
switch (*c->json) {
58-
case 't': return lept_parse_true(c, v);
59-
case 'f': return lept_parse_false(c, v);
60-
case 'n': return lept_parse_null(c, v);
64+
case 't': return lept_parse_literal(c, v, "true", LEPT_TRUE);
65+
case 'f': return lept_parse_literal(c, v, "false", LEPT_FALSE);
66+
case 'n': return lept_parse_literal(c, v, "null", LEPT_NULL);
6167
default: return lept_parse_number(c, v);
6268
case '\0': return LEPT_PARSE_EXPECT_VALUE;
6369
}

tutorial02/leptjson.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
typedef enum { LEPT_NULL, LEPT_FALSE, LEPT_TRUE, LEPT_NUMBER, LEPT_STRING, LEPT_ARRAY, LEPT_OBJECT } lept_type;
55

66
typedef struct {
7-
double n;
7+
double n;
88
lept_type type;
99
}lept_value;
1010

tutorial02/test.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ static void test_parse_number() {
7070
TEST_NUMBER(1.234E+10, "1.234E+10");
7171
TEST_NUMBER(1.234E-10, "1.234E-10");
7272
TEST_NUMBER(0.0, "1e-10000"); /* must underflow */
73+
TEST_NUMBER(1.0000000000000002, "1.0000000000000002"); /* the smallest number > 1 */
74+
TEST_NUMBER( 4.9406564584124654e-324, "4.9406564584124654e-324"); /* minimum denormal */
75+
TEST_NUMBER(-4.9406564584124654e-324, "-4.9406564584124654e-324");
76+
TEST_NUMBER( 2.2250738585072009e-308, "2.2250738585072009e-308"); /* Max subnormal double */
77+
TEST_NUMBER(-2.2250738585072009e-308, "-2.2250738585072009e-308");
78+
TEST_NUMBER( 2.2250738585072014e-308, "2.2250738585072014e-308"); /* Min normal positive double */
79+
TEST_NUMBER(-2.2250738585072014e-308, "-2.2250738585072014e-308");
80+
TEST_NUMBER( 1.7976931348623157e308, "1.7976931348623157e308"); /* Max double */
81+
TEST_NUMBER(-1.7976931348623157e308, "-1.7976931348623157e308");
7382
}
7483

7584
#define TEST_ERROR(error, json)\
@@ -89,7 +98,7 @@ static void test_parse_invalid_value() {
8998
TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "nul");
9099
TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "?");
91100

92-
#if 0
101+
#if 1
93102
/* invalid number */
94103
TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "+0");
95104
TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "+1");
@@ -105,7 +114,7 @@ static void test_parse_invalid_value() {
105114
static void test_parse_root_not_singular() {
106115
TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "null x");
107116

108-
#if 0
117+
#if 1
109118
/* invalid number */
110119
TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "0123"); /* after zero should be '.' or nothing */
111120
TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "0x0");
@@ -114,7 +123,7 @@ static void test_parse_root_not_singular() {
114123
}
115124

116125
static void test_parse_number_too_big() {
117-
#if 0
126+
#if 1
118127
TEST_ERROR(LEPT_PARSE_NUMBER_TOO_BIG, "1e309");
119128
TEST_ERROR(LEPT_PARSE_NUMBER_TOO_BIG, "-1e309");
120129
#endif

0 commit comments

Comments
 (0)