persing minus sign and exponents for numeric values

This commit is contained in:
cozis
2022-04-24 23:12:35 +02:00
parent 841e3f75fa
commit 113830d092
7 changed files with 132 additions and 10 deletions
+5 -1
View File
@@ -1,3 +1,7 @@
test
vgcore.*
parse-file
*.gcno
*.gcda
*.gcov
parse-file
all.json
+17 -2
View File
@@ -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
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
Executable
+3
View File
@@ -0,0 +1,3 @@
rm *.gcda
rm *.gcno
rm vgcore.*
Executable
+3
View File
@@ -0,0 +1,3 @@
./build.sh --coverage
./test
gcov -b test-xjson.gcno
+2 -1
View File
@@ -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);
+15
View File
@@ -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("{}"),
+87 -6
View File
@@ -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 == '[')