diff --git a/tutorial01/.vscode/.BROWSE.VC.DB b/tutorial01/.vscode/.BROWSE.VC.DB new file mode 100644 index 00000000..9d03291a Binary files /dev/null and b/tutorial01/.vscode/.BROWSE.VC.DB differ diff --git a/tutorial01/.vscode/c_cpp_properties.json b/tutorial01/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..7e4f5227 --- /dev/null +++ b/tutorial01/.vscode/c_cpp_properties.json @@ -0,0 +1,28 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": ["/usr/include"], + "browse" : { + "limitSymbolsToIncludedHeaders" : true, + "databaseFilename" : "" + } + }, + { + "name": "Linux", + "includePath": ["/usr/include"], + "browse" : { + "limitSymbolsToIncludedHeaders" : true, + "databaseFilename" : "" + } + }, + { + "name": "Win32", + "includePath": ["c:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include"], + "browse" : { + "limitSymbolsToIncludedHeaders" : true, + "databaseFilename" : "" + } + } + ] +} diff --git a/tutorial01/.vscode/launch.json b/tutorial01/.vscode/launch.json new file mode 100644 index 00000000..a413a761 --- /dev/null +++ b/tutorial01/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C++ Launch (Windows)", + "type": "cppvsdbg", + "request": "launch", + "program": "enter program name, for example ${workspaceRoot}/a.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceRoot}", + "environment": [] + }, + { + "name": "C++ Attach (Windows)", + "type": "cppvsdbg", + "request": "attach", + "program": "enter program name, for example ${workspaceRoot}/a.exe", + "processId": "${command.pickProcess}" + } + ] +} \ No newline at end of file diff --git a/tutorial01/leptjson.c b/tutorial01/leptjson.c index 5299fe1d..e152b0c2 100644 --- a/tutorial01/leptjson.c +++ b/tutorial01/leptjson.c @@ -1,47 +1,216 @@ #include "leptjson.h" #include /* assert() */ #include /* NULL */ +//#include /* strlen() */ +#include /*HUGE_VAL*/ +#include /*errno,ERAGNE*/ #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; -}lept_context; + const char* json; +} lept_context; 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; + const char* p = c->json; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == 'r') { + p++; + } + c->json = p; } 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; - return LEPT_PARSE_OK; + 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; + return 0; } +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_literal(lept_context* c, lept_value* v, const char* ch, lept_type tp) { + switch (*ch) { + case 'n': { + 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; + return 0; + break; + } + case 't': { + 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; + } + case 'f': { + 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; + } + default: + break; + } +} +*/ +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->n = strtod(c->json, NULL); + if (errno == ERANGE && (v->n == HUGE_VAL)) + return LEPT_PARSE_NUMBER_TOO_BIG; + v->type = LEPT_NUMBER; + c->json = p; + return LEPT_PARSE_OK; +} + +/* +//Pass all tests +static int lept_parse_number(lept_context* c, lept_value* v) { + char* end; + v->n = strtod(c->json, &end); + int length = strlen(c->json); + if (c->json == end || *(c->json) == '+' || *(c->json) == '.' || *(c->json + length - 1) == '.' || *(c->json) == 'I' || *(c->json) == 'i' || *(c->json) == 'N' || *(c->json) == 'n') { + return LEPT_PARSE_INVALID_VALUE; + } + + c->json = end; + v->type = LEPT_NUMBER; + 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 '\0': return LEPT_PARSE_EXPECT_VALUE; - default: return LEPT_PARSE_INVALID_VALUE; - } + switch (*c->json) { + case 'n': + //return lept_parse_null(c, v); + return lept_parse_literal(c, v, "null", LEPT_NULL); + case '\0': + return LEPT_PARSE_EXPECT_VALUE; + case 't': + return lept_parse_literal(c, v, "true", LEPT_TRUE); + case 'f': + //return lept_parse_false(c, v); + return lept_parse_literal(c, v, "false", LEPT_FALSE); + default: + return lept_parse_number(c, v); + } } +static int lept_parse_root_not_singular(lept_context* c) { + if (c == NULL) + return LEPT_PARSE_OK; + const char* p = c->json; + while (p != NULL && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r' && *p != '\0') { + p++; + } + if (p != NULL && *p == '\0') { + return LEPT_PARSE_OK; + } + else + return LEPT_PARSE_ROOT_NOT_SINGULAR; +} + + int lept_parse(lept_value* v, const char* json) { - lept_context c; - assert(v != NULL); - c.json = json; - v->type = LEPT_NULL; - lept_parse_whitespace(&c); - return lept_parse_value(&c, v); + /* + lept_context c; + assert(v != NULL); + c.json = json; + v->type = LEPT_NULL; + lept_parse_whitespace(&c); + return lept_parse_value(&c, v); + */ + lept_context c; + assert(v != NULL); + c.json = json; + v->type = LEPT_NULL; + lept_parse_whitespace(&c); + int lept_i = lept_parse_value(&c, v); + int lept_ii = lept_parse_root_not_singular(&c); + if (lept_ii == LEPT_PARSE_OK) { + return lept_i; + } + else + return LEPT_PARSE_ROOT_NOT_SINGULAR; } lept_type lept_get_type(const lept_value* v) { - assert(v != NULL); - return v->type; + assert(v != NULL); + return v->type; +} + +double lept_get_number(const lept_value* v) { + assert(v != NULL && v->type == LEPT_NUMBER); + return v->n; } diff --git a/tutorial01/leptjson.h b/tutorial01/leptjson.h index 9b65d22a..0c356a7f 100644 --- a/tutorial01/leptjson.h +++ b/tutorial01/leptjson.h @@ -4,18 +4,23 @@ typedef enum { LEPT_NULL, LEPT_FALSE, LEPT_TRUE, LEPT_NUMBER, LEPT_STRING, LEPT_ARRAY, LEPT_OBJECT } lept_type; typedef struct { + double n; lept_type type; }lept_value; + 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, + LEPT_PARSE_NUMBER_TOO_BIG }; int lept_parse(lept_value* v, const char* json); lept_type lept_get_type(const lept_value* v); +double lept_get_number(const lept_value* v); + #endif /* LEPTJSON_H__ */ diff --git a/tutorial01/test.c b/tutorial01/test.c index e7672181..2804fec6 100644 --- a/tutorial01/test.c +++ b/tutorial01/test.c @@ -1,6 +1,5 @@ #include -#include -#include +#include // NULL #include "leptjson.h" static int main_ret = 0; @@ -10,8 +9,9 @@ static int test_pass = 0; #define EXPECT_EQ_BASE(equality, expect, actual, format) \ do {\ test_count++;\ - if (equality)\ + if (equality){\ test_pass++;\ + }\ else {\ fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", __FILE__, __LINE__, expect, actual);\ main_ret = 1;\ @@ -20,52 +20,130 @@ static int test_pass = 0; #define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d") +#define EXPECT_EQ_DOUBLE(expect,actual) EXPECT_EQ_BASE((expect) == (actual),expect,actual,"%.17g") + +#define TEST_NUMBER(expect,json) \ + do {\ +lept_value v;\ +EXPECT_EQ_INT(LEPT_PARSE_OK,lept_parse(&v,json));\ +EXPECT_EQ_INT(LEPT_NUMBER,lept_get_type(&v));\ +EXPECT_EQ_DOUBLE(expect,lept_get_number(&v));\ +}while(0) + +#define TEST_ERROR(error,json)\ + do{\ + lept_value v;\ + v.type = LEPT_FALSE;\ + EXPECT_EQ_INT(error, lept_parse(&v, json));\ + EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v));\ + }while(0) + + +static void test_parse_number() { + TEST_NUMBER(0.0, "0"); + TEST_NUMBER(0.0, "-0"); + TEST_NUMBER(0.0, "-0.0"); + TEST_NUMBER(1.0, "1"); + TEST_NUMBER(-1.0, "-1"); + TEST_NUMBER(1.5, "1.5"); + TEST_NUMBER(-1.5, "-1.5"); + TEST_NUMBER(3.1416, "3.1416"); + TEST_NUMBER(1E10, "1E10"); + TEST_NUMBER(1e10, "1e10"); + TEST_NUMBER(1E+10, "1E+10"); + TEST_NUMBER(1E-10, "1E-10"); + TEST_NUMBER(-1E10, "-1E10"); + TEST_NUMBER(-1e10, "-1e10"); + TEST_NUMBER(-1E+10, "-1E+10"); + TEST_NUMBER(-1E-10, "-1E-10"); + TEST_NUMBER(1.234E+10, "1.234E+10"); + TEST_NUMBER(1.234E-10, "1.234E-10"); + TEST_NUMBER(0.0, "1e-10000"); /* must underflow */ + +} + static void test_parse_null() { - lept_value v; - v.type = LEPT_FALSE; - EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "null")); - EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v)); + lept_value v; + v.type = LEPT_TRUE; + EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "null")); + EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v)); } static void test_parse_expect_value() { - lept_value v; + TEST_ERROR(LEPT_PARSE_EXPECT_VALUE, ""); + TEST_ERROR(LEPT_PARSE_EXPECT_VALUE, " "); +} - v.type = LEPT_FALSE; - EXPECT_EQ_INT(LEPT_PARSE_EXPECT_VALUE, lept_parse(&v, "")); - EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v)); +static void test_parse_invalid_value() { + TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "nul"); + TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "?"); - v.type = LEPT_FALSE; - EXPECT_EQ_INT(LEPT_PARSE_EXPECT_VALUE, lept_parse(&v, " ")); - EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v)); + //#if 0 + /* invalid number */ + 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, "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_invalid_value() { - lept_value v; - v.type = LEPT_FALSE; - EXPECT_EQ_INT(LEPT_PARSE_INVALID_VALUE, lept_parse(&v, "nul")); - EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v)); - - v.type = LEPT_FALSE; - EXPECT_EQ_INT(LEPT_PARSE_INVALID_VALUE, lept_parse(&v, "?")); - EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v)); +static void test_parse_abnormal_number() { + /* the smallest number > 1 */ + TEST_NUMBER(1.0000000000000002, "1.0000000000000002"); + /* minimum denormal */ + TEST_NUMBER(4.9406564584124654e-324, "4.9406564584124654e-324"); + TEST_NUMBER(-4.9406564584124654e-324, "-4.9406564584124654e-324"); + /* Max subnormal double */ + TEST_NUMBER(2.2250738585072009e-308, "2.2250738585072009e-308"); + TEST_NUMBER(-2.2250738585072009e-308, "-2.2250738585072009e-308"); + /* Min normal positive double */ + TEST_NUMBER(2.2250738585072014e-308, "2.2250738585072014e-308"); + TEST_NUMBER(-2.2250738585072014e-308, "-2.2250738585072014e-308"); + /* Max double */ + TEST_NUMBER(1.7976931348623157e+308, "1.7976931348623157e+308"); + TEST_NUMBER(-1.7976931348623157e+308, "-1.7976931348623157e+308"); } static void test_parse_root_not_singular() { - lept_value v; - v.type = LEPT_FALSE; - EXPECT_EQ_INT(LEPT_PARSE_ROOT_NOT_SINGULAR, lept_parse(&v, "null x")); - EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v)); + lept_value v; + v.type = LEPT_FALSE; + EXPECT_EQ_INT(LEPT_PARSE_ROOT_NOT_SINGULAR, lept_parse(&v, "null x")); + EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v)); +} + +static void test_parse_true() { + lept_value v; + v.type = LEPT_TRUE; + 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_NULL; + EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "false")); + EXPECT_EQ_INT(LEPT_FALSE, lept_get_type(&v)); +} + + static void test_parse() { - test_parse_null(); - test_parse_expect_value(); - test_parse_invalid_value(); - test_parse_root_not_singular(); + test_parse_null(); + test_parse_true(); + test_parse_false(); + test_parse_expect_value(); + test_parse_invalid_value(); + test_parse_root_not_singular(); + test_parse_number(); + test_parse_abnormal_number(); } int main() { - test_parse(); - printf("%d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count); - return main_ret; + test_parse(); + printf("%d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count); + system("pause"); + return main_ret; }