diff options
author | Charlie Stanton <charlie@shtanton.xyz> | 2021-10-03 18:57:27 +0100 |
---|---|---|
committer | Charlie Stanton <charlie@shtanton.xyz> | 2021-10-03 18:57:27 +0100 |
commit | 69852d9ae210080e999eb5bbb81481f527580a97 (patch) | |
tree | e1ecb61cfa9b81846d15a11dcaf95fef5e64f465 | |
parent | cc219d714960ed68d2a822cd98bb428c32b71e1f (diff) | |
download | cudl-69852d9ae210080e999eb5bbb81481f527580a97.tar |
Complete parser with arrays, bools and nulls. Create empty testing file
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | cudl.c | 167 | ||||
-rw-r--r-- | cudl.h | 49 | ||||
-rw-r--r-- | spec.txt | 2 | ||||
-rw-r--r-- | test.c | 2 |
5 files changed, 187 insertions, 37 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ebfaa61 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +CC=tcc +BIN=test + +test: test.o @@ -1,36 +1,11 @@ #include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include "cudl.h" -struct cudl_array_value { - struct cudl_value *values; - size_t length; -}; +#define STRIP_WHITESPACE(text) while (isspace(*text)) text++ -struct cudl_map_value { - struct cudl_map_field { - char *key; - struct cudl_value value; - } *fields; - size_t length; -}; - -struct cudl_value { - union { - char *string; - double number; - int boolean; - struct array_value array; - struct map_value map; - } data; - int tag; -}; - -#define CUDL_TAG_NULL 0 -#define CUDL_TAG_ARRAY 1 - -#define CUDL_OK 0 -#define CUDL_ERR_OUT_OF_MEMORY 1 -#define CUDL_ERR_MISSING_VALUE 2 -#define CUDL_ERR_READING 3 +int cudl_err = CUDL_OK; static char *fread_all(FILE *file) { size_t size; @@ -49,7 +24,28 @@ static char *fread_all(FILE *file) { return buffer; } -void cudl_debug(struct cudl_value *value) { +void cudl_debug(struct cudl_value value) { + int i; + switch (value.tag) { + case CUDL_TAG_NULL: + printf("%%null"); + break; + case CUDL_TAG_BOOL: + if (value.data.boolean) + printf("%%true"); + else + printf("%%false"); + break; + case CUDL_TAG_ARRAY: + printf("["); + for (i = 0; i < value.data.array.length; i++) + cudl_debug(value.data.array.values[i]); + printf("]"); + break; + default: + printf("UNKNOWN"); + break; + } } /* Free all children of the value, not the value itself */ @@ -68,16 +64,115 @@ void cudl_deinit_value(struct cudl_value value) { } } -int cudl_parse_from_file(FILE *file, struct cudl_value *value) { +/* Parse a value from input and store it in value. + * Return the number of bytes consumed. + * Input must end with a null byte */ +size_t parse_value(char *input, struct cudl_value *value); + +static size_t parse_bool_or_null(char *input, struct cudl_value *value) { + if (strncmp(input, "null", 4)) { + value->tag = CUDL_TAG_NULL; + return 4; + } + if (strncmp(input, "true", 4)) { + value->tag = CUDL_TAG_BOOL; + value->data.boolean = 1; + return 4; + } + if (strncmp(input, "false", 5)) { + value->tag = CUDL_TAG_BOOL; + value->data.boolean = 0; + return 5; + } + cudl_err = CUDL_ERR_EXPECTED_BOOL_OR_NULL; + return 0; +} + +static size_t parse_array(char *input, struct cudl_value *value) { + size_t length, capacity; + struct cudl_value *values, *newvalues; + int i; + char *original_input; + + original_input = input; + value->tag = CUDL_TAG_ARRAY; + length = 0; + capacity = 8; + if ((values = malloc(capacity * sizeof(struct cudl_value))) == NULL) { + cudl_err = CUDL_ERR_OUT_OF_MEMORY; + return 0; + } + + STRIP_WHITESPACE(input); + for (;;) { + if (*input == '\0') { + cudl_err = CUDL_ERR_UNMATCHED_BRACK; + for (i = 0; i < length; i++) + cudl_deinit_value(values[i]); + free(values); + return 0; + } else if (*input == ']') { + input++; + values = realloc(values, length * sizeof(struct cudl_value)); + value->data.array.length = length; + value->data.array.values = values; + return input - original_input; + } + if (length >= capacity) { + if ((newvalues = realloc(values, 2 * capacity * sizeof(struct cudl_value))) == NULL) { + cudl_err = CUDL_ERR_OUT_OF_MEMORY; + for (i = 0; i < length; i++) + cudl_deinit_value(values[i]); + free(values); + return 0; + } + capacity *= 2; + } + input += parse_value(input, values + length); + if (cudl_err) { + for (i = 0; i < length; i++) { + cudl_deinit_value(values[i]); + } + free(values); + return 0; + } + length++; + } +} + +static size_t _parse_value(char *input, struct cudl_value *value) { + if (*input == '%') + return parse_bool_or_null(++input, value) + 1; + if (*input == '[') + return parse_array(++input, value) + 1; + cudl_err = CUDL_ERR_UNRECOGNISED_VALUE; + return 0; +} + +static size_t parse_value(char *input, struct cudl_value *value) { + char *original_input; + original_input = input; + input += _parse_value(input, value); + STRIP_WHITESPACE(input); + return input - original_input; +} + +void cudl_parse_from_file(FILE *file, struct cudl_value *value) { char *input; if ((input = fread_all(file)) == NULL) { if (ferror(file)) - return CUDL_ERR_READING; + cudl_err = CUDL_ERR_READING; else - return CUDL_ERR_OUT_OF_MEMORY; + cudl_err = CUDL_ERR_OUT_OF_MEMORY; + return; } - return cudl_parse(input, value); + input += cudl_parse(input, value); + if (*input != '\0') + cudl_deinit_value(*value); + free(input); } -int cudl_parse(char *input, struct cudl_value *value) { +size_t cudl_parse(char *input, struct cudl_value *value) { + STRIP_WHITESPACE(input); + return parse_value(input, value); } @@ -0,0 +1,49 @@ +#ifndef cudl_h_INCLUDED +#define cudl_h_INCLUDED + +struct cudl_array_value { + struct cudl_value *values; + size_t length; +}; + +struct cudl_map_value { + struct cudl_map_field { + char *key; + struct cudl_value value; + } *fields; + size_t length; +}; + +struct cudl_value { + union { + char *string; + double number; + int boolean; + struct array_value array; + struct map_value map; + } data; + int tag; +}; + +enum { + CUDL_TAG_NULL; + CUDL_TAG_BOOL; + CUDL_TAG_ARRAY; +} + +enum { + CUDL_OK = 0; + CUDL_ERR_OUT_OF_MEMORY; + CUDL_ERR_EXPECTED_VALUE; + CUDL_ERR_READING; + CUDL_ERR_EXPECTED_BOOL_OR_NULL; +}; + +extern int cudl_err; + +void cudl_debug(struct cudl_value value); +void cudl_deinit_value(struct cudl_value value); +void cudl_parse_from_file(FILE *file, struct cudl_value *value); +size_t cudl_parse(char *input, struct cudl_value *value); + +#endif // cudl_h_INCLUDED @@ -28,7 +28,7 @@ A map can be preceeded by nothing and succeeded by a ], which is not consumed. A sequence of values, no delimeter. -An array is preceeded by a [ and succeeded by a ] +An array is preceeded by a [ (optionally followed by whitespace) and succeeded by a ] ## String @@ -0,0 +1,2 @@ +int main() { +} |