From e5d44899cffd80653da9e0336af36230c4e992a0 Mon Sep 17 00:00:00 2001 From: Charlie Stanton Date: Sun, 9 Jan 2022 15:10:21 +0000 Subject: Add parsing numbers --- cudl.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- cudl.h | 1 + test.cudl | 5 +++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/cudl.c b/cudl.c index b596e92..b5022a7 100644 --- a/cudl.c +++ b/cudl.c @@ -5,6 +5,7 @@ #include "cudl.h" #define STRIP_WHITESPACE(text) while (isspace(*(text))) (text)++ + #define IS_KEY_CHAR(c) (\ 'a' <= (c) && (c) <= 'z' ||\ 'A' <= (c) && (c) <= 'Z' ||\ @@ -12,6 +13,10 @@ (c) == '_' || (c) == '-'\ ) +#define IS_DIGIT(c) (\ + '0' <= (c) && (c) <= '9'\ +) + int cudl_err = CUDL_OK; static char *fread_all(FILE *file) { @@ -43,18 +48,26 @@ void cudl_debug(struct cudl_value value) { else printf("%%false"); break; + case CUDL_TAG_NUMBER: + printf("%lf", value.data.number); + break; case CUDL_TAG_STRING: printf("\"%s\"", value.data.string); break;; case CUDL_TAG_ARRAY: printf("["); - for (i = 0; i < value.data.array.length; i++) + for (i = 0; i < value.data.array.length; i++) { + if (i != 0) + printf(" "); cudl_debug(value.data.array.values[i]); + } printf("]"); break; case CUDL_TAG_MAP: printf("{"); for (i = 0; i < value.data.map.length; i++) { + if (i != 0) + printf(" "); printf("\"%s\": ", value.data.map.fields[i].key); cudl_debug(value.data.map.fields[i].value); } @@ -106,11 +119,61 @@ static size_t parse_bool_or_null(char *input, struct cudl_value *value) { return 0; } +static size_t parse_number(char *input, struct cudl_value *value) { + double number; + size_t i, exponentStart; + int exponent, otherExponent; + int exponentUsed; + exponentUsed = 0; + number = 0; + i = input[0] == '-'; + for (;; i++) { + if (IS_DIGIT(input[i])) { + number = number * 10 + (input[i] - '0'); + exponent++; + continue; + } else if (input[i] == '.') { + exponent = 0; + exponentUsed = 1; + continue; + } + break; + } + if (input[0] == '-') + number = 0 - number; + if (!exponentUsed) + exponent = 0; + otherExponent = 0; + if (input[i] == 'e' && (IS_DIGIT(input[i+1]) || (input[i+1] == '-' && IS_DIGIT(input[i+2])))) { + i++; + exponentStart = i; + i += input[i] == '-'; + for (;; i++) { + if (IS_DIGIT(input[i])) + otherExponent = otherExponent * 10 + (input[i] - '0'); + else + break; + } + if (input[exponentStart] == '-') + otherExponent = 0 - otherExponent; + } + exponent = exponent - otherExponent; + for (; exponent > 0; exponent--) { + number /= 10; + } + for (; exponent < 0; exponent++) { + number *= 10; + } + value->tag = CUDL_TAG_NUMBER; + value->data.number = number; + return i; +} + /* Convert UCS character to utf-8 bytes. * Return number of bytes generated. * Sets cudl_error on error. * Shamelessly lifted from https://github.com/cktan/tomc99 */ -size_t cudl_ucs_to_utf8(int64_t ucs, char utf8[6]) { +static size_t cudl_ucs_to_utf8(int64_t ucs, char utf8[6]) { if ( 0xd800 <= ucs && ucs <= 0xdfff || 0xfffe <= ucs && ucs <= 0xffff || @@ -482,6 +545,8 @@ static size_t _parse_value(char *input, struct cudl_value *value) { value->tag = CUDL_TAG_STRING; return parse_quoted_string(++input, &value->data.string) + 1; } + if (IS_DIGIT(*input) || *input == '-') + return parse_number(input, value); cudl_err = CUDL_ERR_UNRECOGNISED_VALUE; return 0; } diff --git a/cudl.h b/cudl.h index 36d2365..6f78909 100644 --- a/cudl.h +++ b/cudl.h @@ -33,6 +33,7 @@ struct cudl_map_field { enum { CUDL_TAG_NULL, CUDL_TAG_BOOL, + CUDL_TAG_NUMBER, CUDL_TAG_ARRAY, CUDL_TAG_MAP, CUDL_TAG_STRING, diff --git a/test.cudl b/test.cudl index a9de397..b95e6be 100644 --- a/test.cudl +++ b/test.cudl @@ -4,6 +4,11 @@ [%null %null %false] ["hello\nfriend\t\tstuff\"" "world"] "\U0001f600" + 12 + 12.4 + 13.456 + 123.345e4 + 123456789e-8 { testing: "this is a test map" i_hope_it_works: {nesting: "nested maps!!!"} -- cgit v1.2.3