add json parsing of lists and maps
This commit is contained in:
parent
7471093f67
commit
025c8125fa
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
*.o
|
*.o
|
||||||
planarbot
|
planarbot
|
||||||
|
echojson
|
||||||
|
14
arraylist.c
14
arraylist.c
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
12
echojson.c
Normal 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
135
json.c
@ -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
4
json.h
@ -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
9
jsontest/complex.json
Normal 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
1
jsontest/float.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
1.231
|
1
jsontest/list.json
Normal file
1
jsontest/list.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["asdf", 1, 2]
|
1
jsontest/null.json
Normal file
1
jsontest/null.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
null
|
1
jsontest/number.json
Normal file
1
jsontest/number.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
2
|
1
jsontest/simplestring.json
Normal file
1
jsontest/simplestring.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
"asdf"
|
7
makefile
7
makefile
@ -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
|
||||||
|
10
planarbot.c
10
planarbot.c
@ -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;
|
||||||
|
27
sortedmap.c
27
sortedmap.c
@ -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:
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user