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() { +} | 
