add json parsing of lists and maps

This commit is contained in:
Felix Van der Jeugt 2022-11-08 23:31:00 +01:00
parent 7471093f67
commit 025c8125fa
No known key found for this signature in database
GPG Key ID: 58B209295023754D
16 changed files with 210 additions and 20 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
*.o *.o
planarbot planarbot
echojson

View File

@ -26,18 +26,20 @@ void add_list(ArrayList *this, void *item) {
this->items[this->size++] = item; this->items[this->size++] = item;
} }
void free_listitems(ArrayList *this) { void * fold_list(ArrayList *this, void *init, void * (*f)(void *acc, int index, void *item)) {
int i; int i;
for(i = 0; i < this->size; i++) { for(i = 0; i < this->size; i++) {
free(this->items[i]); init = f(init, i, this->items[i]);
} }
return init;
}
void * free_listitem(void *acc, int index, void *item) {
free(item);
return NULL;
} }
void free_list(ArrayList *this) { void free_list(ArrayList *this) {
int i;
for (i = 0; i < this->size; i++) {
free(this->items[i]);
}
free(this->items); free(this->items);
free(this); free(this);
} }

View File

@ -9,6 +9,7 @@ typedef struct arraylist {
ArrayList * list(); ArrayList * list();
void * get_list(ArrayList *this, int index); void * get_list(ArrayList *this, int index);
void add_list(ArrayList *this, void *item); void add_list(ArrayList *this, void *item);
void free_listitems(ArrayList *this); void * fold_list(ArrayList *this, void *init, void * (*f)(void *acc, int index, void *item));
void * free_listitem(void *acc, int index, void *item);
void free_list(ArrayList *this); void free_list(ArrayList *this);
#endif #endif

12
echojson.c Normal file
View File

@ -0,0 +1,12 @@
#include <stdio.h>
#include "json.h"
int main(int argc, char **argv) {
FILE *fp = fopen(argv[1], "r");
Json * json = json_parse(fp);
json_print(json, stdout);
json_free(json);
fclose(fp);
return 0;
}

135
json.c
View File

@ -67,6 +67,7 @@ Json * parse_number(FILE *stream, int sign) {
break; break;
default: default:
if (c != EOF) ungetc(c, stream); if (c != EOF) ungetc(c, stream);
if (den == 0) den = 1;
json = malloc(sizeof(Json)); json = malloc(sizeof(Json));
json->type = NUMBER; json->type = NUMBER;
json->value.number = sign * num * 1.0 / den; json->value.number = sign * num * 1.0 / den;
@ -104,15 +105,109 @@ Json * parse_string(FILE *stream) {
buffer[i++] = c; buffer[i++] = c;
} }
} }
free(buffer);
return NULL; return NULL;
} }
Json * parse_list(FILE *stream) { return NULL; /* TODO */ } Json * parse_list(FILE *stream) {
Json * parse_map(FILE *stream) { return NULL; /* TODO */ } char c;
Json * json;
ArrayList * values = list();
int expect_comma = 0;
while ((c = getc(stream)) != EOF) {
switch (c) {
case ']':
json = malloc(sizeof(Json));
json->type = LIST;
json->value.list = values;
return json;
case ' ':
case '\n':
case '\t':
break;
case ',':
if (expect_comma) {
expect_comma = 0;
break;
}
default:
ungetc(c, stream);
json = json_parse(stream);
add_list(values, (void *) json);
expect_comma = 1;
}
}
fold_list(values, NULL, free_listitem);
free_list(values);
return NULL;
}
enum map_state { MKEY, MCOLON, MVALUE, MCOMMA };
Json * parse_map(FILE *stream) {
char c;
Json * json = NULL;
char * key = NULL;
SortedMap * values = map();
enum map_state s = MKEY;
while ((c = getc(stream)) != EOF) {
switch (s) {
case MKEY:
switch (c) {
case ' ': case '\n': case '\t': break;
case '}':
json = malloc(sizeof(Json));
json->type = MAP;
json->value.map = values;
return json;
case '"':
json = parse_string(stream);
key = json->value.string;
free(json);
json = NULL;
s = MCOLON;
}
break;
case MCOLON:
switch (c) {
case ' ': case '\n': case '\t': break;
case ':':
s = MVALUE;
}
break;
case MVALUE:
switch (c) {
case ' ': case '\n': case '\t': break;
default:
ungetc(c, stream);
json = json_parse(stream);
values = put_map(values, key, (void *) json);
json = NULL;
s = MCOMMA;
}
break;
case MCOMMA:
switch (c) {
case ' ': case '\n': case '\t': break;
case ',':
s = MKEY;
break;
case '}':
json = malloc(sizeof(Json));
json->type = MAP;
json->value.map = values;
return json;
}
break;
}
}
fold_map(values, NULL, free_mappair);
free_map(values);
return NULL;
}
Json * json_parse(FILE *stream) { Json * json_parse(FILE *stream) {
char c; char c;
Json * json = NULL;
while ((c = getc(stream)) != EOF) { while ((c = getc(stream)) != EOF) {
switch (c) { switch (c) {
case '{': case '{':
@ -149,7 +244,11 @@ Json * json_parse(FILE *stream) {
fprintf(stderr, "encountered char: '%c'", c); fprintf(stderr, "encountered char: '%c'", c);
} }
} }
return json; return NULL;
}
void print_string(FILE *stream, char *string) {
fprintf(stream, "\"%s\"", string);
} }
struct printacc { struct printacc {
@ -159,7 +258,12 @@ struct printacc {
void * json_print_map(void * voidacc, char *key, void *value) { void * json_print_map(void * voidacc, char *key, void *value) {
struct printacc *acc = (struct printacc *) voidacc; struct printacc *acc = (struct printacc *) voidacc;
if (acc->index++ > 0) {
fprintf(acc->stream, ", ");
}
print_string(acc->stream, key);
fprintf(acc->stream, ": ");
json_print((Json *) value, acc->stream);
return acc; return acc;
} }
@ -174,7 +278,7 @@ void json_print(Json *this, FILE *stream) {
fprintf(stream, this->value.boolean == 0 ? "false" : "true"); fprintf(stream, this->value.boolean == 0 ? "false" : "true");
break; break;
case STRING: case STRING:
fprintf(stream, "\"%s\"", this->value.string); print_string(stream, this->value.string);
break; break;
case NUMBER: case NUMBER:
fprintf(stream, "%f", this->value.number); fprintf(stream, "%f", this->value.number);
@ -193,12 +297,23 @@ void json_print(Json *this, FILE *stream) {
case MAP: case MAP:
fprintf(stream, "{"); fprintf(stream, "{");
acc.stream = stream; acc.stream = stream;
fold_map((void *) &acc, this->value.map, json_print_map); fold_map(this->value.map, (void *) &acc, json_print_map);
fprintf(stream, "}"); fprintf(stream, "}");
break; break;
} }
} }
void * json_freelist(void *acc, int index, void *item) {
json_free((Json *) item);
return NULL;
}
void * json_freemap(void *acc, char *key, void *value) {
free(key);
json_free((Json *) value);
return NULL;
}
void json_free(Json *this) { void json_free(Json *this) {
switch (this->type) { switch (this->type) {
case NIL: case NIL:
@ -209,10 +324,12 @@ void json_free(Json *this) {
free(this->value.string); free(this->value.string);
break; break;
case LIST: case LIST:
/* TODO */ fold_list(this->value.list, NULL, json_freelist);
free_list(this->value.list);
break; break;
case MAP: case MAP:
/* TODO */ fold_map(this->value.map, NULL, json_freemap);
free_map(this->value.map);
break; break;
} }
free(this); free(this);

4
json.h
View File

@ -1,7 +1,11 @@
#ifndef JSON_HEADER #ifndef JSON_HEADER
#define JSON_HEADER #define JSON_HEADER
#include <stdio.h>
#include "sortedmap.h" #include "sortedmap.h"
#include "arraylist.h" #include "arraylist.h"
enum jsontype { NIL, BOOLEAN, STRING, NUMBER, LIST, MAP }; enum jsontype { NIL, BOOLEAN, STRING, NUMBER, LIST, MAP };
typedef struct json { typedef struct json {

9
jsontest/complex.json Normal file
View File

@ -0,0 +1,9 @@
{
"planets": [
{ "ship_count": 2, "x": -2.0, "y": 0.0, "owner": 1, "name": "your planet" },
{ "ship_count": 4, "x": 2.0, "y": 0.0, "owner": 2, "name": "enemy planet" },
{ "ship_count": 2, "x": 0.0, "y": 2.0, "owner": null, "name": "neutral planet" }
], "expeditions": [
{ "id": 169, "ship_count": 8, "origin": "your planet", "destination": "enemy planet", "owner": 1, "turns_remaining": 2 }
]
}

1
jsontest/float.json Normal file
View File

@ -0,0 +1 @@
1.231

1
jsontest/list.json Normal file
View File

@ -0,0 +1 @@
["asdf", 1, 2]

1
jsontest/null.json Normal file
View File

@ -0,0 +1 @@
null

1
jsontest/number.json Normal file
View File

@ -0,0 +1 @@
2

View File

@ -0,0 +1 @@
"asdf"

View File

@ -3,11 +3,18 @@ CFLAGS += -g -Wall -Werror -pedantic -ansi
all: planarbot inputfile all: planarbot inputfile
valgrind ./planarbot < inputfile valgrind ./planarbot < inputfile
test: echojson
find jsontest -type f -exec valgrind ./echojson \{\} \;
planarbot: planarbot.o arraylist.o sortedmap.o json.o planarbot: planarbot.o arraylist.o sortedmap.o json.o
planarbot.o: arraylist.h planarbot.o: arraylist.h
arraylist.o: arraylist.h arraylist.o: arraylist.h
sortedmap.o: sortedmap.h sortedmap.o: sortedmap.h
json.o: json.h arraylist.h sortedmap.h json.o: json.h arraylist.h sortedmap.h
echojson: echojson.o json.o arraylist.o sortedmap.o
echojson.o: json.h
clean: clean:
rm -f *.o planarbot rm -f *.o planarbot
.PHONY: all clean

View File

@ -104,14 +104,16 @@ Gamestate *read_gamestate() {
} }
void free_gamestate(Gamestate *this) { void free_gamestate(Gamestate *this) {
fold_list(this->planets, NULL, free_listitem);
free_list(this->planets); free_list(this->planets);
fold_list(this->expeditions, NULL, free_listitem);
free_list(this->expeditions); free_list(this->expeditions);
free(this); free(this);
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
Json * json = json_parse(stdin); Json * json = json_parse(stdin);
Gamestate *gamestate; /*Gamestate *gamestate;
SortedMap *test; SortedMap *test;
gamestate = read_gamestate(); gamestate = read_gamestate();
@ -124,7 +126,11 @@ int main(int argc, char **argv) {
test = put_map(test, "awer", "qwer"); test = put_map(test, "awer", "qwer");
printf("%s\n", (char *) get_map(test, "awer")); printf("%s\n", (char *) get_map(test, "awer"));
print_map(test); print_map(test);
free_map(test); free_map(test); */
json_print(json, stdout);
json_free(json);
json = json_parse(stdin);
json_print(json, stdout); json_print(json, stdout);
json_free(json); json_free(json);
return 0; return 0;

View File

@ -98,7 +98,7 @@ void * fold_map(SortedMap *this, void * init, void * (*f)(void * acc, char *key,
case LEAF: case LEAF:
return f(init, this->key, this->content.value); return f(init, this->key, this->content.value);
case INTERN: case INTERN:
return fold_map(fold_map(init, this->content.children.l, f), this->content.children.r, f); return fold_map(this->content.children.r, fold_map(this->content.children.l, init, f), f);
default: default:
return NULL; return NULL;
} }
@ -118,6 +118,31 @@ void free_mapvalues(SortedMap *this) {
} }
} }
void free_mapkeys(SortedMap *this) {
switch (this->type) {
case EMPTY:
break;
case LEAF:
free(this->key);
break;
case INTERN:
free_mapkeys(this->content.children.l);
free_mapkeys(this->content.children.r);
break;
}
}
void * free_mappair(void *acc, char *key, void *value) {
free(key);
free(value);
return NULL;
}
void * free_mapitem(void *acc, char *key, void *value) {
free(value);
return NULL;
}
void free_map(SortedMap *this) { void free_map(SortedMap *this) {
switch (this->type) { switch (this->type) {
case EMPTY: case EMPTY:

View File

@ -19,6 +19,7 @@ void * get_map(SortedMap *this, char *key);
SortedMap * put_map(SortedMap *this, char *key, void *value); SortedMap * put_map(SortedMap *this, char *key, void *value);
void print_map(SortedMap *this); void print_map(SortedMap *this);
void * fold_map(SortedMap *this, void * init, void * (*f)(void * acc, char *key, void *value)); void * fold_map(SortedMap *this, void * init, void * (*f)(void * acc, char *key, void *value));
void free_mapvalues(SortedMap *this); void * free_mappair(void *acc, char *key, void *value);
void * free_mapitem(void *acc, char *key, void *value);
void free_map(SortedMap *this); void free_map(SortedMap *this);
#endif #endif