Skip to content

Parse numbers as either integer or floating type #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

<!-- TODO: document jimp.h here -->
31 changes: 17 additions & 14 deletions examples/03_parsing_database.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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");

Expand Down
22 changes: 11 additions & 11 deletions examples/database.json
Original file line number Diff line number Diff line change
@@ -1,66 +1,66 @@
{
"number": [69, 420, 1337, 80085],
"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",
"location": "Wonderland",
"body_count": 150,
"cash": 1.5,
"name": "Alice Smith",
"age": 34
},
{
"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
}
]
}
51 changes: 49 additions & 2 deletions jimp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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).
Expand Down Expand Up @@ -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 != '.' && *endptr != 'E' && *endptr != 'e')) {
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;
Expand Down Expand Up @@ -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;
Expand Down