From 2a7175108f8c20ad6208f17627073264e147db19 Mon Sep 17 00:00:00 2001 From: Guiorgy Date: Sun, 29 Jun 2025 14:11:45 +0400 Subject: [PATCH 1/4] fixed a typo in README also added a missing punctuation --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9ea6a78..cface43 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ $ ./test record ## Notes -1. Does not depends on libc. Could be theoretically used in embedded, but I know nothing about embedded, so maybe not. -2. `jim_float()` is quite likely very stupid and imprecise +1. Does not depend on libc. Could be theoretically used in embedded, but I know nothing about embedded, so maybe not. +2. `jim_float()` is quite likely very stupid and imprecise. From f06394f46c90f1dc948e4a6bb92756f522150bc0 Mon Sep 17 00:00:00 2001 From: Guiorgy Date: Sun, 29 Jun 2025 16:49:52 +0400 Subject: [PATCH 2/4] support parsing numbers as integers --- examples/03_parsing_database.c | 31 +++++++++++---------- examples/database.json | 22 +++++++-------- jimp.h | 51 ++++++++++++++++++++++++++++++++-- 3 files changed, 77 insertions(+), 27 deletions(-) diff --git a/examples/03_parsing_database.c b/examples/03_parsing_database.c index 15e7aad..eaf9d94 100644 --- a/examples/03_parsing_database.c +++ b/examples/03_parsing_database.c @@ -8,9 +8,9 @@ typedef struct { const char *name; - double age; + long long age; const char *location; - double body_count; + double cash; } Person; typedef struct { @@ -27,14 +27,14 @@ bool parse_person(Jimp *jimp, Person *p) if (!jimp_string(jimp)) return false; p->name = strdup(jimp->string); } else if (strcmp(jimp->string, "age") == 0) { - if (!jimp_number(jimp)) return false; - p->age = jimp->number; + if (!jimp_integer(jimp)) return false; + p->age = jimp->integer; } else if (strcmp(jimp->string, "location") == 0) { if (!jimp_string(jimp)) return false; p->location = strdup(jimp->string); - } else if (strcmp(jimp->string, "body_count") == 0) { - if (!jimp_number(jimp)) return false; - p->body_count = jimp->number; + } else if (strcmp(jimp->string, "cash") == 0) { + if (!jimp_float(jimp)) return false; + p->cash = jimp->floating; } else { jimp_unknown_member(jimp); return false; @@ -58,14 +58,14 @@ bool parse_people(Jimp *jimp, People *ps) void print_person(const Person *p) { - printf("name = %s\n", p->name); - printf("age = %lf\n", p->age); - printf("location = %s\n", p->location); - printf("body_count = %lf\n", p->body_count); + printf("name = %s\n", p->name); + printf("age = %lld\n", p->age); + printf("location = %s\n", p->location); + printf("cash = $%.2lf\n", p->cash); } typedef struct { - long *items; + JimpNumber *items; size_t count; size_t capacity; } Numbers; @@ -105,8 +105,11 @@ int main(void) printf("\n"); } printf("------------------------------\n"); - da_foreach(long, x, &xs) { - printf("%ld ", *x); + da_foreach(JimpNumber, x, &xs) { + if (x->type == JIMP_INTEGER) + printf("%lld ", x->value.i); + else + printf("%lf ", x->value.f); } printf("\n"); diff --git a/examples/database.json b/examples/database.json index 57356d8..b00e4b5 100644 --- a/examples/database.json +++ b/examples/database.json @@ -1,10 +1,10 @@ { - "number": [69, 420, 1337, 80085], + "number": [69, 420, 1337, 80085, .69, 42.123, 123., 9007199254740993, 9007199254740993.0], "profile": [ { "location": "Wonderland", "location": "Wonderland", - "body_count": 150, + "cash": 1.5, "name": "Alice Smith", "age": 34 }, @@ -12,55 +12,55 @@ "name": "Bob Johnson", "age": 45, "location": "Atlantis", - "body_count": 300 + "cash": 3 }, { "name": "Charlie Brown", "age": 28, "location": "Chocolate Factory", - "body_count": 200 + "cash": 2 }, { "name": "Diana Prince", "age": 32, "location": "Themyscira", - "body_count": 250 + "cash": 2.5 }, { "name": "Ethan Hunt", "age": 40, "location": "Mission HQ", - "body_count": 350 + "cash": 3.5 }, { "name": "Fiona Apple", "age": 37, "location": "Music City", - "body_count": 180 + "cash": 1.8 }, { "name": "George Lucas", "age": 75, "location": "Galaxy Far Far Away", - "body_count": 500 + "cash": 5 }, { "name": "Hannah Montana", "age": 25, "location": "Nashville", - "body_count": 100 + "cash": 1 }, { "name": "Ian Malcolm", "age": 60, "location": "Jurassic Park", - "body_count": 400 + "cash": 4 }, { "name": "Jessica Rabbit", "age": 30, "location": "Toontown", - "body_count": 220 + "cash": 2.2 } ] } diff --git a/jimp.h b/jimp.h index 7667d97..d33005c 100644 --- a/jimp.h +++ b/jimp.h @@ -35,6 +35,21 @@ typedef enum { JIMP_NUMBER, } Jimp_Token; +typedef enum { + JIMP_FLOATING, + JIMP_INTEGER +} JimpNumberType; + +union JimpNumberValue { + double f; + long long i; +}; + +typedef struct { + JimpNumberType type; + union JimpNumberValue value; +} JimpNumber; + typedef struct { const char *file_path; const char *start; @@ -47,7 +62,9 @@ typedef struct { char *string; size_t string_count; size_t string_capacity; - double number; + JimpNumber number; + double floating; + long long integer; bool boolean; } Jimp; @@ -63,6 +80,14 @@ bool jimp_boolean(Jimp *jimp); /// Any consequent calls to the jimp_* functions may invalidate jimp->number. bool jimp_number(Jimp *jimp); +/// If succeeds puts the freshly parsed number into jimp->number and jimp->floating. +/// Any consequent calls to the jimp_* functions may invalidate jimp->number and jimp->floating. +bool jimp_float(Jimp *jimp); + +/// If succeeds puts the freshly parsed number into jimp->number and jimp->integer. +/// Any consequent calls to the jimp_* functions may invalidate jimp->number and jimp->integer. +bool jimp_integer(Jimp *jimp); + /// If succeeds puts the freshly parsed string into jimp->string as a NULL-terminated string. /// Any consequent calls to the jimp_* functions may invalidate jimp->string. /// strdup it if you don't wanna lose it (memory management is on you at that point). @@ -175,8 +200,16 @@ static bool jimp__get_token(Jimp *jimp) } char *endptr = NULL; - jimp->number = strtod(jimp->point, &endptr); // TODO: This implies that jimp->end is a valid address and *jimp->end == 0 + jimp->number.value.i = strtoull(jimp->point, &endptr, 0); // TODO: This implies that jimp->end is a valid address and *jimp->end == 0 + if (jimp->point != endptr && *endptr != '.') { + jimp->number.type = JIMP_INTEGER; + jimp->point = endptr; + jimp->token = JIMP_NUMBER; + return true; + } + jimp->number.value.f = strtod(jimp->point, &endptr); if (jimp->point != endptr) { + jimp->number.type = JIMP_FLOATING; jimp->point = endptr; jimp->token = JIMP_NUMBER; return true; @@ -370,6 +403,20 @@ bool jimp_number(Jimp *jimp) return jimp__get_and_expect_token(jimp, JIMP_NUMBER); } +bool jimp_float(Jimp *jimp) +{ + if (!jimp__get_and_expect_token(jimp, JIMP_NUMBER)) return false; + jimp->floating = jimp->number.type == JIMP_FLOATING ? jimp->number.value.f : jimp->number.value.i; + return true; +} + +bool jimp_integer(Jimp *jimp) +{ + if (!jimp__get_and_expect_token(jimp, JIMP_NUMBER) || jimp->number.type != JIMP_INTEGER) return false; + jimp->integer = jimp->number.value.i; + return true; +} + static bool jimp__get_and_expect_token(Jimp *jimp, Jimp_Token token) { if (!jimp__get_token(jimp)) return false; From 6e2ab645d43eccd996484cc1f003f6741d1de4d6 Mon Sep 17 00:00:00 2001 From: Guiorgy Date: Sun, 29 Jun 2025 17:23:37 +0400 Subject: [PATCH 3/4] also account for scientific notation --- examples/database.json | 2 +- jimp.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/database.json b/examples/database.json index b00e4b5..7b6fffa 100644 --- a/examples/database.json +++ b/examples/database.json @@ -1,5 +1,5 @@ { - "number": [69, 420, 1337, 80085, .69, 42.123, 123., 9007199254740993, 9007199254740993.0], + "number": [69, 420, 1337, 80085, .69, 42.123, 123., 9007199254740993, 9007199254740993.0, +1, -1, +1.0, -1.0, +.1, -.0, 5e5, 5E5, +5e+5, -5e-5], "profile": [ { "location": "Wonderland", diff --git a/jimp.h b/jimp.h index d33005c..e4a6238 100644 --- a/jimp.h +++ b/jimp.h @@ -201,7 +201,7 @@ static bool jimp__get_token(Jimp *jimp) char *endptr = NULL; jimp->number.value.i = strtoull(jimp->point, &endptr, 0); // TODO: This implies that jimp->end is a valid address and *jimp->end == 0 - if (jimp->point != endptr && *endptr != '.') { + if (jimp->point != endptr && (*endptr != '.' && *endptr != 'E' && *endptr != 'e')) { jimp->number.type = JIMP_INTEGER; jimp->point = endptr; jimp->token = JIMP_NUMBER; From 44a58f2117b7bd09913aa2e89ea52c5d7345ce52 Mon Sep 17 00:00:00 2001 From: Guiorgy Date: Thu, 3 Jul 2025 13:54:34 +0400 Subject: [PATCH 4/4] flattened JimpNumber struct into Jimp also renamed floating -> decimal --- examples/03_parsing_database.c | 20 ++++++++----- jimp.h | 52 +++++++--------------------------- 2 files changed, 24 insertions(+), 48 deletions(-) diff --git a/examples/03_parsing_database.c b/examples/03_parsing_database.c index eaf9d94..66876f4 100644 --- a/examples/03_parsing_database.c +++ b/examples/03_parsing_database.c @@ -27,14 +27,14 @@ bool parse_person(Jimp *jimp, Person *p) if (!jimp_string(jimp)) return false; p->name = strdup(jimp->string); } else if (strcmp(jimp->string, "age") == 0) { - if (!jimp_integer(jimp)) return false; + if (!jimp_number(jimp)) return false; p->age = jimp->integer; } else if (strcmp(jimp->string, "location") == 0) { if (!jimp_string(jimp)) return false; p->location = strdup(jimp->string); } else if (strcmp(jimp->string, "cash") == 0) { - if (!jimp_float(jimp)) return false; - p->cash = jimp->floating; + if (!jimp_number(jimp)) return false; + p->cash = jimp->decimal; } else { jimp_unknown_member(jimp); return false; @@ -65,7 +65,13 @@ void print_person(const Person *p) } typedef struct { - JimpNumber *items; + JimpNumberType type; + long long integer; + double decimal; +} Number; + +typedef struct { + Number *items; size_t count; size_t capacity; } Numbers; @@ -90,7 +96,7 @@ int main(void) if (!jimp_array_begin(&jimp)) return 1; while (jimp_array_item(&jimp)) { if (!jimp_number(&jimp)) return 1; - da_append(&xs, jimp.number); + da_append(&xs, {.type = jimp.number_type, .integer = jimp.integer, .decimal = jimp.decimal}); } if (!jimp_array_end(&jimp)) return 1; } else { @@ -107,9 +113,9 @@ int main(void) printf("------------------------------\n"); da_foreach(JimpNumber, x, &xs) { if (x->type == JIMP_INTEGER) - printf("%lld ", x->value.i); + printf("%lld ", x->integer); else - printf("%lf ", x->value.f); + printf("%lf ", x->decimal); } printf("\n"); diff --git a/jimp.h b/jimp.h index e4a6238..e6534be 100644 --- a/jimp.h +++ b/jimp.h @@ -36,20 +36,10 @@ typedef enum { } Jimp_Token; typedef enum { - JIMP_FLOATING, + JIMP_DECIMAL, JIMP_INTEGER } JimpNumberType; -union JimpNumberValue { - double f; - long long i; -}; - -typedef struct { - JimpNumberType type; - union JimpNumberValue value; -} JimpNumber; - typedef struct { const char *file_path; const char *start; @@ -62,8 +52,8 @@ typedef struct { char *string; size_t string_count; size_t string_capacity; - JimpNumber number; - double floating; + JimpNumberType number_type; + double decimal; long long integer; bool boolean; } Jimp; @@ -76,18 +66,10 @@ void jimp_begin(Jimp *jimp, const char *file_path, const char *input, size_t inp /// Any consequent calls to the jimp_* functions may invalidate jimp->boolean. bool jimp_boolean(Jimp *jimp); -/// If succeeds puts the freshly parsed number into jimp->number. -/// Any consequent calls to the jimp_* functions may invalidate jimp->number. +/// If succeeds puts the freshly parsed number into jimp->number_type, jimp->decimal and jimp->integer. +/// Any consequent calls to the jimp_* functions may invalidate jimp->number_type, jimp->decimal and jimp->integer. bool jimp_number(Jimp *jimp); -/// If succeeds puts the freshly parsed number into jimp->number and jimp->floating. -/// Any consequent calls to the jimp_* functions may invalidate jimp->number and jimp->floating. -bool jimp_float(Jimp *jimp); - -/// If succeeds puts the freshly parsed number into jimp->number and jimp->integer. -/// Any consequent calls to the jimp_* functions may invalidate jimp->number and jimp->integer. -bool jimp_integer(Jimp *jimp); - /// If succeeds puts the freshly parsed string into jimp->string as a NULL-terminated string. /// Any consequent calls to the jimp_* functions may invalidate jimp->string. /// strdup it if you don't wanna lose it (memory management is on you at that point). @@ -200,16 +182,18 @@ static bool jimp__get_token(Jimp *jimp) } char *endptr = NULL; - jimp->number.value.i = strtoull(jimp->point, &endptr, 0); // TODO: This implies that jimp->end is a valid address and *jimp->end == 0 + jimp->integer = strtoull(jimp->point, &endptr, 0); // TODO: This implies that jimp->end is a valid address and *jimp->end == 0 if (jimp->point != endptr && (*endptr != '.' && *endptr != 'E' && *endptr != 'e')) { - jimp->number.type = JIMP_INTEGER; + jimp->number_type = JIMP_INTEGER; + jimp->decimal = jimp->integer; jimp->point = endptr; jimp->token = JIMP_NUMBER; return true; } - jimp->number.value.f = strtod(jimp->point, &endptr); + jimp->decimal = strtod(jimp->point, &endptr); if (jimp->point != endptr) { - jimp->number.type = JIMP_FLOATING; + jimp->number_type = JIMP_DECIMAL; + jimp->integer = jimp->decimal; jimp->point = endptr; jimp->token = JIMP_NUMBER; return true; @@ -403,20 +387,6 @@ bool jimp_number(Jimp *jimp) return jimp__get_and_expect_token(jimp, JIMP_NUMBER); } -bool jimp_float(Jimp *jimp) -{ - if (!jimp__get_and_expect_token(jimp, JIMP_NUMBER)) return false; - jimp->floating = jimp->number.type == JIMP_FLOATING ? jimp->number.value.f : jimp->number.value.i; - return true; -} - -bool jimp_integer(Jimp *jimp) -{ - if (!jimp__get_and_expect_token(jimp, JIMP_NUMBER) || jimp->number.type != JIMP_INTEGER) return false; - jimp->integer = jimp->number.value.i; - return true; -} - static bool jimp__get_and_expect_token(Jimp *jimp, Jimp_Token token) { if (!jimp__get_token(jimp)) return false;