diff --git a/MyCode/01/leptjson.c b/MyCode/01/leptjson.c new file mode 100644 index 00000000..3a93e369 --- /dev/null +++ b/MyCode/01/leptjson.c @@ -0,0 +1,94 @@ +#include "leptjson.h" +#include /* assert() */ +#include /* NULL */ + +#define EXPECT(c, ch) \ + do \ + { \ + assert(*c->json == (ch)); \ + c->json++; \ + }while(0) + +// 为了减少函数之间传递多个参数 +typedef struct { + const char *json; +}lept_context; + +// 解析(跳过)空白部分 +/* ws = *(%x20 / %x09 / %x0A / %x0D) */ +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; +} + +// 解析true +/* true = "true" */ +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; +} + +// 解析false +/* false = "false" */ +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; +} + +// 解析null +/* null = "null" */ +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; +} + +/* value = null / false / true */ +static int lept_parse_value(lept_context* c, lept_value* v) { + switch(*c->json) { + case 'n': + return lept_parse_null(c, v); + case 't': + return lept_parse_true(c, v); + case 'f': + return lept_parse_false(c, v); + case '\0': + return LEPT_PARSE_EXPECT_VALUE; + default: + return LEPT_PARSE_INVALID_VALUE; + } +} + +int lept_parse(lept_value* v, const char* json) { + lept_context c; + int ret; + assert(v != NULL); + c.json = json; + v->type = LEPT_NULL; + lept_parse_whitespace(&c); + if ((ret = lept_parse_value(&c, v)) == LEPT_PARSE_OK) { + lept_parse_whitespace(&c); + if (*c.json != '\0') + ret = LEPT_PARSE_ROOT_NOT_SINGULAR; + } + return ret; +} + +// 获取数据类型 +lept_type lept_get_type(const lept_value* v) { + assert(v != NULL); + return v->type; +} diff --git a/MyCode/01/leptjson.h b/MyCode/01/leptjson.h new file mode 100644 index 00000000..188b86fd --- /dev/null +++ b/MyCode/01/leptjson.h @@ -0,0 +1,35 @@ +// 项目名称_目录_文件名_H__ +#ifndef LEPTJSON_H__ +#define LEPTJSON_H__ + +// JSON数据类型 +typedef enum { LEPT_NULL, + LEPT_FALSE, + LEPT_TRUE, + LEPT_NUMBER, + LEPT_STRING, + LEPT_ARRAY, + LEPT_OBJECT + } lept_type; + +// JSON数据值 +typedef struct { + lept_type type; +} lept_value; + +// 函数调用返回错误码 +enum +{ + LEPT_PARSE_OK = 0, + LEPT_PARSE_EXPECT_VALUE, // JSON只有空白 + LEPT_PARSE_INVALID_VALUE, // 非正确字面值 + LEPT_PARSE_ROOT_NOT_SINGULAR // 空白之后还有其他字符 +}; + +// 解析JSON函数 +int lept_parse(lept_value* v, const char* json); + +// 访问结果函数 +lept_type lept_get_type(const lept_value* v); + +#endif \ No newline at end of file diff --git a/MyCode/01/leptjson.o b/MyCode/01/leptjson.o new file mode 100644 index 00000000..36da6cdf Binary files /dev/null and b/MyCode/01/leptjson.o differ diff --git a/MyCode/01/makefile b/MyCode/01/makefile new file mode 100644 index 00000000..984af88a --- /dev/null +++ b/MyCode/01/makefile @@ -0,0 +1,8 @@ +test.exe: leptjson.o test.o + gcc leptjson.o test.o -o test.exe + +leptjson.o: leptjson.c leptjson.h + gcc leptjson.c -c + +test.o: test.c + gcc test.c -c \ No newline at end of file diff --git a/MyCode/01/test.c b/MyCode/01/test.c new file mode 100644 index 00000000..fd718337 --- /dev/null +++ b/MyCode/01/test.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include "leptjson.h" + +static int main_ret = 0; +static int test_count = 0; +static int test_pass = 0; + +#define EXPECT_EQ_BASE(equality, expect, actual, format) \ + do { \ + test_count++; \ + if (equality) \ + test_pass++; \ + else { \ + fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", __FILE__, __LINE__, expect, actual); \ + main_ret = 1;\ + }\ + }while(0) + +#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d") + +// 具体测试函数 +//因为 static 函数的意思是指,该函数只作用于编译单元中,那么没有被调用时,编译器是能发现的。 +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)); +} + +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; // 这里设置为TRUE,让lept_get_type中修改这个值 + 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; + v.type = LEPT_FALSE; + EXPECT_EQ_INT(LEPT_PARSE_EXPECT_VALUE, lept_parse(&v, "")); + EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v)); + + 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() { + 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_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)); +} + +static void test_parse() { + test_parse_null(); + test_parse_true(); + test_parse_false(); + test_parse_expect_value(); + test_parse_root_not_singular(); +} + +int main(){ + test_parse(); + printf("%d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count); + return main_ret; +} \ No newline at end of file diff --git a/MyCode/01/test.exe b/MyCode/01/test.exe new file mode 100644 index 00000000..c3360f0d Binary files /dev/null and b/MyCode/01/test.exe differ diff --git a/MyCode/01/test.o b/MyCode/01/test.o new file mode 100644 index 00000000..b7491b83 Binary files /dev/null and b/MyCode/01/test.o differ diff --git a/MyCode/02/.vscode/launch.json b/MyCode/02/.vscode/launch.json new file mode 100644 index 00000000..08a1e421 --- /dev/null +++ b/MyCode/02/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Launch", + "type": "cppdbg", + "request": "launch", + "program": "enter program name, for example ${workspaceFolder}/a.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": true, + "MIMode": "gdb", + "miDebuggerPath": "/path/to/gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/MyCode/02/.vscode/settings.json b/MyCode/02/.vscode/settings.json new file mode 100644 index 00000000..4217d5b7 --- /dev/null +++ b/MyCode/02/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "string.h": "c" + } +} \ No newline at end of file diff --git a/MyCode/02/leptjson.c b/MyCode/02/leptjson.c new file mode 100644 index 00000000..53b04277 --- /dev/null +++ b/MyCode/02/leptjson.c @@ -0,0 +1,119 @@ +#include "leptjson.h" +#include /* assert() */ +#include /* NULL */ +#include /* errno, ERANGE */ +#include /* HUGE_VAL */ + +#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; + +// 解析(跳过)空白部分 +/* ws = *(%x20 / %x09 / %x0A / %x0D) */ +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_number(lept_context* c, lept_value* v) { + const char* p = c->json; + /* 负号 ... */ + if('-' == *p) ++p; + /* 整数 ... 只有0或者非零开头的整数*/ + if('0' == *p) ++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('e' == *p || 'E' == *p) { + ++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 || v->n == -HUGE_VAL)) + return LEPT_PARSE_NUMBER_TOO_BIG; + v->type = LEPT_NUMBER; + c->json = p; + return LEPT_PARSE_OK; +} + +/* value = null / false / true */ +static int lept_parse_value(lept_context* c, lept_value* v) { + switch(*c->json) { + case 'n': + return lept_parse_literal(c, v, "null", LEPT_NULL); + case 't': + return lept_parse_literal(c, v, "true", LEPT_TRUE); + case 'f': + return lept_parse_literal(c, v, "false", LEPT_FALSE); + case '\0': + return LEPT_PARSE_EXPECT_VALUE; + default: + return lept_parse_number(c, v); + } +} + +int lept_parse(lept_value* v, const char* json) { + lept_context c; + int ret; + assert(v != NULL); + c.json = json; + v->type = LEPT_NULL; + 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; + } + } + return ret; +} + +// 获取数据类型 +lept_type lept_get_type(const lept_value* v) { + 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/MyCode/02/leptjson.h b/MyCode/02/leptjson.h new file mode 100644 index 00000000..fee37565 --- /dev/null +++ b/MyCode/02/leptjson.h @@ -0,0 +1,37 @@ +// 项目名称_目录_文件名_H__ +#ifndef LEPTJSON_H__ +#define LEPTJSON_H__ + +// JSON数据类型 +typedef enum { LEPT_NULL, + LEPT_FALSE, + LEPT_TRUE, + LEPT_NUMBER, + LEPT_STRING, + LEPT_ARRAY, + LEPT_OBJECT + } lept_type; + +// JSON数据值 +typedef struct { + double n; + lept_type type; +} lept_value; + +// 函数调用返回错误码 +enum { + LEPT_PARSE_OK = 0, + LEPT_PARSE_EXPECT_VALUE, // JSON只有空白 + LEPT_PARSE_INVALID_VALUE, // 非正确字面值 + LEPT_PARSE_ROOT_NOT_SINGULAR, // 空白之后还有其他字符 + LEPT_PARSE_NUMBER_TOO_BIG +}; + +// 解析JSON函数 +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 \ No newline at end of file diff --git a/MyCode/02/leptjson.o b/MyCode/02/leptjson.o new file mode 100644 index 00000000..466e94cb Binary files /dev/null and b/MyCode/02/leptjson.o differ diff --git a/MyCode/02/makefile b/MyCode/02/makefile new file mode 100644 index 00000000..984af88a --- /dev/null +++ b/MyCode/02/makefile @@ -0,0 +1,8 @@ +test.exe: leptjson.o test.o + gcc leptjson.o test.o -o test.exe + +leptjson.o: leptjson.c leptjson.h + gcc leptjson.c -c + +test.o: test.c + gcc test.c -c \ No newline at end of file diff --git a/MyCode/02/test.c b/MyCode/02/test.c new file mode 100644 index 00000000..38c06f24 --- /dev/null +++ b/MyCode/02/test.c @@ -0,0 +1,142 @@ +#include +#include +#include +#include "leptjson.h" + +static int main_ret = 0; +static int test_count = 0; +static int test_pass = 0; + +#define EXPECT_EQ_BASE(equality, expect, actual, format) \ + do { \ + test_count++; \ + if (equality) \ + test_pass++; \ + else { \ + fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", __FILE__, __LINE__, expect, actual); \ + main_ret = 1;\ + }\ + } while(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, "%f") + +#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) + +#define TEST_LITERAL(_type, _json) \ + do { \ + lept_value v; \ + v.type = LEPT_FALSE; \ + EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, _json)); \ + EXPECT_EQ_INT(_type, lept_get_type(&v)); \ + } while(0) + +#define TEST_NUMBER(_expect, _json) \ + do { \ + lept_value _v; \ + _v.type = LEPT_NULL; \ + 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) + +// 具体测试函数 +//因为 static 函数的意思是指,该函数只作用于编译单元中,那么没有被调用时,编译器是能发现的。 +static void test_parse_literal() { + TEST_LITERAL(LEPT_NULL, "null"); + TEST_LITERAL(LEPT_TRUE, "true"); + TEST_LITERAL(LEPT_FALSE, "false"); +} + +static void test_parse_number() { + TEST_NUMBER(0.0, "0"); + TEST_NUMBER(0.0, "-0.0"); + TEST_NUMBER(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.1415, "3.1415"); + TEST_NUMBER(1E+10, "1E+10"); + TEST_NUMBER(1E-10, "1E-10"); + TEST_NUMBER(-1E10, "-1E10"); + TEST_NUMBER(-1e10, "-1e10"); + TEST_NUMBER(-1e10, "-1e10"); + TEST_NUMBER(1.234E-10, "1.234E-10"); + TEST_NUMBER(0.0, "1e-10000"); /* must underflow 下溢出*/ + /* 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_expect_value() { + TEST_ERROR(LEPT_PARSE_EXPECT_VALUE, ""); + TEST_ERROR(LEPT_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, "+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_root_not_singular() { + TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "null x"); + +#if 0 + /* invalid number */ + 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() { + test_parse_literal(); + test_parse_number(); + test_parse_expect_value(); + test_parse_invalid_value(); + test_parse_root_not_singular(); + test_parse_number_too_big(); +} + +int main(){ + test_parse(); + printf("%d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count); + return main_ret; +} \ No newline at end of file diff --git a/MyCode/02/test.exe b/MyCode/02/test.exe new file mode 100644 index 00000000..99c5fcbf Binary files /dev/null and b/MyCode/02/test.exe differ diff --git a/MyCode/02/test.o b/MyCode/02/test.o new file mode 100644 index 00000000..19c02539 Binary files /dev/null and b/MyCode/02/test.o differ diff --git a/tutorial01/test.exe b/tutorial01/test.exe new file mode 100644 index 00000000..2b0f4ac0 Binary files /dev/null and b/tutorial01/test.exe differ