From e925c8eb29dba5583ee51bdadfe36c31838fb9c8 Mon Sep 17 00:00:00 2001 From: xmfbit Date: Mon, 2 Jan 2017 12:07:46 +0800 Subject: [PATCH 1/9] complete tutor01 --- tutorial01/leptjson.c | 32 +++++++++++++++++++++++++++++++- tutorial01/leptjson.h | 10 ++++++---- tutorial01/test.c | 16 ++++++++++++++++ 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/tutorial01/leptjson.c b/tutorial01/leptjson.c index 5299fe1d..a3925f97 100644 --- a/tutorial01/leptjson.c +++ b/tutorial01/leptjson.c @@ -24,9 +24,32 @@ static int lept_parse_null(lept_context* c, lept_value* v) { return LEPT_PARSE_OK; } +static int lept_parse_false(lept_context* c, lept_value* v) { + EXPECT(c, 'f'); + if(c->json[0] != 'a' || c->json[1] != 'l' + || c->json[2] != 's' || c->json[3] != 'e') { + return LEPT_PARSE_INVALID_VALUE; + } + c->json += 4; + v->type = LEPT_FALSE; + return LEPT_PARSE_OK; +} + +static int lept_parse_true(lept_context* c, lept_value* v) { + EXPECT(c, 't'); + if(c->json[0] != 'r' || c->json[1] != 'u' || c->json[2] != 'e') { + return LEPT_PARSE_INVALID_VALUE; + } + c->json += 3; + v->type = LEPT_TRUE; + return LEPT_PARSE_OK; +} + static int lept_parse_value(lept_context* c, lept_value* v) { switch (*c->json) { case 'n': return lept_parse_null(c, v); + case 'f': return lept_parse_false(c, v); + case 't': return lept_parse_true(c, v); case '\0': return LEPT_PARSE_EXPECT_VALUE; default: return LEPT_PARSE_INVALID_VALUE; } @@ -34,11 +57,18 @@ static int lept_parse_value(lept_context* c, lept_value* v) { int lept_parse(lept_value* v, const char* json) { lept_context c; + int type; assert(v != NULL); c.json = json; v->type = LEPT_NULL; lept_parse_whitespace(&c); - return lept_parse_value(&c, v); + if((type = lept_parse_value(&c, v)) == LEPT_PARSE_OK) { + lept_parse_whitespace(&c); + if(c.json[0] != '\0') { + type = LEPT_PARSE_ROOT_NOT_SINGULAR; + } + } + return type; } lept_type lept_get_type(const lept_value* v) { diff --git a/tutorial01/leptjson.h b/tutorial01/leptjson.h index 9b65d22a..eea09e4d 100644 --- a/tutorial01/leptjson.h +++ b/tutorial01/leptjson.h @@ -1,17 +1,19 @@ #ifndef LEPTJSON_H__ #define LEPTJSON_H__ +/* JSON types */ typedef enum { LEPT_NULL, LEPT_FALSE, LEPT_TRUE, LEPT_NUMBER, LEPT_STRING, LEPT_ARRAY, LEPT_OBJECT } lept_type; typedef struct { lept_type type; }lept_value; +/* parsing state */ enum { - LEPT_PARSE_OK = 0, - LEPT_PARSE_EXPECT_VALUE, - LEPT_PARSE_INVALID_VALUE, - LEPT_PARSE_ROOT_NOT_SINGULAR + LEPT_PARSE_OK = 0, + LEPT_PARSE_EXPECT_VALUE, + LEPT_PARSE_INVALID_VALUE, + LEPT_PARSE_ROOT_NOT_SINGULAR }; int lept_parse(lept_value* v, const char* json); diff --git a/tutorial01/test.c b/tutorial01/test.c index e7672181..a88a4a3b 100644 --- a/tutorial01/test.c +++ b/tutorial01/test.c @@ -27,6 +27,20 @@ static void test_parse_null() { EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v)); } +static void test_parse_true() { + lept_value v; + v.type = LEPT_FALSE; + EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "true")); + EXPECT_EQ_INT(LEPT_TRUE, lept_get_type(&v)); +} + +static void test_parse_false() { + lept_value v; + v.type = LEPT_TRUE; + EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "false")); + EXPECT_EQ_INT(LEPT_FALSE, lept_get_type(&v)); +} + static void test_parse_expect_value() { lept_value v; @@ -59,6 +73,8 @@ static void test_parse_root_not_singular() { static void test_parse() { test_parse_null(); + test_parse_false(); + test_parse_true(); test_parse_expect_value(); test_parse_invalid_value(); test_parse_root_not_singular(); From 4c0b32c35b89634b4ae903577a3a7386d76a384e Mon Sep 17 00:00:00 2001 From: xmfbit Date: Mon, 2 Jan 2017 23:12:56 +0800 Subject: [PATCH 2/9] complete tutor2 --- tutorial02/leptjson.c | 71 +++++++++++++++++++++++++------------------ tutorial02/test.c | 16 +++++----- 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/tutorial02/leptjson.c b/tutorial02/leptjson.c index 7693e43b..9fcfa47f 100644 --- a/tutorial02/leptjson.c +++ b/tutorial02/leptjson.c @@ -1,8 +1,11 @@ #include "leptjson.h" #include /* assert() */ #include /* NULL, strtod() */ - +#include +#include #define EXPECT(c, ch) do { assert(*c->json == (ch)); c->json++; } while(0) +#define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9') +#define ISDIGIT1TO9(ch) ((ch) >= '1' && (ch) <= '9') typedef struct { const char* json; @@ -15,37 +18,47 @@ static void lept_parse_whitespace(lept_context* c) { c->json = p; } -static int lept_parse_true(lept_context* c, lept_value* v) { - EXPECT(c, 't'); - if (c->json[0] != 'r' || c->json[1] != 'u' || c->json[2] != 'e') - return LEPT_PARSE_INVALID_VALUE; - c->json += 3; - v->type = LEPT_TRUE; - return LEPT_PARSE_OK; -} - -static int lept_parse_false(lept_context* c, lept_value* v) { - EXPECT(c, 'f'); - if (c->json[0] != 'a' || c->json[1] != 'l' || c->json[2] != 's' || c->json[3] != 'e') - return LEPT_PARSE_INVALID_VALUE; - c->json += 4; - v->type = LEPT_FALSE; - return LEPT_PARSE_OK; -} - -static int lept_parse_null(lept_context* c, lept_value* v) { - EXPECT(c, 'n'); - if (c->json[0] != 'u' || c->json[1] != 'l' || c->json[2] != 'l') - return LEPT_PARSE_INVALID_VALUE; - c->json += 3; - v->type = LEPT_NULL; +static int lept_parse_literal(lept_context* c, lept_value* v, + const char* json, int type) { + int i, len = strlen(json); + for(i = 0; i < len; ++i) { + if(c->json[i] != json[i]) return LEPT_PARSE_INVALID_VALUE; + } + v->type = type; + c->json += len; return LEPT_PARSE_OK; } static int lept_parse_number(lept_context* c, lept_value* v) { char* end; - /* \TODO validate number */ + const char* ptr = c->json; + if(*ptr == '-') ++ptr; + if(!ISDIGIT(*ptr)) return LEPT_PARSE_INVALID_VALUE; + if(*ptr == '0') { + if(ptr[1] != '\0' && ptr[1] != '.') return LEPT_PARSE_ROOT_NOT_SINGULAR; /*after zero should be '.' or nothing*/ + } + while(*ptr != '\0' && ISDIGIT(*ptr)) ptr++; + if(*ptr != '\0') { + if(*ptr == '.') { + ++ptr; + if(*ptr == '\0') return LEPT_PARSE_INVALID_VALUE; /*at least one digit after '.'*/ + } + while(*ptr != '\0' && ISDIGIT(*ptr)) ++ptr; + if(*ptr != '\0') { + if(*ptr != 'E' && *ptr != 'e') return LEPT_PARSE_INVALID_VALUE; + ++ptr; + if(!ISDIGIT(*ptr)) { + if(*ptr != '+' && *ptr != '-') return LEPT_PARSE_INVALID_VALUE; + ++ptr; + } + while(*ptr != '\0' && ISDIGIT(*ptr)) ++ptr; + } + } v->n = strtod(c->json, &end); + if(!isfinite(v->n)) { + /* overflow */ + return LEPT_PARSE_NUMBER_TOO_BIG; + } if (c->json == end) return LEPT_PARSE_INVALID_VALUE; c->json = end; @@ -55,9 +68,9 @@ static int lept_parse_number(lept_context* c, lept_value* v) { static int lept_parse_value(lept_context* c, lept_value* v) { switch (*c->json) { - case 't': return lept_parse_true(c, v); - case 'f': return lept_parse_false(c, v); - case 'n': return lept_parse_null(c, v); + case 't': return lept_parse_literal(c, v, "true", LEPT_TRUE); + case 'f': return lept_parse_literal(c, v, "false", LEPT_FALSE); + case 'n': return lept_parse_literal(c, v, "null", LEPT_NULL); default: return lept_parse_number(c, v); case '\0': return LEPT_PARSE_EXPECT_VALUE; } diff --git a/tutorial02/test.c b/tutorial02/test.c index 6e3ebed2..e642f0cc 100644 --- a/tutorial02/test.c +++ b/tutorial02/test.c @@ -70,6 +70,11 @@ static void test_parse_number() { TEST_NUMBER(1.234E+10, "1.234E+10"); TEST_NUMBER(1.234E-10, "1.234E-10"); TEST_NUMBER(0.0, "1e-10000"); /* must underflow */ + /* add some bondary conditions */ + TEST_NUMBER(2.2250738585072009E-308, "2.2250738585072009E-308"); /* max subnormal double */ + TEST_NUMBER(5E-324, "5E-324"); /* max subnormal postive double */ + TEST_NUMBER(1.7976931348623157E308, "1.7976931348623157E308"); /* max double */ + TEST_NUMBER(2.2250738585072014E-308, "2.2250738585072014E-308"); /* min normal positive double */ } #define TEST_ERROR(error, json)\ @@ -88,36 +93,31 @@ static void test_parse_expect_value() { static void test_parse_invalid_value() { TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "nul"); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "?"); - -#if 0 /* invalid number */ + TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "."); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "+0"); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "+1"); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, ".123"); /* at least one digit before '.' */ TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "1."); /* at least one digit after '.' */ + TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "0."); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "INF"); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "inf"); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "NAN"); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "nan"); -#endif } static void test_parse_root_not_singular() { TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "null x"); - -#if 0 /* invalid number */ + TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "0123."); TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "0123"); /* after zero should be '.' or nothing */ TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "0x0"); TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "0x123"); -#endif } static void test_parse_number_too_big() { -#if 0 TEST_ERROR(LEPT_PARSE_NUMBER_TOO_BIG, "1e309"); TEST_ERROR(LEPT_PARSE_NUMBER_TOO_BIG, "-1e309"); -#endif } static void test_parse() { From 788ab1d2860b1774eb3d72ad2ca64a88706b4ee3 Mon Sep 17 00:00:00 2001 From: xmfbit Date: Mon, 2 Jan 2017 23:20:34 +0800 Subject: [PATCH 3/9] improve according to solution --- tutorial02/leptjson.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tutorial02/leptjson.c b/tutorial02/leptjson.c index 9fcfa47f..17791d85 100644 --- a/tutorial02/leptjson.c +++ b/tutorial02/leptjson.c @@ -1,7 +1,6 @@ #include "leptjson.h" #include /* assert() */ #include /* NULL, strtod() */ -#include #include #define EXPECT(c, ch) do { assert(*c->json == (ch)); c->json++; } while(0) #define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9') @@ -20,12 +19,17 @@ static void lept_parse_whitespace(lept_context* c) { static int lept_parse_literal(lept_context* c, lept_value* v, const char* json, int type) { - int i, len = strlen(json); - for(i = 0; i < len; ++i) { + size_t i = 0; + while(json[i]) { if(c->json[i] != json[i]) return LEPT_PARSE_INVALID_VALUE; + ++i; } + /* + for(i = 0; i < len; ++i) { + if(c->json[i] != json[i]) return LEPT_PARSE_INVALID_VALUE; + }*/ v->type = type; - c->json += len; + c->json += i; return LEPT_PARSE_OK; } From f76290009235886a3fc5644925a485a5ae8fb509 Mon Sep 17 00:00:00 2001 From: xmfbit Date: Tue, 3 Jan 2017 21:07:50 +0800 Subject: [PATCH 4/9] complete tutor3 --- tutorial03/leptjson.c | 53 +++++++++++++++++++++++++++++++++++++------ tutorial03/test.c | 22 +++++++++++++----- 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/tutorial03/leptjson.c b/tutorial03/leptjson.c index 07f7e2c7..a87d3a4b 100644 --- a/tutorial03/leptjson.c +++ b/tutorial03/leptjson.c @@ -4,7 +4,8 @@ #include /* HUGE_VAL */ #include /* NULL, malloc(), realloc(), free(), strtod() */ #include /* memcpy() */ - +#include +#include #ifndef LEPT_PARSE_STACK_INIT_SIZE #define LEPT_PARSE_STACK_INIT_SIZE 256 #endif @@ -86,24 +87,54 @@ static int lept_parse_number(lept_context* c, lept_value* v) { return LEPT_PARSE_OK; } +/* 处理转义字符 */ +static char lept_sub_process(char ch) { + switch (ch) { + case '\\': return '\\'; + case 'n': return '\n'; + case '\"': return '\"'; + case '/': return '/'; + case 'b': return '\b'; + case 'f': return '\f'; + case 'r': return '\r'; + case 't': return '\t'; + case 'u': /* 暂不处理 */ + default: return 0; /* 其他字符 */ + } + return 0; +} + static int lept_parse_string(lept_context* c, lept_value* v) { size_t head = c->top, len; const char* p; - EXPECT(c, '\"'); + EXPECT(c, '\"');/* should begin with " */ p = c->json; for (;;) { char ch = *p++; switch (ch) { - case '\"': + case '\"': /* should end with " */ len = c->top - head; - lept_set_string(v, (const char*)lept_context_pop(c, len), len); + lept_set_string(v, (const char*)lept_context_pop(c, len), len); /* we fill the string with the content of the stack */ c->json = p; return LEPT_PARSE_OK; - case '\0': + case '\\': /* 转义字符 */ + ch = lept_sub_process(*p++); + if(ch == 0) { /* 不合法的转义字符 */ + c->top = head; + return LEPT_PARSE_INVALID_STRING_ESCAPE; + } + PUTC(c, ch); + continue; + case '\0': /* we cannot find the endding " */ c->top = head; return LEPT_PARSE_MISS_QUOTATION_MARK; default: - PUTC(c, ch); + if((unsigned char) ch >= 0x20) + PUTC(c, ch); /* we use a stack as buffer to store the chars */ + else { /* invalid char */ + c->top = head; + return LEPT_PARSE_INVALID_STRING_CHAR; + } } } } @@ -154,11 +185,15 @@ lept_type lept_get_type(const lept_value* v) { int lept_get_boolean(const lept_value* v) { /* \TODO */ - return 0; + assert(v != NULL && (v->type == LEPT_FALSE || v->type == LEPT_TRUE)); + return v->type == LEPT_FALSE? 0: 1; } void lept_set_boolean(lept_value* v, int b) { /* \TODO */ + assert(v != NULL); + lept_free(v); + v->type = b == 0? LEPT_FALSE: LEPT_TRUE; } double lept_get_number(const lept_value* v) { @@ -168,6 +203,10 @@ double lept_get_number(const lept_value* v) { void lept_set_number(lept_value* v, double n) { /* \TODO */ + assert(v != NULL); + lept_free(v); + v->type = LEPT_NUMBER; + v->u.n = n; } const char* lept_get_string(const lept_value* v) { diff --git a/tutorial03/test.c b/tutorial03/test.c index ac788aca..62e07771 100644 --- a/tutorial03/test.c +++ b/tutorial03/test.c @@ -7,6 +7,9 @@ static int main_ret = 0; static int test_count = 0; static int test_pass = 0; +#define FALSE 0 +#define TRUE 1 + #define EXPECT_EQ_BASE(equality, expect, actual, format) \ do {\ test_count++;\ @@ -107,10 +110,8 @@ static void test_parse_number() { static void test_parse_string() { TEST_STRING("", "\"\""); TEST_STRING("Hello", "\"Hello\""); -#if 0 TEST_STRING("Hello\nWorld", "\"Hello\\nWorld\""); TEST_STRING("\" \\ / \b \f \n \r \t", "\"\\\" \\\\ \\/ \\b \\f \\n \\r \\t\""); -#endif } #define TEST_ERROR(error, json)\ @@ -163,19 +164,15 @@ static void test_parse_missing_quotation_mark() { } static void test_parse_invalid_string_escape() { -#if 0 TEST_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\v\""); TEST_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\'\""); TEST_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\0\""); TEST_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\x12\""); -#endif } static void test_parse_invalid_string_char() { -#if 0 TEST_ERROR(LEPT_PARSE_INVALID_STRING_CHAR, "\"\x01\""); TEST_ERROR(LEPT_PARSE_INVALID_STRING_CHAR, "\"\x1F\""); -#endif } static void test_access_null() { @@ -190,10 +187,23 @@ static void test_access_null() { static void test_access_boolean() { /* \TODO */ /* Use EXPECT_TRUE() and EXPECT_FALSE() */ + lept_value v; + lept_init(&v); + lept_set_string(&v, "abcd", 4); + lept_set_boolean(&v, TRUE); + EXPECT_TRUE(lept_get_boolean(&v)); + lept_set_boolean(&v, FALSE); + EXPECT_FALSE(lept_get_boolean(&v)); + lept_free(&v); /* dont forget to free lept_value struct */ } static void test_access_number() { /* \TODO */ + lept_value v; + lept_init(&v); + lept_set_number(&v, 1.0); + EXPECT_EQ_DOUBLE(1.0, lept_get_number(&v)); + lept_free(&v); } static void test_access_string() { From cc9e095a71d2595929a0632f9811b3ef06e0fd19 Mon Sep 17 00:00:00 2001 From: xmfbit Date: Tue, 3 Jan 2017 22:34:28 +0800 Subject: [PATCH 5/9] complete tutor4 --- tutorial04/leptjson.c | 56 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/tutorial04/leptjson.c b/tutorial04/leptjson.c index 0a123bf2..5bef7190 100644 --- a/tutorial04/leptjson.c +++ b/tutorial04/leptjson.c @@ -8,7 +8,7 @@ #include /* HUGE_VAL */ #include /* NULL, malloc(), realloc(), free(), strtod() */ #include /* memcpy() */ - +#include #ifndef LEPT_PARSE_STACK_INIT_SIZE #define LEPT_PARSE_STACK_INIT_SIZE 256 #endif @@ -17,6 +17,7 @@ #define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9') #define ISDIGIT1TO9(ch) ((ch) >= '1' && (ch) <= '9') #define PUTC(c, ch) do { *(char*)lept_context_push(c, sizeof(char)) = (ch); } while(0) +#define ISVALIDHEX(ch) (isdigit((ch)) || ((ch) >= 'a' && (ch) <= 'f') || ((ch) >= 'A' && (ch) <= 'F')) typedef struct { const char* json; @@ -90,20 +91,61 @@ static int lept_parse_number(lept_context* c, lept_value* v) { return LEPT_PARSE_OK; } +static unsigned char char2bin(char ch) { + if(isdigit(ch)) return ch - '0'; + if(ch >= 'a' && ch <= 'f') return ch - 'a' + 10; + if(ch >= 'A' && ch <= 'F') return ch - 'A' + 10; + return 0; +} + static const char* lept_parse_hex4(const char* p, unsigned* u) { /* \TODO */ + const char* end = p + 4; + unsigned tmp = 0; + while(*p != '\0' && p != end) { + tmp <<= 4; + if(!ISVALIDHEX(*p)) { + return NULL; + } + tmp |= char2bin(*p++); + } + if(p == '\0' && p != end) { + return NULL; + } + *u = tmp; return p; } static void lept_encode_utf8(lept_context* c, unsigned u) { /* \TODO */ + unsigned char* p = NULL; + assert(u <= 0x10FFFF); + if(u <= 0x007F) { + *(unsigned char*)lept_context_push(c, sizeof(unsigned char)) = (unsigned char)u; + } else if(u <= 0x07FF) { + p = (unsigned char*)lept_context_push(c, 2); + p[0] = ((u >> 6) & 0x1F) | 0xC0; + p[1] = ( u & 0x3F) | 0x80; + } else if(u <= 0xFFFF) { + p = (unsigned char*)lept_context_push(c, 3); + p[0] = (0xE0 | ((u >> 12) & 0xFF)); + p[1] = (0x80 | ((u >> 6) & 0x3F)); + p[2] = (0x80 | ( u & 0x3F));; + } else { + p = (unsigned char*)lept_context_push(c, 4); + p[0] = ((u >> 18) & 0x7) | 0xF0; + p[1] = ((u >> 12) & 0x3F) | 0x80; + p[2] = ((u >> 6 ) & 0x3F) | 0x80; + p[3] = ( u & 0x3F) | 0x80; + } + return; } #define STRING_ERROR(ret) do { c->top = head; return ret; } while(0) static int lept_parse_string(lept_context* c, lept_value* v) { size_t head = c->top, len; - unsigned u; + unsigned u, ulow; const char* p; EXPECT(c, '\"'); p = c->json; @@ -129,6 +171,16 @@ static int lept_parse_string(lept_context* c, lept_value* v) { if (!(p = lept_parse_hex4(p, &u))) STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX); /* \TODO surrogate handling */ + if(u <= 0xDBFF && u >= 0xD800) { + if(p[0] != '\\' || p[1] != 'u') + STRING_ERROR( LEPT_PARSE_INVALID_UNICODE_SURROGATE); + p += 2; + if(!(p = lept_parse_hex4(p, &ulow))) + STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX); + if(ulow > 0xDFFF || ulow < 0xDC00) + STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE); + u = 0x10000 + (u - 0xD800) * 0x400 + (ulow - 0xDC00); + } lept_encode_utf8(c, u); break; default: From 5f300a50d0eb57ce36754f53d341a9e8a86b6f4c Mon Sep 17 00:00:00 2001 From: xmfbit Date: Wed, 4 Jan 2017 16:16:46 +0800 Subject: [PATCH 6/9] complete tutor5 --- tutorial05/leptjson.c | 39 +++++++++++++++++++++++++++++++-------- tutorial05/test.c | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/tutorial05/leptjson.c b/tutorial05/leptjson.c index d2c83f34..bfdf2ce8 100644 --- a/tutorial05/leptjson.c +++ b/tutorial05/leptjson.c @@ -8,7 +8,6 @@ #include /* HUGE_VAL */ #include /* NULL, malloc(), realloc(), free(), strtod() */ #include /* memcpy() */ - #ifndef LEPT_PARSE_STACK_INIT_SIZE #define LEPT_PARSE_STACK_INIT_SIZE 256 #endif @@ -184,9 +183,11 @@ static int lept_parse_string(lept_context* c, lept_value* v) { static int lept_parse_value(lept_context* c, lept_value* v); static int lept_parse_array(lept_context* c, lept_value* v) { - size_t size = 0; + size_t size = 0, i; + lept_value* ptr; int ret; EXPECT(c, '['); + lept_parse_whitespace(c); if (*c->json == ']') { c->json++; v->type = LEPT_ARRAY; @@ -197,12 +198,16 @@ static int lept_parse_array(lept_context* c, lept_value* v) { for (;;) { lept_value e; lept_init(&e); - if ((ret = lept_parse_value(c, &e)) != LEPT_PARSE_OK) - return ret; + if ((ret = lept_parse_value(c, &e)) != LEPT_PARSE_OK) { + break; + } memcpy(lept_context_push(c, sizeof(lept_value)), &e, sizeof(lept_value)); size++; - if (*c->json == ',') + lept_parse_whitespace(c); + if (*c->json == ',') { c->json++; + lept_parse_whitespace(c); + } else if (*c->json == ']') { c->json++; v->type = LEPT_ARRAY; @@ -211,9 +216,16 @@ static int lept_parse_array(lept_context* c, lept_value* v) { memcpy(v->u.a.e = (lept_value*)malloc(size), lept_context_pop(c, size), size); return LEPT_PARSE_OK; } - else - return LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET; + else { + ret = LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET; + break; + } + } + ptr = (lept_value*)c->stack; + for(i = 0; i < size; ++i) { + lept_free(ptr++); } + return ret; } static int lept_parse_value(lept_context* c, lept_value* v) { @@ -244,15 +256,26 @@ int lept_parse(lept_value* v, const char* json) { ret = LEPT_PARSE_ROOT_NOT_SINGULAR; } } - assert(c.top == 0); free(c.stack); return ret; } +size_t lept_get_array_size(const lept_value* v); + +lept_value* lept_get_array_element(const lept_value* v, size_t index); + void lept_free(lept_value* v) { + size_t arr_size, i; assert(v != NULL); if (v->type == LEPT_STRING) free(v->u.s.s); + else if(v->type == LEPT_ARRAY) { + arr_size = lept_get_array_size(v); + for(i = 0; i < arr_size; ++i) { + lept_free(lept_get_array_element(v, i)); + } + free(v->u.a.e); + } v->type = LEPT_NULL; } diff --git a/tutorial05/test.c b/tutorial05/test.c index 2d4dd21e..bf69dfb5 100644 --- a/tutorial05/test.c +++ b/tutorial05/test.c @@ -129,12 +129,41 @@ static void test_parse_string() { static void test_parse_array() { lept_value v; - + lept_value* ptr = NULL; + size_t i; lept_init(&v); EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "[ ]")); EXPECT_EQ_INT(LEPT_ARRAY, lept_get_type(&v)); EXPECT_EQ_SIZE_T(0, lept_get_array_size(&v)); lept_free(&v); + + lept_init(&v); + EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "[ null , false , true , 123 , \"abc\" ]")); + EXPECT_EQ_SIZE_T(5, lept_get_array_size(&v)); + EXPECT_EQ_INT(LEPT_NULL, lept_get_type(lept_get_array_element(&v, 0))); + EXPECT_FALSE(lept_get_boolean(lept_get_array_element(&v, 1))); + EXPECT_TRUE(lept_get_boolean(lept_get_array_element(&v, 2))); + EXPECT_EQ_DOUBLE(123.0, lept_get_number(lept_get_array_element(&v, 3))); + EXPECT_EQ_STRING("abc", lept_get_string(lept_get_array_element(&v, 4)), 3); + lept_free(&v); + + lept_init(&v); + EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "[ [ ] , [ 0 ] , [ 0 , 1 ] , [ 0 , 1 , 2 ] ]")); + EXPECT_EQ_SIZE_T(4, lept_get_array_size(&v)); + EXPECT_EQ_SIZE_T(0, lept_get_array_size(lept_get_array_element(&v, 0))); + ptr = lept_get_array_element(&v, 1); + EXPECT_EQ_SIZE_T(1, lept_get_array_size(ptr)); + EXPECT_EQ_DOUBLE(0.0, lept_get_number(lept_get_array_element(ptr, 0))); + ptr = lept_get_array_element(&v, 2); + EXPECT_EQ_SIZE_T(2, lept_get_array_size(ptr)); + for(i = 0; i <= 1; ++i) { + EXPECT_EQ_DOUBLE((double)i, lept_get_number(lept_get_array_element(ptr, i))); + } + ptr = lept_get_array_element(&v, 3); + for(i = 0; i <= 2; ++i) { + EXPECT_EQ_DOUBLE((double)i, lept_get_number(lept_get_array_element(ptr, i))); + } + lept_free(&v); } #define TEST_ERROR(error, json)\ @@ -167,10 +196,9 @@ static void test_parse_invalid_value() { TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "nan"); /* invalid value in array */ -#if 0 TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "[1,]"); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "[\"a\", nul]"); -#endif + TEST_ERROR(LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET, "[\"ab\""); } static void test_parse_root_not_singular() { From 26240932ca73d2bbefba3f7bc13831a8cad6dfb2 Mon Sep 17 00:00:00 2001 From: xmfbit Date: Fri, 6 Jan 2017 15:04:48 +0800 Subject: [PATCH 7/9] complete tutor6 --- tutorial06/leptjson.c | 749 ++++++++++++++++++++++++------------------ tutorial06/test.c | 8 +- 2 files changed, 437 insertions(+), 320 deletions(-) diff --git a/tutorial06/leptjson.c b/tutorial06/leptjson.c index 64e3bd0d..a0e464bf 100644 --- a/tutorial06/leptjson.c +++ b/tutorial06/leptjson.c @@ -3,387 +3,508 @@ #include #endif #include "leptjson.h" -#include /* assert() */ -#include /* errno, ERANGE */ -#include /* HUGE_VAL */ -#include /* NULL, malloc(), realloc(), free(), strtod() */ -#include /* memcpy() */ +#include /* assert() */ +#include /* errno, ERANGE */ +#include /* HUGE_VAL */ +#include /* NULL, malloc(), realloc(), free(), strtod() */ +#include /* memcpy() */ #ifndef LEPT_PARSE_STACK_INIT_SIZE #define LEPT_PARSE_STACK_INIT_SIZE 256 #endif -#define EXPECT(c, ch) do { assert(*c->json == (ch)); c->json++; } while(0) -#define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9') -#define ISDIGIT1TO9(ch) ((ch) >= '1' && (ch) <= '9') -#define PUTC(c, ch) do { *(char*)lept_context_push(c, sizeof(char)) = (ch); } while(0) +#define EXPECT(c, ch) \ + do { \ + assert(*c->json == (ch)); \ + c->json++; \ + } while (0) +#define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9') +#define ISDIGIT1TO9(ch) ((ch) >= '1' && (ch) <= '9') +#define PUTC(c, ch) \ + do { \ + *(char *)lept_context_push(c, sizeof(char)) = (ch); \ + } while (0) typedef struct { - const char* json; - char* stack; - size_t size, top; -}lept_context; - -static void* lept_context_push(lept_context* c, size_t size) { - void* ret; - assert(size > 0); - if (c->top + size >= c->size) { - if (c->size == 0) - c->size = LEPT_PARSE_STACK_INIT_SIZE; - while (c->top + size >= c->size) - c->size += c->size >> 1; /* c->size * 1.5 */ - c->stack = (char*)realloc(c->stack, c->size); - } - ret = c->stack + c->top; - c->top += size; - return ret; + const char *json; + char *stack; + size_t size, top; +} lept_context; + +static void *lept_context_push(lept_context *c, size_t size) { + void *ret; + assert(size > 0); + if (c->top + size >= c->size) { + if (c->size == 0) + c->size = LEPT_PARSE_STACK_INIT_SIZE; + while (c->top + size >= c->size) + c->size += c->size >> 1; /* c->size * 1.5 */ + c->stack = (char *)realloc(c->stack, c->size); + } + ret = c->stack + c->top; + c->top += size; + return ret; } -static void* lept_context_pop(lept_context* c, size_t size) { - assert(c->top >= size); - return c->stack + (c->top -= size); +static void *lept_context_pop(lept_context *c, size_t size) { + assert(c->top >= size); + return c->stack + (c->top -= size); } -static void lept_parse_whitespace(lept_context* c) { - const char *p = c->json; - while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') - p++; - c->json = p; +static void lept_parse_whitespace(lept_context *c) { + const char *p = c->json; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') + p++; + c->json = p; } -static int lept_parse_literal(lept_context* c, lept_value* v, const char* literal, lept_type type) { - size_t i; - EXPECT(c, literal[0]); - for (i = 0; literal[i + 1]; i++) - if (c->json[i] != literal[i + 1]) - return LEPT_PARSE_INVALID_VALUE; - c->json += i; - v->type = type; - return LEPT_PARSE_OK; +static int lept_parse_literal(lept_context *c, lept_value *v, + const char *literal, lept_type type) { + size_t i; + EXPECT(c, literal[0]); + for (i = 0; literal[i + 1]; i++) + if (c->json[i] != literal[i + 1]) + return LEPT_PARSE_INVALID_VALUE; + c->json += i; + v->type = type; + return LEPT_PARSE_OK; } -static int lept_parse_number(lept_context* c, lept_value* v) { - const char* p = c->json; - if (*p == '-') p++; - if (*p == '0') p++; - else { - if (!ISDIGIT1TO9(*p)) return LEPT_PARSE_INVALID_VALUE; - for (p++; ISDIGIT(*p); p++); - } - if (*p == '.') { - p++; - if (!ISDIGIT(*p)) return LEPT_PARSE_INVALID_VALUE; - for (p++; ISDIGIT(*p); p++); - } - if (*p == 'e' || *p == 'E') { - p++; - if (*p == '+' || *p == '-') p++; - if (!ISDIGIT(*p)) return LEPT_PARSE_INVALID_VALUE; - for (p++; ISDIGIT(*p); p++); - } - errno = 0; - v->u.n = strtod(c->json, NULL); - if (errno == ERANGE && (v->u.n == HUGE_VAL || v->u.n == -HUGE_VAL)) - return LEPT_PARSE_NUMBER_TOO_BIG; - v->type = LEPT_NUMBER; - c->json = p; - return LEPT_PARSE_OK; +static int lept_parse_number(lept_context *c, lept_value *v) { + const char *p = c->json; + if (*p == '-') + p++; + if (*p == '0') + p++; + else { + if (!ISDIGIT1TO9(*p)) + return LEPT_PARSE_INVALID_VALUE; + for (p++; ISDIGIT(*p); p++) + ; + } + if (*p == '.') { + p++; + if (!ISDIGIT(*p)) + return LEPT_PARSE_INVALID_VALUE; + for (p++; ISDIGIT(*p); p++) + ; + } + if (*p == 'e' || *p == 'E') { + p++; + if (*p == '+' || *p == '-') + p++; + if (!ISDIGIT(*p)) + return LEPT_PARSE_INVALID_VALUE; + for (p++; ISDIGIT(*p); p++) + ; + } + errno = 0; + v->u.n = strtod(c->json, NULL); + if (errno == ERANGE && (v->u.n == HUGE_VAL || v->u.n == -HUGE_VAL)) + return LEPT_PARSE_NUMBER_TOO_BIG; + v->type = LEPT_NUMBER; + c->json = p; + return LEPT_PARSE_OK; } -static const char* lept_parse_hex4(const char* p, unsigned* u) { - int i; - *u = 0; - for (i = 0; i < 4; i++) { - char ch = *p++; - *u <<= 4; - if (ch >= '0' && ch <= '9') *u |= ch - '0'; - else if (ch >= 'A' && ch <= 'F') *u |= ch - ('A' - 10); - else if (ch >= 'a' && ch <= 'f') *u |= ch - ('a' - 10); - else return NULL; - } - return p; +static const char *lept_parse_hex4(const char *p, unsigned *u) { + int i; + *u = 0; + for (i = 0; i < 4; i++) { + char ch = *p++; + *u <<= 4; + if (ch >= '0' && ch <= '9') + *u |= ch - '0'; + else if (ch >= 'A' && ch <= 'F') + *u |= ch - ('A' - 10); + else if (ch >= 'a' && ch <= 'f') + *u |= ch - ('a' - 10); + else + return NULL; + } + return p; } -static void lept_encode_utf8(lept_context* c, unsigned u) { - if (u <= 0x7F) - PUTC(c, u & 0xFF); - else if (u <= 0x7FF) { - PUTC(c, 0xC0 | ((u >> 6) & 0xFF)); - PUTC(c, 0x80 | ( u & 0x3F)); - } - else if (u <= 0xFFFF) { - PUTC(c, 0xE0 | ((u >> 12) & 0xFF)); - PUTC(c, 0x80 | ((u >> 6) & 0x3F)); - PUTC(c, 0x80 | ( u & 0x3F)); - } - else { - assert(u <= 0x10FFFF); - PUTC(c, 0xF0 | ((u >> 18) & 0xFF)); - PUTC(c, 0x80 | ((u >> 12) & 0x3F)); - PUTC(c, 0x80 | ((u >> 6) & 0x3F)); - PUTC(c, 0x80 | ( u & 0x3F)); - } +static void lept_encode_utf8(lept_context *c, unsigned u) { + if (u <= 0x7F) + PUTC(c, u & 0xFF); + else if (u <= 0x7FF) { + PUTC(c, 0xC0 | ((u >> 6) & 0xFF)); + PUTC(c, 0x80 | (u & 0x3F)); + } else if (u <= 0xFFFF) { + PUTC(c, 0xE0 | ((u >> 12) & 0xFF)); + PUTC(c, 0x80 | ((u >> 6) & 0x3F)); + PUTC(c, 0x80 | (u & 0x3F)); + } else { + assert(u <= 0x10FFFF); + PUTC(c, 0xF0 | ((u >> 18) & 0xFF)); + PUTC(c, 0x80 | ((u >> 12) & 0x3F)); + PUTC(c, 0x80 | ((u >> 6) & 0x3F)); + PUTC(c, 0x80 | (u & 0x3F)); + } } -#define STRING_ERROR(ret) do { c->top = head; return ret; } while(0) - -static int lept_parse_string(lept_context* c, lept_value* v) { - size_t head = c->top, len; - unsigned u, u2; - const char* p; - EXPECT(c, '\"'); - p = c->json; - for (;;) { - char ch = *p++; - switch (ch) { - case '\"': - len = c->top - head; - lept_set_string(v, (const char*)lept_context_pop(c, len), len); - c->json = p; - return LEPT_PARSE_OK; - case '\\': - switch (*p++) { - case '\"': PUTC(c, '\"'); break; - case '\\': PUTC(c, '\\'); break; - case '/': PUTC(c, '/' ); break; - case 'b': PUTC(c, '\b'); break; - case 'f': PUTC(c, '\f'); break; - case 'n': PUTC(c, '\n'); break; - case 'r': PUTC(c, '\r'); break; - case 't': PUTC(c, '\t'); break; - case 'u': - if (!(p = lept_parse_hex4(p, &u))) - STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX); - if (u >= 0xD800 && u <= 0xDBFF) { /* surrogate pair */ - if (*p++ != '\\') - STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE); - if (*p++ != 'u') - STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE); - if (!(p = lept_parse_hex4(p, &u2))) - STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX); - if (u2 < 0xDC00 || u2 > 0xDFFF) - STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE); - u = (((u - 0xD800) << 10) | (u2 - 0xDC00)) + 0x10000; - } - lept_encode_utf8(c, u); - break; - default: - STRING_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE); - } - break; - case '\0': - STRING_ERROR(LEPT_PARSE_MISS_QUOTATION_MARK); - default: - if ((unsigned char)ch < 0x20) - STRING_ERROR(LEPT_PARSE_INVALID_STRING_CHAR); - PUTC(c, ch); +#define STRING_ERROR(ret) \ + do { \ + c->top = head; \ + return ret; \ + } while (0) + +/* 解析 JSON 字符串,把结果写入 str 和 len */ +/* str 指向 c->stack 中的元素,需要在 c->stack */ +static int lept_parse_string_raw(lept_context *c, char **str, size_t *len) { + size_t head = c->top; + unsigned u, u2; + const char *p; + EXPECT(c, '\"'); + p = c->json; + for (;;) { + char ch = *p++; + switch (ch) { + case '\"': + *len = c->top - head; + *str = malloc(sizeof(char) * *len); + memcpy(*str, (const char *)lept_context_pop(c, *len), *len); + c->json = p; + return LEPT_PARSE_OK; + case '\\': + switch (*p++) { + case '\"': + PUTC(c, '\"'); + break; + case '\\': + PUTC(c, '\\'); + break; + case '/': + PUTC(c, '/'); + break; + case 'b': + PUTC(c, '\b'); + break; + case 'f': + PUTC(c, '\f'); + break; + case 'n': + PUTC(c, '\n'); + break; + case 'r': + PUTC(c, '\r'); + break; + case 't': + PUTC(c, '\t'); + break; + case 'u': + if (!(p = lept_parse_hex4(p, &u))) + STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX); + if (u >= 0xD800 && u <= 0xDBFF) { /* surrogate pair */ + if (*p++ != '\\') + STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE); + if (*p++ != 'u') + STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE); + if (!(p = lept_parse_hex4(p, &u2))) + STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_HEX); + if (u2 < 0xDC00 || u2 > 0xDFFF) + STRING_ERROR(LEPT_PARSE_INVALID_UNICODE_SURROGATE); + u = (((u - 0xD800) << 10) | (u2 - 0xDC00)) + 0x10000; } + lept_encode_utf8(c, u); + break; + default: + STRING_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE); + } + break; + case '\0': + STRING_ERROR(LEPT_PARSE_MISS_QUOTATION_MARK); + default: + if ((unsigned char)ch < 0x20) + STRING_ERROR(LEPT_PARSE_INVALID_STRING_CHAR); + PUTC(c, ch); } + } } -static int lept_parse_value(lept_context* c, lept_value* v); +static int lept_parse_string(lept_context *c, lept_value *v) { + int ret; + char *s; + size_t len; + if ((ret = lept_parse_string_raw(c, &s, &len)) == LEPT_PARSE_OK) { + lept_set_string(v, s, len); + free(s); + } + return ret; +} -static int lept_parse_array(lept_context* c, lept_value* v) { - size_t i, size = 0; - int ret; - EXPECT(c, '['); +static int lept_parse_value(lept_context *c, lept_value *v); + +static int lept_parse_array(lept_context *c, lept_value *v) { + size_t i, size = 0; + int ret; + EXPECT(c, '['); + lept_parse_whitespace(c); + if (*c->json == ']') { + c->json++; + v->type = LEPT_ARRAY; + v->u.a.size = 0; + v->u.a.e = NULL; + return LEPT_PARSE_OK; + } + for (;;) { + lept_value e; + lept_init(&e); + if ((ret = lept_parse_value(c, &e)) != LEPT_PARSE_OK) + break; + memcpy(lept_context_push(c, sizeof(lept_value)), &e, sizeof(lept_value)); + size++; lept_parse_whitespace(c); - if (*c->json == ']') { - c->json++; - v->type = LEPT_ARRAY; - v->u.a.size = 0; - v->u.a.e = NULL; - return LEPT_PARSE_OK; + if (*c->json == ',') { + c->json++; + lept_parse_whitespace(c); + } else if (*c->json == ']') { + c->json++; + v->type = LEPT_ARRAY; + v->u.a.size = size; + size *= sizeof(lept_value); + memcpy(v->u.a.e = (lept_value *)malloc(size), lept_context_pop(c, size), + size); + return LEPT_PARSE_OK; + } else { + ret = LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET; + break; } - for (;;) { - lept_value e; - lept_init(&e); - if ((ret = lept_parse_value(c, &e)) != LEPT_PARSE_OK) - break; - memcpy(lept_context_push(c, sizeof(lept_value)), &e, sizeof(lept_value)); - size++; - lept_parse_whitespace(c); - if (*c->json == ',') { - c->json++; - lept_parse_whitespace(c); - } - else if (*c->json == ']') { - c->json++; - v->type = LEPT_ARRAY; - v->u.a.size = size; - size *= sizeof(lept_value); - memcpy(v->u.a.e = (lept_value*)malloc(size), lept_context_pop(c, size), size); - return LEPT_PARSE_OK; - } - else { - ret = LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET; - break; - } - } - /* Pop and free values on the stack */ - for (i = 0; i < size; i++) - lept_free((lept_value*)lept_context_pop(c, sizeof(lept_value))); - return ret; + } + /* Pop and free values on the stack */ + for (i = 0; i < size; i++) + lept_free((lept_value *)lept_context_pop(c, sizeof(lept_value))); + return ret; } - -static int lept_parse_object(lept_context* c, lept_value* v) { - size_t size; - lept_member m; - int ret; - EXPECT(c, '{'); +/* +static void lept_free_lept_member(lept_member* ptr) { + lept_free(ptr->v); +}*/ +static int lept_parse_object(lept_context *c, lept_value *v) { + size_t size, i, len; + lept_member m, *ptr; + int ret; + char *str_buff; + EXPECT(c, '{'); + lept_parse_whitespace(c); + if (*c->json == '}') { /*遇到}说明到达该object末尾,解析完成*/ + c->json++; + v->type = LEPT_OBJECT; + v->u.o.m = 0; + v->u.o.size = 0; + return LEPT_PARSE_OK; + } + m.k = NULL; + size = 0; + for (;;) { + lept_init(&m.v); /* init member: value*/ + /* \todo parse key to m.k, m.klen */ + if (*c->json != '\"') { + /* 说明没有字符串 key */ + ret = LEPT_PARSE_MISS_KEY; + break; + } + ret = lept_parse_string_raw(c, &str_buff, &len); + if (ret != LEPT_PARSE_OK) { + /*there is something wrong when parsing key*/ + /*free allocated memory*/ + free(str_buff); + break; + } + m.k = (char *)malloc(sizeof(char) * (len + 1)); + memcpy(m.k, str_buff, sizeof(char) * len); + m.k[len] = '\0'; + m.klen = len; + free(str_buff); + str_buff = NULL; + /* \todo parse ws colon ws */ + lept_parse_whitespace(c); + if (*c->json != ':') { + /*free allocated memory of m.k*/ + free(m.k); + ret = LEPT_PARSE_MISS_COLON; + break; + } + ++c->json; lept_parse_whitespace(c); - if (*c->json == '}') { - c->json++; - v->type = LEPT_OBJECT; - v->u.o.m = 0; - v->u.o.size = 0; - return LEPT_PARSE_OK; + /* parse value */ + if ((ret = lept_parse_value(c, &m.v)) != LEPT_PARSE_OK) + break; + memcpy(lept_context_push(c, sizeof(lept_member)), &m, sizeof(lept_member)); + size++; + m.k = NULL; /* ownership is transferred to member on stack */ + /* \todo parse ws [comma | right-curly-brace] ws */ + lept_parse_whitespace(c); + if (*c->json != ',' && *c->json != '}') { + ret = LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET; + break; } - m.k = NULL; - size = 0; - for (;;) { - lept_init(&m.v); - /* \todo parse key to m.k, m.klen */ - /* \todo parse ws colon ws */ - /* parse value */ - if ((ret = lept_parse_value(c, &m.v)) != LEPT_PARSE_OK) - break; - memcpy(lept_context_push(c, sizeof(lept_member)), &m, sizeof(lept_member)); - size++; - m.k = NULL; /* ownership is transferred to member on stack */ - /* \todo parse ws [comma | right-curly-brace] ws */ + if (*c->json == ',') { + ++c->json; + lept_parse_whitespace(c); + } else { + ++c->json; + v->type = LEPT_OBJECT; + v->u.o.size = size; + size *= sizeof(lept_member); + memcpy(v->u.o.m = (lept_member *)malloc(size), lept_context_pop(c, size), + size); + return LEPT_PARSE_OK; } - /* \todo Pop and free members on the stack */ - return ret; + } + /* \todo Pop and free members on the stack */ + for (i = 0; i < size; ++i) { + ptr = (lept_member *)lept_context_pop(c, sizeof(lept_member)); + free(ptr->k); + lept_free(&(ptr->v)); + } + return ret; } -static int lept_parse_value(lept_context* c, lept_value* v) { - switch (*c->json) { - case 't': return lept_parse_literal(c, v, "true", LEPT_TRUE); - case 'f': return lept_parse_literal(c, v, "false", LEPT_FALSE); - case 'n': return lept_parse_literal(c, v, "null", LEPT_NULL); - default: return lept_parse_number(c, v); - case '"': return lept_parse_string(c, v); - case '[': return lept_parse_array(c, v); - case '{': return lept_parse_object(c, v); - case '\0': return LEPT_PARSE_EXPECT_VALUE; - } +static int lept_parse_value(lept_context *c, lept_value *v) { + switch (*c->json) { + case 't': + return lept_parse_literal(c, v, "true", LEPT_TRUE); + case 'f': + return lept_parse_literal(c, v, "false", LEPT_FALSE); + case 'n': + return lept_parse_literal(c, v, "null", LEPT_NULL); + default: + return lept_parse_number(c, v); + case '"': + return lept_parse_string(c, v); + case '[': + return lept_parse_array(c, v); + case '{': + return lept_parse_object(c, v); + case '\0': + return LEPT_PARSE_EXPECT_VALUE; + } } -int lept_parse(lept_value* v, const char* json) { - lept_context c; - int ret; - assert(v != NULL); - c.json = json; - c.stack = NULL; - c.size = c.top = 0; - lept_init(v); +int lept_parse(lept_value *v, const char *json) { + lept_context c; + int ret; + assert(v != NULL); + c.json = json; + c.stack = NULL; + c.size = c.top = 0; + lept_init(v); + lept_parse_whitespace(&c); + if ((ret = lept_parse_value(&c, v)) == LEPT_PARSE_OK) { lept_parse_whitespace(&c); - if ((ret = lept_parse_value(&c, v)) == LEPT_PARSE_OK) { - lept_parse_whitespace(&c); - if (*c.json != '\0') { - v->type = LEPT_NULL; - ret = LEPT_PARSE_ROOT_NOT_SINGULAR; - } + if (*c.json != '\0') { + v->type = LEPT_NULL; + ret = LEPT_PARSE_ROOT_NOT_SINGULAR; } - assert(c.top == 0); - free(c.stack); - return ret; + } + assert(c.top == 0); + free(c.stack); + return ret; } -void lept_free(lept_value* v) { - size_t i; - assert(v != NULL); - switch (v->type) { - case LEPT_STRING: - free(v->u.s.s); - break; - case LEPT_ARRAY: - for (i = 0; i < v->u.a.size; i++) - lept_free(&v->u.a.e[i]); - free(v->u.a.e); - break; - default: break; +void lept_free(lept_value *v) { + size_t i; + assert(v != NULL); + switch (v->type) { + case LEPT_STRING: + free(v->u.s.s); + break; + case LEPT_ARRAY: + for (i = 0; i < v->u.a.size; i++) + lept_free(&v->u.a.e[i]); + free(v->u.a.e); + break; + case LEPT_OBJECT: + for (i = 0; i < v->u.o.size; ++i) { + lept_free(&(v->u.o.m[i].v)); + free(v->u.o.m[i].k); } - v->type = LEPT_NULL; + free(v->u.o.m); + break; + default: + break; + } + v->type = LEPT_NULL; } -lept_type lept_get_type(const lept_value* v) { - assert(v != NULL); - return v->type; +lept_type lept_get_type(const lept_value *v) { + assert(v != NULL); + return v->type; } -int lept_get_boolean(const lept_value* v) { - assert(v != NULL && (v->type == LEPT_TRUE || v->type == LEPT_FALSE)); - return v->type == LEPT_TRUE; +int lept_get_boolean(const lept_value *v) { + assert(v != NULL && (v->type == LEPT_TRUE || v->type == LEPT_FALSE)); + return v->type == LEPT_TRUE; } -void lept_set_boolean(lept_value* v, int b) { - lept_free(v); - v->type = b ? LEPT_TRUE : LEPT_FALSE; +void lept_set_boolean(lept_value *v, int b) { + lept_free(v); + v->type = b ? LEPT_TRUE : LEPT_FALSE; } -double lept_get_number(const lept_value* v) { - assert(v != NULL && v->type == LEPT_NUMBER); - return v->u.n; +double lept_get_number(const lept_value *v) { + assert(v != NULL && v->type == LEPT_NUMBER); + return v->u.n; } -void lept_set_number(lept_value* v, double n) { - lept_free(v); - v->u.n = n; - v->type = LEPT_NUMBER; +void lept_set_number(lept_value *v, double n) { + lept_free(v); + v->u.n = n; + v->type = LEPT_NUMBER; } -const char* lept_get_string(const lept_value* v) { - assert(v != NULL && v->type == LEPT_STRING); - return v->u.s.s; +const char *lept_get_string(const lept_value *v) { + assert(v != NULL && v->type == LEPT_STRING); + return v->u.s.s; } -size_t lept_get_string_length(const lept_value* v) { - assert(v != NULL && v->type == LEPT_STRING); - return v->u.s.len; +size_t lept_get_string_length(const lept_value *v) { + assert(v != NULL && v->type == LEPT_STRING); + return v->u.s.len; } -void lept_set_string(lept_value* v, const char* s, size_t len) { - assert(v != NULL && (s != NULL || len == 0)); - lept_free(v); - v->u.s.s = (char*)malloc(len + 1); - memcpy(v->u.s.s, s, len); - v->u.s.s[len] = '\0'; - v->u.s.len = len; - v->type = LEPT_STRING; +void lept_set_string(lept_value *v, const char *s, size_t len) { + assert(v != NULL && (s != NULL || len == 0)); + lept_free(v); + v->u.s.s = (char *)malloc(len + 1); + memcpy(v->u.s.s, s, len); + v->u.s.s[len] = '\0'; + v->u.s.len = len; + v->type = LEPT_STRING; } -size_t lept_get_array_size(const lept_value* v) { - assert(v != NULL && v->type == LEPT_ARRAY); - return v->u.a.size; +size_t lept_get_array_size(const lept_value *v) { + assert(v != NULL && v->type == LEPT_ARRAY); + return v->u.a.size; } -lept_value* lept_get_array_element(const lept_value* v, size_t index) { - assert(v != NULL && v->type == LEPT_ARRAY); - assert(index < v->u.a.size); - return &v->u.a.e[index]; +lept_value *lept_get_array_element(const lept_value *v, size_t index) { + assert(v != NULL && v->type == LEPT_ARRAY); + assert(index < v->u.a.size); + return &v->u.a.e[index]; } -size_t lept_get_object_size(const lept_value* v) { - assert(v != NULL && v->type == LEPT_OBJECT); - return v->u.o.size; +size_t lept_get_object_size(const lept_value *v) { + assert(v != NULL && v->type == LEPT_OBJECT); + return v->u.o.size; } -const char* lept_get_object_key(const lept_value* v, size_t index) { - assert(v != NULL && v->type == LEPT_OBJECT); - assert(index < v->u.o.size); - return v->u.o.m[index].k; +const char *lept_get_object_key(const lept_value *v, size_t index) { + assert(v != NULL && v->type == LEPT_OBJECT); + assert(index < v->u.o.size); + return v->u.o.m[index].k; } -size_t lept_get_object_key_length(const lept_value* v, size_t index) { - assert(v != NULL && v->type == LEPT_OBJECT); - assert(index < v->u.o.size); - return v->u.o.m[index].klen; +size_t lept_get_object_key_length(const lept_value *v, size_t index) { + assert(v != NULL && v->type == LEPT_OBJECT); + assert(index < v->u.o.size); + return v->u.o.m[index].klen; } -lept_value* lept_get_object_value(const lept_value* v, size_t index) { - assert(v != NULL && v->type == LEPT_OBJECT); - assert(index < v->u.o.size); - return &v->u.o.m[index].v; +lept_value *lept_get_object_value(const lept_value *v, size_t index) { + assert(v != NULL && v->type == LEPT_OBJECT); + assert(index < v->u.o.size); + return &v->u.o.m[index].v; } diff --git a/tutorial06/test.c b/tutorial06/test.c index 8d332e45..064fac62 100644 --- a/tutorial06/test.c +++ b/tutorial06/test.c @@ -352,9 +352,7 @@ static void test_parse() { test_parse_number(); test_parse_string(); test_parse_array(); -#if 0 test_parse_object(); -#endif test_parse_expect_value(); test_parse_invalid_value(); @@ -366,11 +364,9 @@ static void test_parse() { test_parse_invalid_unicode_hex(); test_parse_invalid_unicode_surrogate(); test_parse_miss_comma_or_square_bracket(); -#if 0 - test_parse_miss_key(); + /*test_parse_miss_key(); test_parse_miss_colon(); - test_parse_miss_comma_or_curly_bracket(); -#endif + test_parse_miss_comma_or_curly_bracket();*/ } static void test_access_null() { From bcdeec877ee3a1dad8102b7acdc0e769db7aa891 Mon Sep 17 00:00:00 2001 From: xmfbit Date: Fri, 6 Jan 2017 15:13:52 +0800 Subject: [PATCH 8/9] complete tutor6 --- tutorial06/test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tutorial06/test.c b/tutorial06/test.c index 064fac62..74e5f763 100644 --- a/tutorial06/test.c +++ b/tutorial06/test.c @@ -364,9 +364,9 @@ static void test_parse() { test_parse_invalid_unicode_hex(); test_parse_invalid_unicode_surrogate(); test_parse_miss_comma_or_square_bracket(); - /*test_parse_miss_key(); + test_parse_miss_key(); test_parse_miss_colon(); - test_parse_miss_comma_or_curly_bracket();*/ + test_parse_miss_comma_or_curly_bracket(); } static void test_access_null() { From 6b5174be985a1f8bba11bce78410e853856b0411 Mon Sep 17 00:00:00 2001 From: xmfbit Date: Wed, 18 Jan 2017 16:09:09 +0800 Subject: [PATCH 9/9] compelte tutor7 --- tutorial07/leptjson.c | 72 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/tutorial07/leptjson.c b/tutorial07/leptjson.c index 5307b892..8c6f6744 100644 --- a/tutorial07/leptjson.c +++ b/tutorial07/leptjson.c @@ -346,10 +346,76 @@ int lept_parse(lept_value* v, const char* json) { return ret; } +#define ADD_QUOATATION(c) do { PUTC((c), '\"'); } while(0) + static void lept_stringify_string(lept_context* c, const char* s, size_t len) { - /* ... */ + size_t i; + ADD_QUOATATION(c); + for(i = 0; i < len; ++i) { + switch(s[i]) { + case '\"': + PUTS(c, "\\\"", 2); + break; + case '\\': + PUTS(c, "\\\\", 2); + break; + case '\n': + PUTS(c, "\\n", 2); + break; + case '\b': + PUTS(c, "\\b", 2); + break; + case '\f': + PUTS(c, "\\f", 2); + break; + case '\r': + PUTS(c, "\\r", 2); + break; + case '\t': + PUTS(c, "\\t", 2); + break; + default: + if(s[i] < 0x20) { + PUTS(c, "\\u00", 4); + PUTC(c, s[i] / 16 + '0'); + PUTC(c, s[i] % 16 + '0'); + } else { + PUTC(c, s[i]); + } + break; + } + } + ADD_QUOATATION(c); +} +/* forward declaration */ +static void lept_stringify_value(lept_context* c, const lept_value* v); +static void lept_stringify_array(lept_context* c, const lept_value* v) { + size_t i; + assert(v->type == LEPT_ARRAY && "not array!"); + PUTC(c, '['); + for(i = 0; i < v->u.a.size; ++i) { + lept_stringify_value(c, v->u.a.e + i); + if(i != v->u.a.size - 1) PUTC(c, ','); + } + PUTC(c, ']'); +} + +static void lept_stringify_member(lept_context* c, const lept_member* m) { + lept_stringify_string(c, m->k, m->klen); + PUTC(c, ':'); + lept_stringify_value(c, &(m->v)); } +static void lept_stringify_object(lept_context* c, const lept_value* v) { + size_t i; + assert(v->type == LEPT_OBJECT && "not object!"); + PUTC(c, '{'); + for(i = 0; i < v->u.o.size; ++i) { + lept_stringify_member(c, v->u.o.m + i); + if(i != v->u.o.size - 1) PUTC(c, ','); + } + PUTC(c, '}'); +} static void lept_stringify_value(lept_context* c, const lept_value* v) { switch (v->type) { case LEPT_NULL: PUTS(c, "null", 4); break; @@ -358,10 +424,10 @@ static void lept_stringify_value(lept_context* c, const lept_value* v) { case LEPT_NUMBER: c->top -= 32 - sprintf(lept_context_push(c, 32), "%.17g", v->u.n); break; case LEPT_STRING: lept_stringify_string(c, v->u.s.s, v->u.s.len); break; case LEPT_ARRAY: - /* ... */ + lept_stringify_array(c, v); break; case LEPT_OBJECT: - /* ... */ + lept_stringify_object(c, v); break; default: assert(0 && "invalid type"); }