From 113830d092e2e488e8ad5c6b74a3fe81f426326a Mon Sep 17 00:00:00 2001 From: cozis Date: Sun, 24 Apr 2022 23:12:35 +0200 Subject: [PATCH] persing minus sign and exponents for numeric values --- .gitignore | 6 +++- build.sh | 19 +++++++++-- clean.sh | 3 ++ coverage.sh | 3 ++ parse-file.c | 3 +- test.c | 15 +++++++++ xjson.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++---- 7 files changed, 132 insertions(+), 10 deletions(-) create mode 100755 clean.sh create mode 100755 coverage.sh diff --git a/.gitignore b/.gitignore index 55db490..b8463b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ test vgcore.* -parse-file \ No newline at end of file +*.gcno +*.gcda +*.gcov +parse-file +all.json \ No newline at end of file diff --git a/build.sh b/build.sh index 9c42f98..a93fa4d 100755 --- a/build.sh +++ b/build.sh @@ -1,2 +1,17 @@ -gcc test.c xjson.c -o test -Wall -Wextra -g -gcc parse-file.c xjson.c -o parse-file -Wall -Wextra -g \ No newline at end of file +CC=gcc +FLAGS="-Wall -Wextra" + +for arg in "$@" +do + case $arg in + --debug) FLAGS="$FLAGS -DDEBUG -g" + ;; + --release) FLAGS="$FLAGS -DNDEBUG -O3" + ;; + --coverage) FLAGS="$FLAGS -fprofile-arcs -ftest-coverage" + ;; + esac +done + +$CC test.c xjson.c -o test $FLAGS +$CC parse-file.c xjson.c -o parse-file $FLAGS \ No newline at end of file diff --git a/clean.sh b/clean.sh new file mode 100755 index 0000000..f229bef --- /dev/null +++ b/clean.sh @@ -0,0 +1,3 @@ +rm *.gcda +rm *.gcno +rm vgcore.* \ No newline at end of file diff --git a/coverage.sh b/coverage.sh new file mode 100755 index 0000000..b94c5f4 --- /dev/null +++ b/coverage.sh @@ -0,0 +1,3 @@ +./build.sh --coverage +./test +gcov -b test-xjson.gcno \ No newline at end of file diff --git a/parse-file.c b/parse-file.c index 6daaf8b..0067d11 100644 --- a/parse-file.c +++ b/parse-file.c @@ -23,7 +23,8 @@ char *load_file(const char *path, int *len) return NULL; } - if(fread(data, 1, len_, fp) != len_) + assert(len_ >= 0); + if(fread(data, 1, len_, fp) != (unsigned int) len_) { free(data); fclose(fp); diff --git a/test.c b/test.c index eafb744..201da4f 100644 --- a/test.c +++ b/test.c @@ -13,10 +13,25 @@ static const struct { TEST("null"), TEST("true"), TEST("false"), + TEST("1"), TEST("100"), + TEST("-1"), + TEST("-100"), TEST("1.0"), TEST("100.111"), + TEST("-1.0"), + TEST("-100.111"), + + TEST("1e1"), + TEST("100e1"), + TEST("-1e1"), + TEST("-100e1"), + TEST("1.0e1"), + TEST("100.111e1"), + TEST("-1.0e1"), + TEST("-100.111e10"), + TEST("[]"), TEST("[1, 2, 3]"), TEST("{}"), diff --git a/xjson.c b/xjson.c index 1a19eb8..61f9aad 100644 --- a/xjson.c +++ b/xjson.c @@ -732,7 +732,29 @@ static void *parse_string(context_t *ctx, _Bool raw) static xj_value *parse_number(context_t *ctx) { - assert(ctx->i < ctx->len && isdigit(ctx->str[ctx->i])); + assert(ctx->i < ctx->len && (isdigit(ctx->str[ctx->i]) || ctx->str[ctx->i] == '-')); + + _Bool negative = 0; + if(ctx->str[ctx->i] == '-') + { + negative = 1; + + ctx->i += 1; // Skip '-'. + + if(ctx->i == ctx->len) + { + xj_report(ctx->error, "String ended inside after minus sign"); + return NULL; + } + + if(!isdigit(ctx->str[ctx->i])) + { + xj_preport(ctx->error, ctx->str, ctx->i, "Expected a digit after minus sign"); + return NULL; + } + } + + // NOTE: We allow non-0 numbers starting with 0. xj_i64 parsed = 0; @@ -752,23 +774,82 @@ static xj_value *parse_number(context_t *ctx) xj_bool followed_by_dot = ctx->i+1 < ctx->len && ctx->str[ctx->i] == '.' && isdigit(ctx->str[ctx->i+1]); + xj_f64 decimal; + if(followed_by_dot) { ctx->i += 1; // Skip '.'. - xj_f64 parsed2 = parsed, f = 1.0; + xj_f64 f = 1.0; + + decimal = 0; while(ctx->i < ctx->len && isdigit(ctx->str[ctx->i])) { f /= 10; - parsed2 += f * (ctx->str[ctx->i] - '0'); + decimal += f * (ctx->str[ctx->i] - '0'); + ctx->i += 1; + } + } + + _Bool have_exponent = 0; + xj_f64 coeff; + + if(ctx->i < ctx->len && (ctx->str[ctx->i] == 'e' || ctx->str[ctx->i] == 'E')) + { + ctx->i += 1; // Skip 'e'. + + if(ctx->i == ctx->len) + { + xj_report(ctx->error, "String ended where an exponent was expected"); + return NULL; + } + + if(!isdigit(ctx->str[ctx->i])) + { + xj_report(ctx->error, ctx->str, ctx->i, "Expected digit as exponent"); + return NULL; + } + + have_exponent = 1; + int exponent = 0; + while(ctx->i < ctx->len && isdigit(ctx->str[ctx->i])) + { + exponent = exponent * 10 + ctx->str[ctx->i] - '0'; ctx->i += 1; } - return xj_value_float(parsed2, ctx->alloc, ctx->error); + coeff = 1; + for(int j = 0; j < exponent; j += 1) + coeff *= 10; } - return xj_value_int(parsed, ctx->alloc, ctx->error); + xj_value *v; + if(followed_by_dot) + { + xj_f64 r = (xj_f64) parsed + decimal; + + if(negative) + r = -r; + + if(have_exponent) + r = r * coeff; + + v = xj_value_float(r, ctx->alloc, ctx->error); + } + else + { + xj_i64 r = parsed; + + if(negative) + r = -r; + + if(have_exponent) + r = r * coeff; + + v = xj_value_int(r, ctx->alloc, ctx->error); + } + return v; } static xj_value *parse_value(context_t *ctx); @@ -971,7 +1052,7 @@ static xj_value *parse_value(context_t *ctx) if(c == '"') return parse_string(ctx, 0); - if(isdigit(c)) + if(isdigit(c) || c == '-') return parse_number(ctx); if(c == '[')