diff options
Diffstat (limited to 'src/mds-kbdc')
38 files changed, 6259 insertions, 6318 deletions
diff --git a/src/mds-kbdc/builtin-functions.c b/src/mds-kbdc/builtin-functions.c index e0594ab..72593cd 100644 --- a/src/mds-kbdc/builtin-functions.c +++ b/src/mds-kbdc/builtin-functions.c @@ -29,35 +29,35 @@ /** * Define useful data for built-in function with 2 parameters */ -#define define_2 \ - const char32_t* restrict a = *args++; \ - const char32_t* restrict b = *args++; \ - size_t an = string_length(a); \ - size_t bn = string_length(b); \ - size_t i, n = an > bn ? an : bn; \ - char32_t* restrict rc; \ - fail_if (xmalloc(rc, n + 1, char32_t)); \ - rc[n] = -1 +#define define_2\ + const char32_t *restrict a = *args++;\ + const char32_t *restrict b = *args++;\ + size_t an = string_length(a);\ + size_t bn = string_length(b);\ + size_t i, n = an > bn ? an : bn;\ + char32_t *restrict rc;\ + fail_if (xmalloc(rc, n + 1, char32_t));\ + rc[n] = -1 /** * Define useful data for built-in function with 1 parameter */ -#define define_1 \ - const char32_t* restrict a = *args++; \ - size_t i, n = string_length(a); \ - char32_t* restrict rc; \ - fail_if (xmalloc(rc, n + 1, char32_t)); \ - rc[n] = -1 +#define define_1\ + const char32_t* restrict a = *args++;\ + size_t i, n = string_length(a);\ + char32_t *restrict rc;\ + fail_if (xmalloc(rc, n + 1, char32_t));\ + rc[n] = -1 /** * Return a value, or if there was a failure somewhere, return `NULL` * * @param v:void* The value to return on success */ -#define return(v) \ - return v; \ - fail: \ - return NULL; +#define return(v)\ + return v;\ +fail:\ + return NULL; /** @@ -66,12 +66,13 @@ * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_add_2(const char32_t** restrict args) +static char32_t * +builtin_function_add_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] + b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] + b[i % bn]; + return(rc); } @@ -81,12 +82,13 @@ static char32_t* builtin_function_add_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_sub_2(const char32_t** restrict args) +static char32_t * +builtin_function_sub_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] - b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] - b[i % bn]; + return(rc); } @@ -96,12 +98,13 @@ static char32_t* builtin_function_sub_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_mul_2(const char32_t** restrict args) +static char32_t * +builtin_function_mul_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] * b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] * b[i % bn]; + return(rc); } @@ -111,12 +114,13 @@ static char32_t* builtin_function_mul_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_div_2(const char32_t** restrict args) +static char32_t * +builtin_function_div_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] / b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] / b[i % bn]; + return(rc); } @@ -126,12 +130,13 @@ static char32_t* builtin_function_div_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_mod_2(const char32_t** restrict args) +static char32_t * +builtin_function_mod_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] % b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] % b[i % bn]; + return(rc); } @@ -141,12 +146,13 @@ static char32_t* builtin_function_mod_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_rsh_2(const char32_t** restrict args) +static char32_t * +builtin_function_rsh_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] >> b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] >> b[i % bn]; + return(rc); } @@ -156,12 +162,13 @@ static char32_t* builtin_function_rsh_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_lsh_2(const char32_t** restrict args) +static char32_t * +builtin_function_lsh_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] << b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] << b[i % bn]; + return(rc); } @@ -171,12 +178,13 @@ static char32_t* builtin_function_lsh_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_or_2(const char32_t** restrict args) +static char32_t * +builtin_function_or_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] | b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] | b[i % bn]; + return(rc); } @@ -186,12 +194,13 @@ static char32_t* builtin_function_or_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_and_2(const char32_t** restrict args) +static char32_t * +builtin_function_and_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] & b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] & b[i % bn]; + return(rc); } @@ -201,12 +210,13 @@ static char32_t* builtin_function_and_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_xor_2(const char32_t** restrict args) +static char32_t * +builtin_function_xor_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] ^ b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] ^ b[i % bn]; + return(rc); } @@ -216,12 +226,13 @@ static char32_t* builtin_function_xor_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_not_1(const char32_t** restrict args) +static char32_t * +builtin_function_not_1(const char32_t **restrict args) { - define_1; - for (i = 0; i < n; i++) - rc[i] = !a[i]; - return(rc); + define_1; + for (i = 0; i < n; i++) + rc[i] = !a[i]; + return(rc); } @@ -231,12 +242,13 @@ static char32_t* builtin_function_not_1(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_equals_2(const char32_t** restrict args) +static char32_t * +builtin_function_equals_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] == b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] == b[i % bn]; + return(rc); } @@ -246,12 +258,13 @@ static char32_t* builtin_function_equals_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_greater_2(const char32_t** restrict args) +static char32_t * +builtin_function_greater_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] > b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] > b[i % bn]; + return(rc); } @@ -261,12 +274,13 @@ static char32_t* builtin_function_greater_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_less_2(const char32_t** restrict args) +static char32_t * +builtin_function_less_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] < b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] < b[i % bn]; + return(rc); } @@ -276,17 +290,18 @@ static char32_t* builtin_function_less_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_get_2(const char32_t** restrict args) +static char32_t * +builtin_function_get_2(const char32_t **restrict args) { - const char32_t* restrict a = *args++; - const char32_t* restrict b = *args++; - char32_t* restrict rc; - size_t n = (size_t)*b; - mds_kbdc_tree_t* value = variables_get((size_t)*a)->array.elements; - while (n--) - value = value->next; - fail_if (rc = string_dup(value->compiled_string.string), rc == NULL); - return(rc); + const char32_t *restrict a = *args++; + const char32_t *restrict b = *args++; + char32_t *restrict rc; + size_t n = (size_t)*b; + mds_kbdc_tree_t *value = variables_get((size_t)*a)->array.elements; + while (n--) + value = value->next; + fail_if (rc = string_dup(value->compiled_string.string), rc == NULL); + return(rc); } @@ -296,21 +311,22 @@ static char32_t* builtin_function_get_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_set_3(const char32_t** restrict args) +static char32_t * +builtin_function_set_3(const char32_t **restrict args) { - const char32_t* restrict a = *args++; - const char32_t* restrict b = *args++; - const char32_t* restrict c = *args++; - char32_t* restrict rc; - size_t n = (size_t)*b; - mds_kbdc_tree_t* value = variables_get((size_t)*a)->array.elements; - while (n--) - value = value->next; - free(value->compiled_string.string); - value->compiled_string.string = string_dup(c); - fail_if (value->compiled_string.string == NULL); - fail_if (rc = string_dup(c), rc == NULL); - return(rc); + const char32_t *restrict a = *args++; + const char32_t *restrict b = *args++; + const char32_t *restrict c = *args++; + char32_t *restrict rc; + size_t n = (size_t)*b; + mds_kbdc_tree_t *value = variables_get((size_t)*a)->array.elements; + while (n--) + value = value->next; + free(value->compiled_string.string); + value->compiled_string.string = string_dup(c); + fail_if (!value->compiled_string.string); + fail_if (!(rc = string_dup(c))); + return(rc); } @@ -326,25 +342,26 @@ static char32_t* builtin_function_set_3(const char32_t** restrict args) * @param arg_count The number of arguments to pass to the function * @return Whether the described function is a builtin function */ -int builtin_function_defined(const char* restrict name, size_t arg_count) +int +builtin_function_defined(const char *restrict name, size_t arg_count) { - size_t i; - static const char* const BUILTIN_FUNCTIONS_2[] = - { - "add", "sub", "mul", "div", "mod", "rsh", "lsh", "or", - "and", "xor", "equals", "greater", "less", "get", NULL - }; - - if (arg_count == 3) - return !strcmp(name, "set"); - else if (arg_count == 1) - return !strcmp(name, "not"); - else if (arg_count == 2) - for (i = 0; BUILTIN_FUNCTIONS_2[i]; i++) - if (!strcmp(name, BUILTIN_FUNCTIONS_2[i])) - return 1; - - return 0; + size_t i; + static const char* const BUILTIN_FUNCTIONS_2[] = { + "add", "sub", "mul", "div", "mod", "rsh", "lsh", "or", + "and", "xor", "equals", "greater", "less", "get", NULL + }; + + if (arg_count == 1) { + return !strcmp(name, "not"); + } else if (arg_count == 2) { + for (i = 0; BUILTIN_FUNCTIONS_2[i]; i++) + if (!strcmp(name, BUILTIN_FUNCTIONS_2[i])) + return 1; + } else if (arg_count == 3) { + return !strcmp(name, "set"); + } + + return 0; } @@ -362,35 +379,35 @@ int builtin_function_defined(const char* restrict name, size_t arg_count) * @param args The arguments to pass * @return The return value of the function, `NULL` on error */ -char32_t* builtin_function_invoke(const char* restrict name, size_t arg_count, const char32_t** restrict args) +char32_t * +builtin_function_invoke(const char *restrict name, size_t arg_count, const char32_t **restrict args) { -#define t(f) do { fail_if (rc = builtin_function_##f(args), rc == NULL); return rc; } while (0) - char32_t* rc; - - if ((arg_count == 3) && !strcmp(name, "set")) t (set_3); - if ((arg_count == 1) && !strcmp(name, "not")) t (not_1); - - if (arg_count != 2) - abort(); - - if (!strcmp(name, "add")) t (add_2); - if (!strcmp(name, "sub")) t (sub_2); - if (!strcmp(name, "mul")) t (mul_2); - if (!strcmp(name, "div")) t (div_2); - if (!strcmp(name, "mod")) t (mod_2); - if (!strcmp(name, "rsh")) t (rsh_2); - if (!strcmp(name, "lsh")) t (lsh_2); - if (!strcmp(name, "or")) t (or_2); - if (!strcmp(name, "and")) t (and_2); - if (!strcmp(name, "xor")) t (xor_2); - if (!strcmp(name, "equals")) t (equals_2); - if (!strcmp(name, "greater")) t (greater_2); - if (!strcmp(name, "less")) t (less_2); - if (!strcmp(name, "get")) t (get_2); - - abort(); - fail: - return NULL; +#define t(f) do { fail_if (rc = builtin_function_##f(args), rc == NULL); return rc; } while (0) + char32_t *rc; + + if (arg_count == 3 && !strcmp(name, "set")) t (set_3); + if (arg_count == 1 && !strcmp(name, "not")) t (not_1); + + if (arg_count != 2) + abort(); + + if (!strcmp(name, "add")) t (add_2); + if (!strcmp(name, "sub")) t (sub_2); + if (!strcmp(name, "mul")) t (mul_2); + if (!strcmp(name, "div")) t (div_2); + if (!strcmp(name, "mod")) t (mod_2); + if (!strcmp(name, "rsh")) t (rsh_2); + if (!strcmp(name, "lsh")) t (lsh_2); + if (!strcmp(name, "or")) t (or_2); + if (!strcmp(name, "and")) t (and_2); + if (!strcmp(name, "xor")) t (xor_2); + if (!strcmp(name, "equals")) t (equals_2); + if (!strcmp(name, "greater")) t (greater_2); + if (!strcmp(name, "less")) t (less_2); + if (!strcmp(name, "get")) t (get_2); + + abort(); +fail: + return NULL; #undef t } - diff --git a/src/mds-kbdc/builtin-functions.h b/src/mds-kbdc/builtin-functions.h index fe94205..8d2cc2d 100644 --- a/src/mds-kbdc/builtin-functions.h +++ b/src/mds-kbdc/builtin-functions.h @@ -33,7 +33,8 @@ * @param arg_count The number of arguments to pass to the function * @return Whether the described function is a builtin function */ -int builtin_function_defined(const char* restrict name, size_t arg_count) __attribute__((pure)); +__attribute__((pure)) +int builtin_function_defined(const char *restrict name, size_t arg_count); /** * Invoke a builtin function @@ -49,9 +50,8 @@ int builtin_function_defined(const char* restrict name, size_t arg_count) __attr * @param args The arguments to pass * @return The return value of the function, `NULL` on error */ -char32_t* builtin_function_invoke(const char* restrict name, size_t arg_count, const char32_t** restrict args); +char32_t *builtin_function_invoke(const char *restrict name, size_t arg_count, const char32_t **restrict args); #endif - diff --git a/src/mds-kbdc/call-stack.c b/src/mds-kbdc/call-stack.c index 92c83a7..c864e7c 100644 --- a/src/mds-kbdc/call-stack.c +++ b/src/mds-kbdc/call-stack.c @@ -24,31 +24,29 @@ /** * An entry in the call-stack */ -typedef struct mds_kbdc_call -{ - /** - * The tree node where the call was made - */ - const mds_kbdc_tree_t* tree; - - /** - * The position of the line of the tree node - * where the call begins - */ - size_t start; - - /** - * The position of the line of the tree node - * where the call end - */ - size_t end; - - /** - * A snapshot of the include-stack as it - * looked when the call was being made - */ - mds_kbdc_include_stack_t* include_stack; - +typedef struct mds_kbdc_call { + /** + * The tree node where the call was made + */ + const mds_kbdc_tree_t *tree; + + /** + * The position of the line of the tree node + * where the call begins + */ + size_t start; + + /** + * The position of the line of the tree node + * where the call end + */ + size_t end; + + /** + * A snapshot of the include-stack as it + * looked when the call was being made + */ + mds_kbdc_include_stack_t *include_stack; } mds_kbdc_call_t; @@ -56,27 +54,27 @@ typedef struct mds_kbdc_call /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The `result` parameter of root procedure that requires the include-stack */ -static mds_kbdc_parsed_t* result; +static mds_kbdc_parsed_t *result; /** * The original value of `result->pathname` */ -static char* original_pathname; +static char *original_pathname; /** * The original value of `result->source_code` */ -static mds_kbdc_source_code_t* original_source_code; +static mds_kbdc_source_code_t *original_source_code; /** * Stack of visited function- and macro-calls */ -static mds_kbdc_call_t* restrict calls = NULL; +static mds_kbdc_call_t *restrict calls = NULL; /** * The number elements allocated for `calls` @@ -95,57 +93,59 @@ static size_t calls_ptr = 0; * * @return Zero on success, -1 on error */ -int mds_kbdc_call_stack_dump(void) +int +mds_kbdc_call_stack_dump(void) { - char* old_pathname = result->pathname; - mds_kbdc_source_code_t* old_source_code = result->source_code; - size_t ptr = calls_ptr, iptr; - mds_kbdc_call_t* restrict call; - mds_kbdc_include_stack_t* restrict includes; - - while (ptr--) - { - call = calls + ptr; - includes = call->include_stack; - iptr = includes->ptr; - result->pathname = iptr ? includes->stack[iptr - 1]->filename : original_pathname; - result->source_code = iptr ? includes->stack[iptr - 1]->source_code : original_source_code; - NEW_ERROR_(result, NOTE, 1, call->tree->loc_line, call->start, call->end, 1, "called from here"); - DUMP_INCLUDE_STACK(iptr); - } - - result->pathname = old_pathname; - result->source_code = old_source_code; - return 0; - fail: - result->pathname = old_pathname; - result->source_code = old_source_code; - return -1; + char *old_pathname = result->pathname; + mds_kbdc_source_code_t *old_source_code = result->source_code; + size_t ptr = calls_ptr, iptr; + mds_kbdc_call_t *restrict call; + mds_kbdc_include_stack_t *restrict includes; + + while (ptr--) { + call = calls + ptr; + includes = call->include_stack; + iptr = includes->ptr; + result->pathname = iptr ? includes->stack[iptr - 1]->filename : original_pathname; + result->source_code = iptr ? includes->stack[iptr - 1]->source_code : original_source_code; + NEW_ERROR_(result, NOTE, 1, call->tree->loc_line, call->start, call->end, 1, "called from here"); + DUMP_INCLUDE_STACK(iptr); + } + + result->pathname = old_pathname; + result->source_code = old_source_code; + return 0; +fail: + result->pathname = old_pathname; + result->source_code = old_source_code; + return -1; } /** * Prepare for usage of call-stacks * -xo * @param result_ The `result` parameter of root procedure that requires the call-stack + * @param result_ The `result` parameter of root procedure that requires the call-stack */ -void mds_kbdc_call_stack_begin(mds_kbdc_parsed_t* restrict result_) +void +mds_kbdc_call_stack_begin(mds_kbdc_parsed_t *restrict result_) { - result = result_; - original_pathname = result_->pathname; - original_source_code = result_->source_code; + result = result_; + original_pathname = result_->pathname; + original_source_code = result_->source_code; } /** * Cleanup after usage of call-stacks */ -void mds_kbdc_call_stack_end(void) +void +mds_kbdc_call_stack_end(void) { - result->pathname = original_pathname; - result->source_code = original_source_code; - free(calls), calls = NULL; - calls_size = calls_ptr = 0; + result->pathname = original_pathname; + result->source_code = original_source_code; + free(calls), calls = NULL; + calls_size = calls_ptr = 0; } @@ -157,27 +157,27 @@ void mds_kbdc_call_stack_end(void) * @param end The position of the line of the tree node where the call end * @return Zero on success, -1 on error */ -int mds_kbdc_call_stack_push(const mds_kbdc_tree_t* restrict tree, size_t start, size_t end) +int +mds_kbdc_call_stack_push(const mds_kbdc_tree_t *restrict tree, size_t start, size_t end) { - mds_kbdc_call_t* tmp; - mds_kbdc_call_t* call; - - if (calls_ptr == calls_size) - { - fail_if (yrealloc(tmp, calls, calls_size + 4, mds_kbdc_call_t)); - calls_size += 4; - } - - call = calls + calls_ptr++; - call->tree = tree; - call->start = start; - call->end = end; - call->include_stack = mds_kbdc_include_stack_save(); - fail_if (call->include_stack == NULL); - - return 0; - fail: - return -1; + mds_kbdc_call_t *tmp; + mds_kbdc_call_t *call; + + if (calls_ptr == calls_size) { + fail_if (yrealloc(tmp, calls, calls_size + 4, mds_kbdc_call_t)); + calls_size += 4; + } + + call = calls + calls_ptr++; + call->tree = tree; + call->start = start; + call->end = end; + call->include_stack = mds_kbdc_include_stack_save(); + fail_if (!call->include_stack); + + return 0; +fail: + return -1; } @@ -186,10 +186,10 @@ int mds_kbdc_call_stack_push(const mds_kbdc_tree_t* restrict tree, size_t start, * * This function is guaranteed not to modify `errno` */ -void mds_kbdc_call_stack_pop(void) +void +mds_kbdc_call_stack_pop(void) { - int saved_errno = errno; - mds_kbdc_include_stack_free(calls[--calls_ptr].include_stack); - errno = saved_errno; + int saved_errno = errno; + mds_kbdc_include_stack_free(calls[--calls_ptr].include_stack); + errno = saved_errno; } - diff --git a/src/mds-kbdc/call-stack.h b/src/mds-kbdc/call-stack.h index db7a18a..94b6dc8 100644 --- a/src/mds-kbdc/call-stack.h +++ b/src/mds-kbdc/call-stack.h @@ -27,8 +27,8 @@ /** * Add “called from here”-notes */ -#define DUMP_CALL_STACK \ - fail_if (mds_kbdc_call_stack_dump()) +#define DUMP_CALL_STACK\ + fail_if (mds_kbdc_call_stack_dump()) @@ -44,7 +44,7 @@ int mds_kbdc_call_stack_dump(void); * * @param result The `result` parameter of root procedure that requires the call-stack */ -void mds_kbdc_call_stack_begin(mds_kbdc_parsed_t* restrict result); +void mds_kbdc_call_stack_begin(mds_kbdc_parsed_t *restrict result); /** * Cleanup after usage of call-stacks @@ -59,7 +59,7 @@ void mds_kbdc_call_stack_end(void); * @param end The position of the line of the tree node where the call end * @return Zero on success, -1 on error */ -int mds_kbdc_call_stack_push(const mds_kbdc_tree_t* restrict tree, size_t start, size_t end); +int mds_kbdc_call_stack_push(const mds_kbdc_tree_t *restrict tree, size_t start, size_t end); /** * Undo the lasted not-undone call to `mds_kbdc_call_stack_push` @@ -71,4 +71,3 @@ void mds_kbdc_call_stack_pop(void); #endif - diff --git a/src/mds-kbdc/callables.c b/src/mds-kbdc/callables.c index 24b1e8a..07b08b0 100644 --- a/src/mds-kbdc/callables.c +++ b/src/mds-kbdc/callables.c @@ -25,29 +25,29 @@ /** * Map, by index, from argument count, to list of callable's names */ -static char*** restrict names = NULL; +static char ***restrict names = NULL; /** * If `callable_list[callabes[i][j]]` and `callable_include_stack_list[callabes[i][j]]` * describe the callable named by `named[i][j]` with either `i` parameters, or the * number of parameters specified by the suffix in `named[i][j]` */ -static size_t** restrict callables = NULL; +static size_t **restrict callables = NULL; /** * Map the the number of elements in the, by index, corresponding element in `names` */ -static size_t* restrict bucket_sizes = NULL; +static size_t *restrict bucket_sizes = NULL; /** * List of callables */ -static mds_kbdc_tree_t** restrict callable_list = NULL; +static mds_kbdc_tree_t **restrict callable_list = NULL; /** * List of callables' include-stacks */ -static mds_kbdc_include_stack_t** restrict callable_include_stack_list = NULL; +static mds_kbdc_include_stack_t **restrict callable_include_stack_list = NULL; /** * The number of buckets in `names` and `bucket_sizes` @@ -64,26 +64,26 @@ static size_t list_ptr = 0; /** * Destroy the callable storage */ -void callables_terminate(void) +void +callables_terminate(void) { - size_t i, j, n; - char** bucket; - for (i = 0; i < buckets; i++) - { - bucket = names[i]; - for (j = 0, n = bucket_sizes[i]; j < n; j++) - free(bucket[j]); - free(bucket); - free(callables[i]); - } - for (i = 0; i < list_ptr; i++) - mds_kbdc_include_stack_free(callable_include_stack_list[i]); - free(callables), callables = NULL; - free(names), names = NULL; - free(bucket_sizes), bucket_sizes = NULL; - free(callable_list), callable_list = NULL; - free(callable_include_stack_list), callable_include_stack_list = NULL; - buckets = list_ptr = 0; + size_t i, j, n; + char **bucket; + for (i = 0; i < buckets; i++) { + bucket = names[i]; + for (j = 0, n = bucket_sizes[i]; j < n; j++) + free(bucket[j]); + free(bucket); + free(callables[i]); + } + for (i = 0; i < list_ptr; i++) + mds_kbdc_include_stack_free(callable_include_stack_list[i]); + free(callables), callables = NULL; + free(names), names = NULL; + free(bucket_sizes), bucket_sizes = NULL; + free(callable_list), callable_list = NULL; + free(callable_include_stack_list), callable_include_stack_list = NULL; + buckets = list_ptr = 0; } @@ -97,57 +97,57 @@ void callables_terminate(void) * @param callable_include_stack The include-stack for the callable * @return Zero on success, -1 on error */ -int callables_set(const char* restrict name, size_t arg_count, mds_kbdc_tree_t* restrict callable, - mds_kbdc_include_stack_t* restrict callable_include_stack) +int +callables_set(const char *restrict name, size_t arg_count, mds_kbdc_tree_t *restrict callable, + mds_kbdc_include_stack_t *restrict callable_include_stack) { -#define _yrealloc(var, elements, type) (yrealloc(tmp_##var, var, elements, type)) - - char* dupname = NULL; - char*** tmp_names = NULL; - size_t** tmp_callables = NULL; - size_t* tmp_bucket_sizes = NULL; - char** old_names = NULL; - size_t* old_callables = NULL; - mds_kbdc_tree_t** tmp_callable_list = NULL; - mds_kbdc_include_stack_t** tmp_callable_include_stack_list = NULL; - int saved_errno; - - fail_if (xstrdup(dupname, name)); - - if (arg_count >= buckets) - { - fail_if (_yrealloc(names, arg_count + 1, char**)); - fail_if (_yrealloc(callables, arg_count + 1, size_t*)); - fail_if (_yrealloc(bucket_sizes, arg_count + 1, size_t)); - memset(names + buckets, 0, (arg_count + 1 - buckets) * sizeof(char**)); - memset(callables + buckets, 0, (arg_count + 1 - buckets) * sizeof(size_t*)); - memset(bucket_sizes + buckets, 0, (arg_count + 1 - buckets) * sizeof(size_t)); - buckets = arg_count + 1; - } - - fail_if (xxrealloc(old_names, names[arg_count], bucket_sizes[arg_count] + 1, char*)); - fail_if (xxrealloc(old_callables, callables[arg_count], bucket_sizes[arg_count] + 1, size_t)); - - names[arg_count][bucket_sizes[arg_count]] = dupname, dupname = NULL; - callables[arg_count][bucket_sizes[arg_count]] = list_ptr; - bucket_sizes[arg_count]++; - - fail_if (_yrealloc(callable_list, list_ptr + 1, mds_kbdc_tree_t*)); - fail_if (_yrealloc(callable_include_stack_list, list_ptr + 1, mds_kbdc_include_stack_t*)); - - callable_list[list_ptr] = callable; - callable_include_stack_list[list_ptr] = callable_include_stack; - list_ptr++; - - return 0; - fail: - saved_errno = errno; - free(dupname); - if (old_names) - names[arg_count] = old_names; - if (old_callables) - callables[arg_count] = old_callables; - return errno = saved_errno, -1; +#define _yrealloc(var, elements, type) (yrealloc(tmp_##var, var, elements, type)) + + char *dupname = NULL; + char ***tmp_names = NULL; + size_t **tmp_callables = NULL; + size_t *tmp_bucket_sizes = NULL; + char **old_names = NULL; + size_t *old_callables = NULL; + mds_kbdc_tree_t **tmp_callable_list = NULL; + mds_kbdc_include_stack_t **tmp_callable_include_stack_list = NULL; + int saved_errno; + + fail_if (xstrdup(dupname, name)); + + if (arg_count >= buckets) { + fail_if (_yrealloc(names, arg_count + 1, char**)); + fail_if (_yrealloc(callables, arg_count + 1, size_t*)); + fail_if (_yrealloc(bucket_sizes, arg_count + 1, size_t)); + memset(names + buckets, 0, (arg_count + 1 - buckets) * sizeof(char**)); + memset(callables + buckets, 0, (arg_count + 1 - buckets) * sizeof(size_t*)); + memset(bucket_sizes + buckets, 0, (arg_count + 1 - buckets) * sizeof(size_t)); + buckets = arg_count + 1; + } + + fail_if (xxrealloc(old_names, names[arg_count], bucket_sizes[arg_count] + 1, char*)); + fail_if (xxrealloc(old_callables, callables[arg_count], bucket_sizes[arg_count] + 1, size_t)); + + names[arg_count][bucket_sizes[arg_count]] = dupname, dupname = NULL; + callables[arg_count][bucket_sizes[arg_count]] = list_ptr; + bucket_sizes[arg_count]++; + + fail_if (_yrealloc(callable_list, list_ptr + 1, mds_kbdc_tree_t*)); + fail_if (_yrealloc(callable_include_stack_list, list_ptr + 1, mds_kbdc_include_stack_t*)); + + callable_list[list_ptr] = callable; + callable_include_stack_list[list_ptr] = callable_include_stack; + list_ptr++; + + return 0; +fail: + saved_errno = errno; + free(dupname); + if (old_names) + names[arg_count] = old_names; + if (old_callables) + callables[arg_count] = old_callables; + return errno = saved_errno, -1; #undef _yrealloc } @@ -161,27 +161,26 @@ int callables_set(const char* restrict name, size_t arg_count, mds_kbdc_tree_t* * @param callable Output parameter for the callable, `NULL` if not found * @param callable_include_stack Output parameter for the include-stack for the callable */ -void callables_get(const char* restrict name, size_t arg_count, mds_kbdc_tree_t** restrict callable, - mds_kbdc_include_stack_t** restrict callable_include_stack) +void +callables_get(const char *restrict name, size_t arg_count, mds_kbdc_tree_t **restrict callable, + mds_kbdc_include_stack_t **restrict callable_include_stack) { - char** restrict names_; - size_t i, n; - - *callable = NULL; - *callable_include_stack = NULL; - - if (arg_count >= buckets) - return; - - names_ = names[arg_count]; - for (i = 0, n = bucket_sizes[arg_count]; i < n; i++) - { - if (strcmp(names_[i], name)) - continue; - i = callables[arg_count][i]; - *callable = callable_list[i]; - *callable_include_stack = callable_include_stack_list[i]; - return; - } + char **restrict names_; + size_t i, n; + + *callable = NULL; + *callable_include_stack = NULL; + + if (arg_count >= buckets) + return; + + names_ = names[arg_count]; + for (i = 0, n = bucket_sizes[arg_count]; i < n; i++) { + if (strcmp(names_[i], name)) + continue; + i = callables[arg_count][i]; + *callable = callable_list[i]; + *callable_include_stack = callable_include_stack_list[i]; + return; + } } - diff --git a/src/mds-kbdc/callables.h b/src/mds-kbdc/callables.h index bb453f1..9e0d3b3 100644 --- a/src/mds-kbdc/callables.h +++ b/src/mds-kbdc/callables.h @@ -38,8 +38,8 @@ void callables_terminate(void); * @param callable_include_stack The include-stack for the callable * @return Zero on success, -1 on error */ -int callables_set(const char* restrict name, size_t arg_count, mds_kbdc_tree_t* restrict callable, - mds_kbdc_include_stack_t* restrict callable_include_stack); +int callables_set(const char *restrict name, size_t arg_count, mds_kbdc_tree_t *restrict callable, + mds_kbdc_include_stack_t *restrict callable_include_stack); /** * Get a stored callable @@ -50,9 +50,8 @@ int callables_set(const char* restrict name, size_t arg_count, mds_kbdc_tree_t* * @param callable Output parameter for the callable * @param callable_include_stack Output parameter for the include-stack for the callable */ -void callables_get(const char* restrict name, size_t arg_count, mds_kbdc_tree_t** restrict callable, - mds_kbdc_include_stack_t** restrict callable_include_stack); +void callables_get(const char *restrict name, size_t arg_count, mds_kbdc_tree_t **restrict callable, + mds_kbdc_include_stack_t **restrict callable_include_stack); #endif - diff --git a/src/mds-kbdc/compile-layout.c b/src/mds-kbdc/compile-layout.c index 199e870..8eb832b 100644 --- a/src/mds-kbdc/compile-layout.c +++ b/src/mds-kbdc/compile-layout.c @@ -34,12 +34,12 @@ /** * This process's value for `mds_kbdc_tree_t.processed` */ -#define PROCESS_LEVEL 6 +#define PROCESS_LEVEL 6 /** * Tree type constant shortener */ -#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE +#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE /** * Add an error with “included from here”-notes and, unless @@ -50,36 +50,34 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(NODE, SEVERITY, ...) \ - do \ - { \ - NEW_ERROR_WITH_INCLUDES(NODE, includes_ptr, SEVERITY, __VA_ARGS__); \ - if (strcmp(#SEVERITY, "NOTE")) \ - DUMP_CALL_STACK; \ - } \ - while (0) +#define NEW_ERROR(NODE, SEVERITY, ...)\ + do {\ + NEW_ERROR_WITH_INCLUDES(NODE, includes_ptr, SEVERITY, __VA_ARGS__);\ + if (strcmp(#SEVERITY, "NOTE"))\ + DUMP_CALL_STACK;\ + } while (0) /** * Beginning of failure clause */ -#define FAIL_BEGIN fail: saved_errno = errno +#define FAIL_BEGIN fail: saved_errno = errno /** * End of failure clause */ -#define FAIL_END return errno = saved_errno, -1 +#define FAIL_END return errno = saved_errno, -1 /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The parameter of `compile_layout` */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; /** * 3: `return` is being processed @@ -101,12 +99,12 @@ static int multiple_variants = 0; * * (We will not look too hard.) */ -static mds_kbdc_tree_t* last_value_statement = NULL; +static mds_kbdc_tree_t *last_value_statement = NULL; /** * Address of the current return value */ -static char32_t** current_return_value = NULL; +static char32_t **current_return_value = NULL; /** * Whether ‘\set/3’ has been called @@ -121,7 +119,7 @@ static int have_side_effect = 0; * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_subtree(mds_kbdc_tree_t* restrict tree); +static int compile_subtree(mds_kbdc_tree_t *restrict tree); /** * Check that a function used in a part of a literal is defined @@ -133,8 +131,8 @@ static int compile_subtree(mds_kbdc_tree_t* restrict tree); * @param rc Success status output parameter: zero on success, * -1 on error, 1 if an undefined function is used */ -static void check_function_call(const mds_kbdc_tree_t* restrict tree, const char* restrict raw, - size_t lineoff, const char* restrict* restrict end, int* restrict rc); +static void check_function_call(const mds_kbdc_tree_t *restrict tree, const char *restrict raw, + size_t lineoff, const char *restrict *restrict end, int *restrict rc); /** * Parse an argument in a function call @@ -146,8 +144,8 @@ static void check_function_call(const mds_kbdc_tree_t* restrict tree, const char * @param value Output parameter for the value to which the argument evaulates * @return Zero on success, -1 on error */ -static int parse_function_argument(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff, - const char* restrict* restrict end, char32_t** restrict value); +static int parse_function_argument(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff, + const char *restrict *restrict end, char32_t **restrict value); @@ -167,37 +165,36 @@ static int parse_function_argument(mds_kbdc_tree_t* restrict tree, const char* r * but could easily be mistaked for one that does * @return Zero on success, -1 on error */ -static int let(size_t variable, const char32_t* restrict string, const mds_kbdc_tree_t* restrict value, - mds_kbdc_tree_t* restrict statement, size_t lineoff, int possibile_shadow_attempt) +static int +let(size_t variable, const char32_t *restrict string, const mds_kbdc_tree_t *restrict value, + mds_kbdc_tree_t *restrict statement, size_t lineoff, int possibile_shadow_attempt) { - mds_kbdc_tree_t* tree = NULL; - int saved_errno; - - /* Warn if this is a possible shadow attempt. */ - if (possibile_shadow_attempt && variables_let_will_override(variable) && statement && - (variables_has_been_used_in_for(variable) == 0) && (statement->processed != PROCESS_LEVEL)) - { - statement->processed = PROCESS_LEVEL; - NEW_ERROR(statement, WARNING, "does not shadow existing definition"); - error->start = lineoff; - error->end = lineoff + (size_t)snprintf(NULL, 0, "\\%zu", variable); - } - - /* Duplicate value. */ - if (value) - fail_if (tree = mds_kbdc_tree_dup(value), tree == NULL); - if (value == NULL) - { - fail_if (tree = mds_kbdc_tree_create(C(COMPILED_STRING)), tree == NULL); - fail_if ((tree->compiled_string.string = string_dup(string)) == NULL); - } - - /* Assign variable. */ - fail_if (variables_let(variable, tree)); - return 0; - FAIL_BEGIN; - mds_kbdc_tree_free(tree); - FAIL_END; + mds_kbdc_tree_t *tree = NULL; + int saved_errno; + + /* Warn if this is a possible shadow attempt. */ + if (possibile_shadow_attempt && variables_let_will_override(variable) && statement && + !variables_has_been_used_in_for(variable) && statement->processed != PROCESS_LEVEL) { + statement->processed = PROCESS_LEVEL; + NEW_ERROR(statement, WARNING, "does not shadow existing definition"); + error->start = lineoff; + error->end = lineoff + (size_t)snprintf(NULL, 0, "\\%zu", variable); + } + + /* Duplicate value. */ + if (value) { + fail_if (!(tree = mds_kbdc_tree_dup(value))); + } else { + fail_if (!(tree = mds_kbdc_tree_create(C(COMPILED_STRING)))); + fail_if (!(tree->compiled_string.string = string_dup(string))); + } + + /* Assign variable. */ + fail_if (variables_let(variable, tree)); + return 0; + FAIL_BEGIN; + mds_kbdc_tree_free(tree); + FAIL_END; } @@ -212,48 +209,47 @@ static int let(size_t variable, const char32_t* restrict string, const mds_kbdc_ * @param end The offset on the line where the function call ends * @return Zero on success, -1 on error, 1 if the call is invalid */ -static int check_set_3_get_2_call(mds_kbdc_tree_t* restrict tree, int is_set, const char32_t* variable_arg, - const char32_t* index_arg, size_t start, size_t end) +static int +check_set_3_get_2_call(mds_kbdc_tree_t *restrict tree, int is_set, const char32_t *variable_arg, + const char32_t *index_arg, size_t start, size_t end) { -#define F (is_set ? "set/3" : "get/2") -#define FUN_ERROR(...) \ - do \ - { \ - NEW_ERROR(__VA_ARGS__); \ - error->start = start; \ - error->end = end; \ - return 1; \ - } \ - while(0); - - mds_kbdc_tree_t* variable; - mds_kbdc_tree_t* element; - size_t index, arg_count; - - if ((variable_arg[0] <= 0) || (variable_arg[1] != -1)) - FUN_ERROR(tree, ERROR, "first argument in call to function ‘%s’ must be a variable index", F); - - if ((index_arg[0] < 0) || (index_arg[1] != -1)) - FUN_ERROR(tree, ERROR, "second argument in call to function ‘%s’ must be an element index", F); - - variable = variables_get((size_t)*variable_arg); - if (variable == NULL) - FUN_ERROR(tree, ERROR, "‘\\%zu’ is not declared", (size_t)*variable_arg); - if (variable->type != C(ARRAY)) - FUN_ERROR(tree, ERROR, "‘\\%zu’ is not an array", (size_t)*variable_arg); - - arg_count = index = (size_t)*index_arg; - element = variable->array.elements; - while (element && index--) - element = element->next; - - if (element == NULL) - FUN_ERROR(tree, ERROR, "‘\\%zu’ does not hold %zu %s", - (size_t)*variable_arg, arg_count + 1, arg_count ? "elements" : "element"); - - return 0; - fail: - return -1; +#define F (is_set ? "set/3" : "get/2") +#define FUN_ERROR(...)\ + do {\ + NEW_ERROR(__VA_ARGS__);\ + error->start = start;\ + error->end = end;\ + return 1;\ + } while(0); + + mds_kbdc_tree_t *variable; + mds_kbdc_tree_t *element; + size_t index, arg_count; + + if (variable_arg[0] <= 0 || variable_arg[1] != -1) + FUN_ERROR(tree, ERROR, "first argument in call to function ‘%s’ must be a variable index", F); + + if (index_arg[0] < 0 || index_arg[1] != -1) + FUN_ERROR(tree, ERROR, "second argument in call to function ‘%s’ must be an element index", F); + + variable = variables_get((size_t)*variable_arg); + if (!variable) + FUN_ERROR(tree, ERROR, "‘\\%zu’ is not declared", (size_t)*variable_arg); + if (variable->type != C(ARRAY)) + FUN_ERROR(tree, ERROR, "‘\\%zu’ is not an array", (size_t)*variable_arg); + + arg_count = index = (size_t)*index_arg; + element = variable->array.elements; + while (element && index--) + element = element->next; + + if (!element) + FUN_ERROR(tree, ERROR, "‘\\%zu’ does not hold %zu %s", + (size_t)*variable_arg, arg_count + 1, arg_count ? "elements" : "element"); + + return 0; +fail: + return -1; #undef FUN_ERROR #undef F } @@ -274,125 +270,118 @@ static int check_set_3_get_2_call(mds_kbdc_tree_t* restrict tree, int is_set, co * as containing an error * @return Zero on success, -1 on error */ -static int call_function(mds_kbdc_tree_t* restrict tree, const char* restrict name, - const char32_t** restrict arguments, size_t start, size_t end, - char32_t** restrict return_value) +static int +call_function(mds_kbdc_tree_t *restrict tree, const char *restrict name, const char32_t **restrict arguments, + size_t start, size_t end, char32_t **restrict return_value) { -#define FUN_ERROR(...) \ - do \ - { \ - NEW_ERROR(__VA_ARGS__); \ - error->start = start; \ - error->end = end; \ - tree->processed = PROCESS_LEVEL; \ - free(*return_value), *return_value = NULL; \ - goto done; \ - } \ - while(0); - - size_t i, arg_count = 0, empty_count = 0; - char32_t** old_return_value; - mds_kbdc_tree_function_t* function = NULL; - mds_kbdc_include_stack_t* function_include_stack = NULL; - mds_kbdc_include_stack_t* our_include_stack = NULL; - int r, is_set, builtin, saved_errno; - - /* Push call-stack. */ - mds_kbdc_call_stack_push(tree, start, end); - - /* Count the number of arguments we have. */ - while (arguments[arg_count]) - arg_count++; - - /* Push return-stack. */ - *return_value = NULL; - old_return_value = current_return_value; - current_return_value = return_value; - - /* Get function definition. */ - builtin = builtin_function_defined(name, arg_count); - if (builtin == 0) - callables_get(name, arg_count, (mds_kbdc_tree_t**)&function, &function_include_stack); - if ((builtin == 0) && (function == NULL)) - FUN_ERROR(tree, ERROR, "function ‘%s/%zu’ has not been defined yet", name, arg_count); - - - /* Call non-builtin function. */ - if (builtin == 0) - { - /* Push call stack and set parameters. */ - variables_stack_push(); - for (i = 0; i < arg_count; i++) - fail_if (let(i + 1, arguments[i], NULL, NULL, 0, 0)); - - /* Switch include-stack to the function's. */ - fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL); - fail_if (mds_kbdc_include_stack_restore(function_include_stack)); - - /* Call the function. */ - fail_if (compile_subtree(function->inner)); - - /* Switch back the include-stack to ours. */ - fail_if (mds_kbdc_include_stack_restore(our_include_stack)); - mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL; - - /* Pop call stack. */ - variables_stack_pop(); - - /* Check that the function returned a value. */ - if (*return_value == NULL) - FUN_ERROR(tree, ERROR, "function ‘%s/%zu’ did not return a value", name, arg_count); - - goto done; - } - - - /* Call builtin function. */ - - /* Check argument sanity. */ - is_set = (arg_count == 3) && !strcmp(name, "set"); - if (is_set || ((arg_count == 2) && !strcmp(name, "get"))) - { - fail_if (r = check_set_3_get_2_call(tree, is_set, arguments[0], arguments[1], start, end), r < 0); - if (r) - { - tree->processed = PROCESS_LEVEL; - free(*return_value), *return_value = NULL; - goto done; +#define FUN_ERROR(...)\ + do {\ + NEW_ERROR(__VA_ARGS__);\ + error->start = start;\ + error->end = end;\ + tree->processed = PROCESS_LEVEL;\ + free(*return_value), *return_value = NULL;\ + goto done;\ + } while(0); + + size_t i, arg_count = 0, empty_count = 0; + char32_t **old_return_value; + mds_kbdc_tree_function_t *function = NULL; + mds_kbdc_include_stack_t *function_include_stack = NULL; + mds_kbdc_include_stack_t *our_include_stack = NULL; + int r, is_set, builtin, saved_errno; + + /* Push call-stack. */ + mds_kbdc_call_stack_push(tree, start, end); + + /* Count the number of arguments we have. */ + while (arguments[arg_count]) + arg_count++; + + /* Push return-stack. */ + *return_value = NULL; + old_return_value = current_return_value; + current_return_value = return_value; + + /* Get function definition. */ + builtin = builtin_function_defined(name, arg_count); + if (!builtin) + callables_get(name, arg_count, (mds_kbdc_tree_t**)&function, &function_include_stack); + if (!builtin && !function) + FUN_ERROR(tree, ERROR, "function ‘%s/%zu’ has not been defined yet", name, arg_count); + + + /* Call non-builtin function. */ + if (!builtin) { + /* Push call stack and set parameters. */ + variables_stack_push(); + for (i = 0; i < arg_count; i++) + fail_if (let(i + 1, arguments[i], NULL, NULL, 0, 0)); + + /* Switch include-stack to the function's. */ + fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL); + fail_if (mds_kbdc_include_stack_restore(function_include_stack)); + + /* Call the function. */ + fail_if (compile_subtree(function->inner)); + + /* Switch back the include-stack to ours. */ + fail_if (mds_kbdc_include_stack_restore(our_include_stack)); + mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL; + + /* Pop call stack. */ + variables_stack_pop(); + + /* Check that the function returned a value. */ + if (!*return_value) + FUN_ERROR(tree, ERROR, "function ‘%s/%zu’ did not return a value", name, arg_count); + + goto done; } - } - else - { - for (i = 0; i < arg_count; i++) - empty_count += string_length(arguments[i]) == 0; - if (empty_count && (empty_count != arg_count)) - FUN_ERROR(tree, ERROR, - "built-in function ‘%s/%zu’ requires that either none of" - " the arguments are empty strings or that all of them are", - name, arg_count); - } - - /* Call the function. */ - *return_value = builtin_function_invoke(name, arg_count, arguments); - fail_if (*return_value == NULL); - have_side_effect |= is_set; - /* XXX ideally, we want to make sure it is in a scope that actually brings side-effects. */ - - - done: - /* Pop call-stack. */ - mds_kbdc_call_stack_pop(); - - /* Pop return-stack. */ - current_return_value = old_return_value; - return 0; - - FAIL_BEGIN; - mds_kbdc_call_stack_pop(); - mds_kbdc_include_stack_free(our_include_stack); - free(*return_value), *return_value = NULL; - current_return_value = old_return_value; - FAIL_END; + + + /* Call builtin function. */ + + /* Check argument sanity. */ + is_set = arg_count == 3 && !strcmp(name, "set"); + if (is_set || (arg_count == 2 && !strcmp(name, "get"))) { + fail_if (r = check_set_3_get_2_call(tree, is_set, arguments[0], arguments[1], start, end), r < 0); + if (r) { + tree->processed = PROCESS_LEVEL; + free(*return_value), *return_value = NULL; + goto done; + } + } else { + for (i = 0; i < arg_count; i++) + empty_count += !string_length(arguments[i]); + if (empty_count && empty_count != arg_count) + FUN_ERROR(tree, ERROR, + "built-in function ‘%s/%zu’ requires that either none of" + " the arguments are empty strings or that all of them are", + name, arg_count); + } + + /* Call the function. */ + *return_value = builtin_function_invoke(name, arg_count, arguments); + fail_if (!*return_value); + have_side_effect |= is_set; + /* XXX ideally, we want to make sure it is in a scope that actually brings side-effects. */ + + +done: + /* Pop call-stack. */ + mds_kbdc_call_stack_pop(); + + /* Pop return-stack. */ + current_return_value = old_return_value; + return 0; + + FAIL_BEGIN; + mds_kbdc_call_stack_pop(); + mds_kbdc_include_stack_free(our_include_stack); + free(*return_value), *return_value = NULL; + current_return_value = old_return_value; + FAIL_END; #undef FUN_ERROR } @@ -408,102 +397,99 @@ static int call_function(mds_kbdc_tree_t* restrict tree, const char* restrict na * @param end Output parameter for the end of the escape * @return The text the escape represents, `NULL` on error */ -static char32_t* parse_function_call(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff, - int* restrict escape, const char* restrict* restrict end) +static char32_t * +parse_function_call(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff, + int *restrict escape, const char *restrict *restrict end) { -#define R(LOWER, UPPER) (((LOWER) <= c) && (c <= (UPPER))) -#define GROW_ARGS \ - if (arguments_ptr == arguments_size) \ - fail_if (xxrealloc(old_arguments, arguments, arguments_size += 4, char32_t*)) - - const char* restrict bracket = raw + 1; - char32_t* rc = NULL; - const char32_t** restrict arguments_; - char32_t** restrict arguments = NULL; - char32_t** restrict old_arguments = NULL; - size_t arguments_ptr = 0, arguments_size = 0; - char* restrict name; - char c; - int r, saved_errno = 0; - - /* Find the opening bracket associated with the function call and validate the escape. */ - for (; c = *bracket, 1; bracket++) - if ((c == '_') || R('0', '9') || R('a', 'z') || R('A', 'Z')); - else if (c == '(') - break; - else - { - *end = bracket; - if (tree->processed != PROCESS_LEVEL) - NEW_ERROR(tree, ERROR, "invalid escape"); - goto error; - } - - /* Copy the name of the function. */ - name = alloca((size_t)(bracket - raw) * sizeof(char)); - memcpy(name, raw + 1, (size_t)(bracket - raw - 1) * sizeof(char)); - name[bracket - raw - 1] = 0; - - /* Get arguments. */ - for (*end = ++bracket;;) - { - while (**end == ' ') - (*end)++; - GROW_ARGS; - arguments[arguments_ptr] = NULL; - if (**end == ')') - { - *escape = 0; - (*end)++; - arguments_ptr++; - break; +#define R(LOWER, UPPER) ((LOWER) <= c && c <= (UPPER)) +#define GROW_ARGS\ + if (arguments_ptr == arguments_size)\ + fail_if (xxrealloc(old_arguments, arguments, arguments_size += 4, char32_t*)) + + const char *restrict bracket = raw + 1; + char32_t *rc = NULL; + const char32_t **restrict arguments_; + char32_t **restrict arguments = NULL; + char32_t **restrict old_arguments = NULL; + size_t arguments_ptr = 0, arguments_size = 0; + char *restrict name; + char c; + int r, saved_errno = 0; + + /* Find the opening bracket associated with the function call and validate the escape. */ + for (; c = *bracket, 1; bracket++) { + if (c == '_' || R('0', '9') || R('a', 'z') || R('A', 'Z')); + else if (c == '(') { + break; + } else { + *end = bracket; + if (tree->processed != PROCESS_LEVEL) + NEW_ERROR(tree, ERROR, "invalid escape"); + goto error; + } } - else if (**end == '\0') - { - if (tree->processed != PROCESS_LEVEL) - NEW_ERROR(tree, ERROR, "incomplete function call"); - goto error; + + /* Copy the name of the function. */ + name = alloca((size_t)(bracket - raw) * sizeof(char)); + memcpy(name, raw + 1, (size_t)(bracket - raw - 1) * sizeof(char)); + name[bracket - raw - 1] = 0; + + /* Get arguments. */ + for (*end = ++bracket;;) { + while (**end == ' ') + (*end)++; + GROW_ARGS; + arguments[arguments_ptr] = NULL; + if (**end == ')') { + *escape = 0; + (*end)++; + arguments_ptr++; + break; + } else if (!**end) { + if (tree->processed != PROCESS_LEVEL) + NEW_ERROR(tree, ERROR, "incomplete function call"); + goto error; + } + r = parse_function_argument(tree, *end, lineoff + (size_t)(*end - raw), end, arguments + arguments_ptr++); + fail_if (r < 0); } - r = parse_function_argument(tree, *end, lineoff + (size_t)(*end - raw), end, arguments + arguments_ptr++); - fail_if (r < 0); - } - - /* Call the function. */ - if (tree->processed == PROCESS_LEVEL) - goto stop; - arguments_ = alloca(arguments_ptr * sizeof(const char32_t*)); - memcpy(arguments_, arguments, arguments_ptr * sizeof(const char32_t*)); - fail_if (call_function(tree, name, arguments_, lineoff, lineoff + (size_t)(*end - raw), &rc)); - if (rc == NULL) - goto stop; - - goto done; - - error: - error->start = lineoff; - error->end = lineoff + (size_t)(*end - raw); - stop: - *escape = 0; - tree->processed = PROCESS_LEVEL; - fail_if (xmalloc(rc, 1, char32_t)); - *rc = -1; - goto done; - - fail: - saved_errno = errno; - free(rc); - if (old_arguments) - arguments = old_arguments; - while (arguments_ptr--) - free(arguments[arguments_ptr]); - free(arguments); - rc = NULL; - done: - while (arguments_ptr--) - free(arguments[arguments_ptr]); - free(arguments); - errno = saved_errno; - return rc; + + /* Call the function. */ + if (tree->processed == PROCESS_LEVEL) + goto stop; + arguments_ = alloca(arguments_ptr * sizeof(const char32_t*)); + memcpy(arguments_, arguments, arguments_ptr * sizeof(const char32_t*)); + fail_if (call_function(tree, name, arguments_, lineoff, lineoff + (size_t)(*end - raw), &rc)); + if (!rc) + goto stop; + + goto done; + +error: + error->start = lineoff; + error->end = lineoff + (size_t)(*end - raw); +stop: + *escape = 0; + tree->processed = PROCESS_LEVEL; + fail_if (xmalloc(rc, 1, char32_t)); + *rc = -1; + goto done; + +fail: + saved_errno = errno; + free(rc); + if (old_arguments) + arguments = old_arguments; + while (arguments_ptr--) + free(arguments[arguments_ptr]); + free(arguments); + rc = NULL; +done: + while (arguments_ptr--) + free(arguments[arguments_ptr]); + free(arguments); + errno = saved_errno; + return rc; #undef GROW_ARGS #undef R } @@ -520,41 +506,39 @@ static char32_t* parse_function_call(mds_kbdc_tree_t* restrict tree, const char* * -1 on error, 1 if an undefined function is used * @return The number of arguments the part of the literal contains */ -static size_t check_function_calls_in_literal_(const mds_kbdc_tree_t* restrict tree, - const char* restrict raw, size_t lineoff, - const char* restrict* restrict end, int* restrict rc) +static size_t +check_function_calls_in_literal_(const mds_kbdc_tree_t *restrict tree, const char *restrict raw, + size_t lineoff, const char *restrict *restrict end, int *restrict rc) { -#define R(LOWER, UPPER) (((LOWER) <= c) && (c <= (UPPER))) - const char* restrict raw_ = raw; - size_t count = 0; - int space = 1, quote = 0, escape = 0; - char c; - - while ((c = *raw++)) - { - if (space && !strchr(" )", c)) - space = 0, count++; - - if (escape) - { - escape = 0; - if (((c == '_') || R('a', 'z') || R('A', 'Z')) && (c != 'u')) - /* \u*() is disallowed because \u* is used for hexadecimal representation. */ - if (check_function_call(tree, raw - 2, lineoff + (size_t)(raw - 2 - raw_), &raw, rc), *rc < 0) - break; - } - else if (c == '\\') escape = 1; - else if (c == '"') quote ^= 1; - else if (!quote) - { - space = (c == ' '); - if (c == ')') - break; +#define R(LOWER, UPPER) ((LOWER) <= c && c <= (UPPER)) + const char *restrict raw_ = raw; + size_t count = 0; + int space = 1, quote = 0, escape = 0; + char c; + + while ((c = *raw++)) { + if (space && !strchr(" )", c)) + space = 0, count++; + + if (escape) { + escape = 0; + if ((c == '_' || R('a', 'z') || R('A', 'Z')) && c != 'u') + /* \u*() is disallowed because \u* is used for hexadecimal representation. */ + if (check_function_call(tree, raw - 2, lineoff + (size_t)(raw - 2 - raw_), &raw, rc), *rc < 0) + break; + } else if (c == '\\') { + escape = 1; + } else if (c == '"') { + quote ^= 1; + } else if (!quote) { + space = c == ' '; + if (c == ')') + break; + } } - } - - *end = raw; - return count; + + *end = raw; + return count; #undef R } @@ -569,45 +553,46 @@ static size_t check_function_calls_in_literal_(const mds_kbdc_tree_t* restrict t * @param rc Success status output parameter: zero on success, * -1 on error, 1 if an undefined function is used */ -static void check_function_call(const mds_kbdc_tree_t* restrict tree, const char* restrict raw, - size_t lineoff, const char* restrict* restrict end, int* restrict rc) +static void +check_function_call(const mds_kbdc_tree_t *restrict tree, const char *restrict raw, + size_t lineoff, const char *restrict *restrict end, int *restrict rc) { - mds_kbdc_tree_t* function = NULL; - mds_kbdc_include_stack_t* _function_include_stack; - char* restrict bracket = strchr(raw, '('); - char* restrict name; - size_t arg_count; - - /* Check that it is a function call by check that it has an opening bracket. */ - if (bracket == NULL) - { - *end = raw + strlen(raw); - return; - } - - /* Copy the name of the function. */ - name = alloca((size_t)(bracket - raw) * sizeof(char)); - memcpy(name, raw + 1, (size_t)(bracket - raw - 1) * sizeof(char)); - name[bracket++ - raw - 1] = 0; - - /* Get the number of arguments used, and check function calls there too. */ - arg_count = check_function_calls_in_literal_(tree, bracket, lineoff + (size_t)(bracket - raw), end, rc); - if (*rc < 0) return; - - /* Check that the function is defined. */ - if (builtin_function_defined(name, arg_count)) - return; - callables_get(name, arg_count, &function, &_function_include_stack); - if (function != NULL) - return; - *rc |= 1; - NEW_ERROR(tree, ERROR, "function ‘%s/%zu’ has not been defined yet", name, arg_count); - error->start = lineoff; - error->end = lineoff + (size_t)(*end - raw); - return; - - fail: - *rc |= -1; + mds_kbdc_tree_t *function = NULL; + mds_kbdc_include_stack_t *_function_include_stack; + char *restrict bracket = strchr(raw, '('); + char *restrict name; + size_t arg_count; + + /* Check that it is a function call by check that it has an opening bracket. */ + if (!bracket) { + *end = raw + strlen(raw); + return; + } + + /* Copy the name of the function. */ + name = alloca((size_t)(bracket - raw) * sizeof(char)); + memcpy(name, raw + 1, (size_t)(bracket - raw - 1) * sizeof(char)); + name[bracket++ - raw - 1] = 0; + + /* Get the number of arguments used, and check function calls there too. */ + arg_count = check_function_calls_in_literal_(tree, bracket, lineoff + (size_t)(bracket - raw), end, rc); + if (*rc < 0) + return; + + /* Check that the function is defined. */ + if (builtin_function_defined(name, arg_count)) + return; + callables_get(name, arg_count, &function, &_function_include_stack); + if (function) + return; + *rc |= 1; + NEW_ERROR(tree, ERROR, "function ‘%s/%zu’ has not been defined yet", name, arg_count); + error->start = lineoff; + error->end = lineoff + (size_t)(*end - raw); + return; + +fail: + *rc |= -1; } @@ -619,14 +604,15 @@ static void check_function_call(const mds_kbdc_tree_t* restrict tree, const char * @param lineoff The offset on the line where the literal beings * @return Zero on success, -1 on error, 1 if an undefined function is used */ -static int check_function_calls_in_literal(const mds_kbdc_tree_t* restrict tree, - const char* restrict raw, size_t lineoff) +static int +check_function_calls_in_literal(const mds_kbdc_tree_t *restrict tree, + const char *restrict raw, size_t lineoff) { - int rc = 0; - (void) check_function_calls_in_literal_(tree, raw, lineoff, &raw, &rc); - fail_if (rc < 0); - fail: - return rc; + int rc = 0; + (void) check_function_calls_in_literal_(tree, raw, lineoff, &raw, &rc); + fail_if (rc < 0); +fail: + return rc; } @@ -641,102 +627,98 @@ static int check_function_calls_in_literal(const mds_kbdc_tree_t* restrict tree, * @param end Output parameter for the end of the escape * @return The text the escape represents, `NULL` on error */ -static char32_t* parse_escape(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff, - int* restrict escape, const char* restrict* restrict end) +static char32_t * +parse_escape(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff, + int *restrict escape, const char *restrict *restrict end) { -#define R(LOWER, UPPER) (((LOWER) <= c) && (c <= (UPPER))) -#define CR(COND, LOWER, UPPER) ((*escape == (COND)) && R(LOWER, UPPER)) -#define VARIABLE (int)(raw - raw_) - (c == '.'), raw_ -#define RETURN_ERROR(...) \ - do \ - { \ - NEW_ERROR(__VA_ARGS__); \ - error->start = lineoff; \ - error->end = lineoff + (size_t)(raw - raw_); \ - tree->processed = PROCESS_LEVEL; \ - *escape = 0; \ - if (rc) \ - goto done; \ - fail_if (xmalloc(rc, 1, char32_t)); \ - *rc = -1; \ - goto done; \ - } \ - while (0) - - const char* restrict raw_ = raw++; - char c = *raw++; - uintmax_t numbuf = 0; - char32_t* rc = NULL; - mds_kbdc_tree_t* value; - int have = 0, saved_errno; - - - /* Get escape type. */ - if (c == '0') - /* Octal representation. */ - *escape = 8, have = 1; - else if (c == 'u') - /* Hexadecimal representation. */ - *escape = 16; - else if (R('1', '9')) - /* Variable dereference. */ - *escape = 10, have = 1, numbuf = (uintmax_t)(c - '0'); - else if ((c == '_') || R('a', 'z') || R('A', 'Z')) - /* Function call. */ - *escape = 100; - else - RETURN_ERROR(tree, ERROR, "invalid escape"); - - - /* Read escape. */ - if (*escape == 100) - /* Function call. */ - { - fail_if (rc = parse_function_call(tree, raw_, lineoff, escape, end), rc == NULL); - return rc; - } - /* Octal or hexadecimal representation, or variable dereference. */ - for (; (c = *raw); have = 1, raw++) - if (CR( 8, '0', '7')) numbuf = 8 * numbuf + (c & 15); - else if (CR(16, '0', '9')) numbuf = 16 * numbuf + (c & 15); - else if (CR(16, 'a', 'f')) numbuf = 16 * numbuf + (c & 15) + 9; - else if (CR(16, 'A', 'F')) numbuf = 16 * numbuf + (c & 15) + 9; - else if (CR(10, '0', '9')) numbuf = 10 * numbuf + (c & 15); - else break; - if (c == '.') - raw++; - if (have == 0) - RETURN_ERROR(tree, ERROR, "invalid escape"); - - - /* Evaluate escape. */ - if (*escape == 10) - { - /* Variable dereference. */ - if (value = variables_get((size_t)numbuf), value == NULL) - RETURN_ERROR(tree, ERROR, "variable ‘%.*s’ is not defined", VARIABLE); - if (value->type == C(ARRAY)) - RETURN_ERROR(tree, ERROR, "variable ‘%.*s’ is an array", VARIABLE); - if (value->type != C(COMPILED_STRING)) - NEW_ERROR(tree, INTERNAL_ERROR, "variable ‘%.*s’ is of impossible type", VARIABLE); - fail_if (rc = string_dup(value->compiled_string.string), rc == NULL); - } - else - { - /* Octal or hexadecimal representation. */ - fail_if (xmalloc(rc, 2, char32_t)); - rc[0] = (char32_t)numbuf, rc[1] = -1; - } - - - done: - *escape = 0; - *end = raw; - return rc; - fail: - saved_errno = errno; - free(rc); - return errno = saved_errno, NULL; +#define R(LOWER, UPPER) ((LOWER) <= c && c <= (UPPER)) +#define CR(COND, LOWER, UPPER) (*escape == (COND) && R(LOWER, UPPER)) +#define VARIABLE (int)(raw - raw_) - (c == '.'), raw_ +#define RETURN_ERROR(...)\ + do {\ + NEW_ERROR(__VA_ARGS__);\ + error->start = lineoff;\ + error->end = lineoff + (size_t)(raw - raw_);\ + tree->processed = PROCESS_LEVEL;\ + *escape = 0;\ + if (rc)\ + goto done;\ + fail_if (xmalloc(rc, 1, char32_t));\ + *rc = -1;\ + goto done;\ + } while (0) + + const char* restrict raw_ = raw++; + char c = *raw++; + uintmax_t numbuf = 0; + char32_t* rc = NULL; + mds_kbdc_tree_t* value; + int have = 0, saved_errno; + + + /* Get escape type. */ + if (c == '0') + /* Octal representation. */ + *escape = 8, have = 1; + else if (c == 'u') + /* Hexadecimal representation. */ + *escape = 16; + else if (R('1', '9')) + /* Variable dereference. */ + *escape = 10, have = 1, numbuf = (uintmax_t)(c - '0'); + else if (c == '_' || R('a', 'z') || R('A', 'Z')) + /* Function call. */ + *escape = 100; + else + RETURN_ERROR(tree, ERROR, "invalid escape"); + + + /* Read escape. */ + if (*escape == 100) { + /* Function call. */ + fail_if (rc = parse_function_call(tree, raw_, lineoff, escape, end), rc == NULL); + return rc; + } + /* Octal or hexadecimal representation, or variable dereference. */ + for (; (c = *raw); have = 1, raw++) { + if (CR( 8, '0', '7')) numbuf = 8 * numbuf + (c & 15); + else if (CR(16, '0', '9')) numbuf = 16 * numbuf + (c & 15); + else if (CR(16, 'a', 'f')) numbuf = 16 * numbuf + (c & 15) + 9; + else if (CR(16, 'A', 'F')) numbuf = 16 * numbuf + (c & 15) + 9; + else if (CR(10, '0', '9')) numbuf = 10 * numbuf + (c & 15); + else break; + } + if (c == '.') + raw++; + if (have == 0) + RETURN_ERROR(tree, ERROR, "invalid escape"); + + + /* Evaluate escape. */ + if (*escape == 10) { + /* Variable dereference. */ + if (!(value = variables_get((size_t)numbuf))) + RETURN_ERROR(tree, ERROR, "variable ‘%.*s’ is not defined", VARIABLE); + if (value->type == C(ARRAY)) + RETURN_ERROR(tree, ERROR, "variable ‘%.*s’ is an array", VARIABLE); + if (value->type != C(COMPILED_STRING)) + NEW_ERROR(tree, INTERNAL_ERROR, "variable ‘%.*s’ is of impossible type", VARIABLE); + fail_if (!(rc = string_dup(value->compiled_string.string))); + } else { + /* Octal or hexadecimal representation. */ + fail_if (xmalloc(rc, 2, char32_t)); + rc[0] = (char32_t)numbuf, rc[1] = -1; + } + + +done: + *escape = 0; + *end = raw; + return rc; +fail: + saved_errno = errno; + free(rc); + return errno = saved_errno, NULL; #undef RETURN_ERROR #undef VARIABLE #undef CR @@ -752,127 +734,114 @@ static char32_t* parse_escape(mds_kbdc_tree_t* restrict tree, const char* restri * @param lineoff The offset on the line where the string beings * @return The string as pure text, `NULL` on error */ -static char32_t* parse_quoted_string(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff) +static char32_t * +parse_quoted_string(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff) { -#define GROW_BUF \ - if (buf_ptr == buf_size) \ - fail_if (xxrealloc(old_buf, buf, buf_size += 16, char)) -#define COPY \ - n = string_length(subrc); \ - fail_if (xxrealloc(old_rc, rc, rc_ptr + n, char32_t)); \ - memcpy(rc + rc_ptr, subrc, n * sizeof(char32_t)), rc_ptr += n; \ - free(subrc), subrc = NULL -#define STORE \ - if (buf_ptr) \ - do \ - { \ - GROW_BUF; \ - buf[buf_ptr] = '\0', buf_ptr = 0; \ - fail_if (subrc = string_decode(buf), subrc == NULL); \ - COPY; \ - } \ - while (0) -#define CHAR_ERROR(...) \ - do \ - { \ - NEW_ERROR(__VA_ARGS__); \ - error->end = lineoff + (size_t)(raw - raw_); \ - error->start = error->end - 1; \ - } \ - while (0) - - const char* restrict raw_ = raw; - char32_t* restrict subrc = NULL; - char32_t* restrict rc = NULL; - char32_t* restrict old_rc = NULL; - char* restrict buf = NULL; - char* restrict old_buf = NULL; - size_t rc_ptr = 0, n; - size_t buf_ptr = 0, buf_size = 0; - size_t escoff = 0; - int quote = 0, escape = 0; - char c; - int saved_errno; - - /* Parse the string. */ - while ((c = *raw++)) - if (escape && quote && strchr("()[]{}<>\"\\,", c)) - { - /* Buffer UTF-8 text for convertion to UTF-32. */ - GROW_BUF; - buf[buf_ptr++] = c; - escape = 0; - } - else if (escape) - { - /* Parse escape. */ - raw -= 2, escoff = lineoff + (size_t)(raw - raw_); - subrc = parse_escape(tree, raw, escoff, &escape, &raw); - fail_if (subrc == NULL); - COPY; - } - else if (c == '"') - { - /* Close or open quote, of it got closed, convert the buffered UTF-8 text to UTF-32. */ - if (quote ^= 1) continue; - if ((quote == 1) && (raw != raw_ + 1)) - CHAR_ERROR(tree, WARNING, "strings should either be unquoted or unclosed in one large quoted"); - STORE; - } - else if (c == '\\') - { - /* Convert the buffered UTF-8 text to UTF-32, and start an escape. */ - STORE; - escape = 1; - } - else if ((quote == 0) && (tree->processed != PROCESS_LEVEL)) - { - /* Only escapes may be used without quotes, if the string contains quotes. */ - if (*raw_ == '"') - CHAR_ERROR(tree, ERROR, "only escapes may be outside quotes in quoted strings"); - else - CHAR_ERROR(tree, ERROR, "mixing numericals and escapes is not allowed"); - tree->processed = PROCESS_LEVEL; - } - else - { - /* Buffer UTF-8 text for convertion to UTF-32. */ - GROW_BUF; - buf[buf_ptr++] = c; - } - - /* Check that no escape is incomplete. */ - if (escape && (tree->processed != PROCESS_LEVEL)) - { - NEW_ERROR(tree, ERROR, "incomplete escape"); - error->start = escoff; - error->end = lineoff + strlen(raw_); - tree->processed = PROCESS_LEVEL; - } - - /* Check that the quote is complete. */ - if (quote && (tree->processed != PROCESS_LEVEL)) - { - NEW_ERROR(tree, ERROR, "quote is not closed"); - error->start = lineoff; - error->end = lineoff + strlen(raw_); - tree->processed = PROCESS_LEVEL; - } - - /* Shrink or grow to string to its minimal size, and -1-terminate it. */ - fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t)); - rc[rc_ptr] = -1; - - free(buf); - return rc; - fail: - saved_errno = errno; - free(subrc); - free(old_rc); - free(old_buf); - free(rc); - free(buf); - return errno = saved_errno, NULL; +#define GROW_BUF\ + if (buf_ptr == buf_size)\ + fail_if (xxrealloc(old_buf, buf, buf_size += 16, char)) +#define COPY\ + n = string_length(subrc);\ + fail_if (xxrealloc(old_rc, rc, rc_ptr + n, char32_t));\ + memcpy(rc + rc_ptr, subrc, n * sizeof(char32_t)), rc_ptr += n;\ + free(subrc), subrc = NULL +#define STORE\ + do {\ + if (buf_ptr) {\ + GROW_BUF;\ + buf[buf_ptr] = '\0', buf_ptr = 0;\ + fail_if (!(subrc = string_decode(buf)));\ + COPY;\ + }\ + } while (0) +#define CHAR_ERROR(...)\ + do {\ + NEW_ERROR(__VA_ARGS__);\ + error->end = lineoff + (size_t)(raw - raw_);\ + error->start = error->end - 1;\ + } while (0) + + const char *restrict raw_ = raw; + char32_t *restrict subrc = NULL; + char32_t *restrict rc = NULL; + char32_t *restrict old_rc = NULL; + char *restrict buf = NULL; + char *restrict old_buf = NULL; + size_t rc_ptr = 0, n; + size_t buf_ptr = 0, buf_size = 0; + size_t escoff = 0; + int quote = 0, escape = 0; + char c; + int saved_errno; + + /* Parse the string. */ + while ((c = *raw++)) { + if (escape && quote && strchr("()[]{}<>\"\\,", c)) { + /* Buffer UTF-8 text for convertion to UTF-32. */ + GROW_BUF; + buf[buf_ptr++] = c; + escape = 0; + } else if (escape) { + /* Parse escape. */ + raw -= 2, escoff = lineoff + (size_t)(raw - raw_); + subrc = parse_escape(tree, raw, escoff, &escape, &raw); + fail_if (!subrc); + COPY; + } else if (c == '"') { + /* Close or open quote, of it got closed, convert the buffered UTF-8 text to UTF-32. */ + if ((quote ^= 1)) + continue; + if (quote == 1 && raw != raw_ + 1) + CHAR_ERROR(tree, WARNING, "strings should either be unquoted or unclosed in one large quoted"); + STORE; + } else if (c == '\\') { + /* Convert the buffered UTF-8 text to UTF-32, and start an escape. */ + STORE; + escape = 1; + } else if (!quote && tree->processed != PROCESS_LEVEL) { + /* Only escapes may be used without quotes, if the string contains quotes. */ + if (*raw_ == '"') + CHAR_ERROR(tree, ERROR, "only escapes may be outside quotes in quoted strings"); + else + CHAR_ERROR(tree, ERROR, "mixing numericals and escapes is not allowed"); + tree->processed = PROCESS_LEVEL; + } else { + /* Buffer UTF-8 text for convertion to UTF-32. */ + GROW_BUF; + buf[buf_ptr++] = c; + } + } + + /* Check that no escape is incomplete. */ + if (escape && tree->processed != PROCESS_LEVEL) { + NEW_ERROR(tree, ERROR, "incomplete escape"); + error->start = escoff; + error->end = lineoff + strlen(raw_); + tree->processed = PROCESS_LEVEL; + } + + /* Check that the quote is complete. */ + if (quote && tree->processed != PROCESS_LEVEL) { + NEW_ERROR(tree, ERROR, "quote is not closed"); + error->start = lineoff; + error->end = lineoff + strlen(raw_); + tree->processed = PROCESS_LEVEL; + } + + /* Shrink or grow to string to its minimal size, and -1-terminate it. */ + fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t)); + rc[rc_ptr] = -1; + + free(buf); + return rc; +fail: + saved_errno = errno; + free(subrc); + free(old_rc); + free(old_buf); + free(rc); + free(buf); + return errno = saved_errno, NULL; #undef CHAR_ERROR #undef STORE #undef COPY @@ -888,37 +857,36 @@ static char32_t* parse_quoted_string(mds_kbdc_tree_t* restrict tree, const char* * @param lineoff The offset on the line where the string beings * @return The string as pure text, `NULL` on error */ -static char32_t* parse_unquoted_string(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff) +static char32_t * +parse_unquoted_string(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff) { -#define R(LOWER, UPPER) (((LOWER) <= c) && (c <= (UPPER))) -#define CHAR_ERROR(...) \ - do \ - { \ - NEW_ERROR(__VA_ARGS__); \ - error->end = lineoff + (size_t)(raw - raw_); \ - error->start = error->end - 1; \ - tree->processed = PROCESS_LEVEL; \ - goto done; \ - } \ - while (0) - - const char* restrict raw_ = raw; - char32_t* rc; - char32_t buf = 0; - char c; - - while ((c = *raw++)) - if (R('0', '9')) buf = 10 * buf + (c & 15); - else if (c == '\\') CHAR_ERROR(tree, ERROR, "mixing numericals and escapes is not allowed"); - else if (c == '"') CHAR_ERROR(tree, ERROR, "mixing numericals and quotes is not allowed"); - else CHAR_ERROR(tree, ERROR, "stray ‘%c’", c); /* XXX support multibyte */ - - done: - fail_if (xmalloc(rc, 2, char32_t)); - return rc[0] = buf, rc[1] = -1, rc; +#define R(LOWER, UPPER) ((LOWER) <= c && c <= (UPPER)) +#define CHAR_ERROR(...)\ + do {\ + NEW_ERROR(__VA_ARGS__);\ + error->end = lineoff + (size_t)(raw - raw_);\ + error->start = error->end - 1;\ + tree->processed = PROCESS_LEVEL;\ + goto done;\ + } while (0) + + const char *restrict raw_ = raw; + char32_t *rc, buf = 0; + char c; + + while ((c = *raw++)) { + if (R('0', '9')) buf = 10 * buf + (c & 15); + else if (c == '\\') CHAR_ERROR(tree, ERROR, "mixing numericals and escapes is not allowed"); + else if (c == '"') CHAR_ERROR(tree, ERROR, "mixing numericals and quotes is not allowed"); + else CHAR_ERROR(tree, ERROR, "stray ‘%c’", c); /* XXX support multibyte */ + } + +done: + fail_if (xmalloc(rc, 2, char32_t)); + return rc[0] = buf, rc[1] = -1, rc; - fail: - return NULL; +fail: + return NULL; #undef CHAR_ERROR #undef R } @@ -932,15 +900,16 @@ static char32_t* parse_unquoted_string(mds_kbdc_tree_t* restrict tree, const cha * @param lineoff The offset on the line where the string beings * @return The string as pure text, `NULL` on error */ -static char32_t* parse_string(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff) +static char32_t * +parse_string(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff) { - mds_kbdc_tree_t* old_last_value_statement = last_value_statement; - char32_t* rc = (strchr("\"\\", *raw) ? parse_quoted_string : parse_unquoted_string)(tree, raw, lineoff); - last_value_statement = old_last_value_statement; - fail_if (rc == NULL); - return rc; - fail: - return NULL; + mds_kbdc_tree_t *old_last_value_statement = last_value_statement; + char32_t *rc = (strchr("\"\\", *raw) ? parse_quoted_string : parse_unquoted_string)(tree, raw, lineoff); + last_value_statement = old_last_value_statement; + fail_if (!rc); + return rc; +fail: + return NULL; } @@ -952,120 +921,108 @@ static char32_t* parse_string(mds_kbdc_tree_t* restrict tree, const char* restri * @param lineoff The offset on the line where the string beings * @return The string as pure text, `NULL` on error */ -static char32_t* parse_keys(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff) +static char32_t * +parse_keys(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff) { -#define GROW_BUF \ - if (buf_ptr == buf_size) \ - fail_if (xxrealloc(old_buf, buf, buf_size += 16, char)) -#define COPY \ - n = string_length(subrc); \ - fail_if (xxrealloc(old_rc, rc, rc_ptr + n, char32_t)); \ - memcpy(rc + rc_ptr, subrc, n * sizeof(char32_t)), rc_ptr += n; \ - free(subrc), subrc = NULL -#define STORE \ - if (buf_ptr) \ - do \ - { \ - GROW_BUF; \ - buf[buf_ptr] = '\0', buf_ptr = 0; \ - fail_if (subrc = string_decode(buf), subrc == NULL); \ - COPY; \ - } \ - while (0) -#define SPECIAL(VAL) \ - STORE; \ - fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t)); \ - rc[rc_ptr++] = -(VAL + 1) - - mds_kbdc_tree_t* old_last_value_statement = last_value_statement; - const char* restrict raw_ = raw++; - char32_t* restrict subrc = NULL; - char32_t* restrict rc = NULL; - char32_t* restrict old_rc = NULL; - char* restrict buf = NULL; - char* restrict old_buf = NULL; - size_t rc_ptr = 0, n; - size_t buf_ptr = 0, buf_size = 0; - size_t escoff = 0; - int escape = 0, quote = 0; - char c; - int saved_errno; - - /* Parse the string. */ - while (c = *raw++, c && *raw) - if (escape && strchr("()[]{}<>\"\\,", c)) - { - /* Buffer UTF-8 text for convertion to UTF-32. */ - GROW_BUF; - buf[buf_ptr++] = c; - escape = 0; - } - else if (escape) - { - /* Parse escape. */ - raw -= 2, escoff = lineoff + (size_t)(raw - raw_); - subrc = parse_escape(tree, raw, escoff, &escape, &raw); - fail_if (subrc == NULL); - COPY; - } - else if (c == '\\') - { - /* Convert the buffered UTF-8 text to UTF-32, and start an escape. */ +#define GROW_BUF\ + if (buf_ptr == buf_size)\ + fail_if (xxrealloc(old_buf, buf, buf_size += 16, char)) +#define COPY\ + n = string_length(subrc);\ + fail_if (xxrealloc(old_rc, rc, rc_ptr + n, char32_t));\ + memcpy(rc + rc_ptr, subrc, n * sizeof(char32_t)), rc_ptr += n;\ + free(subrc), subrc = NULL +#define STORE\ + do {\ + if (buf_ptr) {\ + GROW_BUF;\ + buf[buf_ptr] = '\0', buf_ptr = 0;\ + fail_if (!(subrc = string_decode(buf)));\ + COPY;\ + }\ + } while (0) +#define SPECIAL(VAL)\ + STORE;\ + fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t));\ + rc[rc_ptr++] = -(VAL + 1) + + mds_kbdc_tree_t *old_last_value_statement = last_value_statement; + const char *restrict raw_ = raw++; + char32_t *restrict subrc = NULL; + char32_t *restrict rc = NULL; + char32_t *restrict old_rc = NULL; + char *restrict buf = NULL; + char *restrict old_buf = NULL; + size_t rc_ptr = 0, n; + size_t buf_ptr = 0, buf_size = 0; + size_t escoff = 0; + int escape = 0, quote = 0; + char c; + int saved_errno; + + /* Parse the string. */ + while (c = *raw++, c && *raw) { + if (escape && strchr("()[]{}<>\"\\,", c)) { + /* Buffer UTF-8 text for convertion to UTF-32. */ + GROW_BUF; + buf[buf_ptr++] = c; + escape = 0; + } else if (escape) { + /* Parse escape. */ + raw -= 2, escoff = lineoff + (size_t)(raw - raw_); + subrc = parse_escape(tree, raw, escoff, &escape, &raw); + fail_if (!subrc); + COPY; + } else if (c == '\\') { + /* Convert the buffered UTF-8 text to UTF-32, and start an escape. */ + STORE; + escape = 1; + } else if (c == ',' && !quote) { + /* Sequence in key-combination. */ + SPECIAL(1); + } else if (c == '"') { + /* String in key-combination. */ + quote ^= 1; + SPECIAL(2); + } else { + /* Buffer UTF-8 text for convertion to UTF-32. */ + GROW_BUF; + buf[buf_ptr++] = c; + } + } STORE; - escape = 1; - } - else if ((c == ',') && !quote) - { - /* Sequence in key-combination. */ - SPECIAL(1); - } - else if (c == '"') - { - /* String in key-combination. */ - quote ^= 1; - SPECIAL(2); - } - else - { - /* Buffer UTF-8 text for convertion to UTF-32. */ - GROW_BUF; - buf[buf_ptr++] = c; - } - STORE; - - /* Check that no escape is incomplete. */ - if (escape && (tree->processed != PROCESS_LEVEL)) - { - NEW_ERROR(tree, ERROR, "incomplete escape"); - error->start = lineoff + (size_t)(strrchr(raw_, '\\') - raw_); - error->end = lineoff + strlen(raw_); - tree->processed = PROCESS_LEVEL; - } - - /* Check that key-combination is complete. */ - if ((c != '>') && (tree->processed != PROCESS_LEVEL)) - { - NEW_ERROR(tree, ERROR, "key-combination is not closed"); - error->start = lineoff; - error->end = lineoff + strlen(raw_); - tree->processed = PROCESS_LEVEL; - } - - /* Shrink or grow to string to its minimal size, and -1-terminate it. */ - fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t)); - rc[rc_ptr] = -1; - - free(buf); - return last_value_statement = old_last_value_statement, rc; - fail: - saved_errno = errno; - free(subrc); - free(old_rc); - free(old_buf); - free(rc); - free(buf); - errno = saved_errno; - return last_value_statement = old_last_value_statement, NULL; + + /* Check that no escape is incomplete. */ + if (escape && tree->processed != PROCESS_LEVEL) { + NEW_ERROR(tree, ERROR, "incomplete escape"); + error->start = lineoff + (size_t)(strrchr(raw_, '\\') - raw_); + error->end = lineoff + strlen(raw_); + tree->processed = PROCESS_LEVEL; + } + + /* Check that key-combination is complete. */ + if (c != '>' && tree->processed != PROCESS_LEVEL) { + NEW_ERROR(tree, ERROR, "key-combination is not closed"); + error->start = lineoff; + error->end = lineoff + strlen(raw_); + tree->processed = PROCESS_LEVEL; + } + + /* Shrink or grow to string to its minimal size, and -1-terminate it. */ + fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t)); + rc[rc_ptr] = -1; + + free(buf); + return last_value_statement = old_last_value_statement, rc; +fail: + saved_errno = errno; + free(subrc); + free(old_rc); + free(old_buf); + free(rc); + free(buf); + errno = saved_errno; + return last_value_statement = old_last_value_statement, NULL; #undef SPECIAL #undef STORE #undef COPY @@ -1081,54 +1038,55 @@ static char32_t* parse_keys(mds_kbdc_tree_t* restrict tree, const char* restrict * @param lineoff The offset on the line where the variable string begins * @return The index of the variable, zero on error */ -static size_t parse_variable(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff) +static size_t +parse_variable(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff) { - size_t var, n; - const char* restrict raw_ = raw; - char* restrict dotless; - - /* The variable must begin with \. */ - if (*raw++ != '\\') goto bad; - /* Zero is not a valid varible, nor may there be leading zeroes or be empty. */ - if (*raw == '0') goto bad; - if (*raw == '.') goto bad; - if (*raw == '\0') goto bad; - for (; *raw; raw++) - /* Check that the variable consists only of digits. */ - if (('0' <= *raw) && (*raw <= '9')); - /* However, it may end with a dot. */ - else if ((raw[0] == '.') && (raw[1] == '\0')) - break; - else - goto bad; - - /* Parse the variable string and check that it did not overflow. */ - n = (size_t)(raw - raw_); - dotless = alloca((n + 1) * sizeof(char)); - memcpy(dotless, raw_, n * sizeof(char)), dotless[n] = '\0'; - var = atoz(dotless + 1); - if (strlen(dotless + 1) != (size_t)snprintf(NULL, 0, "%zu", var)) - fail_if ((errno = ERANGE)); - if (var == 0) - { - NEW_ERROR(tree, INTERNAL_ERROR, - "parsed a variable string to be 0, which should not be possible"); - error->start = lineoff; - error->end = lineoff + strlen(raw_); - tree->processed = PROCESS_LEVEL; - return 1; - } - return var; - fail: - return 0; - - bad: - /* Report an error but return a variable index if the variable-string is invalid. */ - NEW_ERROR(tree, ERROR, "not a variable"); - error->start = lineoff; - error->end = lineoff + strlen(raw_); - tree->processed = PROCESS_LEVEL; - return 1; + size_t var, n; + const char *restrict raw_ = raw; + char *restrict dotless; + + /* The variable must begin with \. */ + if (*raw++ != '\\') goto bad; + /* Zero is not a valid varible, nor may there be leading zeroes or be empty. */ + if (*raw == '0') goto bad; + if (*raw == '.') goto bad; + if (*raw == '\0') goto bad; + for (; *raw; raw++) { + /* Check that the variable consists only of digits. */ + if ('0' <= *raw && *raw <= '9') + /* However, it may end with a dot. */; + else if (raw[0] == '.' && raw[1] == '\0') + break; + else + goto bad; + } + + /* Parse the variable string and check that it did not overflow. */ + n = (size_t)(raw - raw_); + dotless = alloca((n + 1) * sizeof(char)); + memcpy(dotless, raw_, n * sizeof(char)), dotless[n] = '\0'; + var = atoz(dotless + 1); + if (strlen(dotless + 1) != (size_t)snprintf(NULL, 0, "%zu", var)) + fail_if ((errno = ERANGE)); + if (!var) { + NEW_ERROR(tree, INTERNAL_ERROR, + "parsed a variable string to be 0, which should not be possible"); + error->start = lineoff; + error->end = lineoff + strlen(raw_); + tree->processed = PROCESS_LEVEL; + return 1; + } + return var; +fail: + return 0; + +bad: + /* Report an error but return a variable index if the variable-string is invalid. */ + NEW_ERROR(tree, ERROR, "not a variable"); + error->start = lineoff; + error->end = lineoff + strlen(raw_); + tree->processed = PROCESS_LEVEL; + return 1; } @@ -1142,63 +1100,65 @@ static size_t parse_variable(mds_kbdc_tree_t* restrict tree, const char* restric * @param value Output parameter for the value to which the argument evaulates * @return Zero on success, -1 on error */ -static int parse_function_argument(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff, - const char* restrict* restrict end, char32_t** restrict value) +static int +parse_function_argument(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff, + const char *restrict *restrict end, char32_t **restrict value) { - size_t size = strlen(raw), ptr = 0, call_end = 0; - int escape = 0, quote = 0; - char* raw_argument = NULL; - int saved_errno; - - /* Find the span of the argument. */ - while (ptr < size) - { - char c = raw[ptr++]; - - /* Escapes may be longer than one character, - but only the first can affect the parsing. */ - if (escape) escape = 0; - /* Nested function and nested quotes can appear. */ - else if (ptr <= call_end) ; - /* Quotes end with the same symbols as they start with, - and quotes automatically escape brackets. */ - /* \ can either start a functon call or an escape. */ - else if (c == '\\') - { - /* It may not be an escape, but registering it - as an escape cannot harm us since we only - skip the first character, and a function call - cannot be that short. */ - escape = 1; - /* Nested quotes can appear at function calls. */ - call_end = get_end_of_call(raw, ptr, size); - } - /* " is the quote symbol. */ - else if (quote) quote = (c != '"'); - else if (c == '"') quote = 1; - /* End of argument? */ - else if (strchr(" )", c)) - { - ptr--; - break; + size_t size = strlen(raw), ptr = 0, call_end = 0; + int escape = 0, quote = 0, saved_errno; + char *raw_argument = NULL; + char c; + + /* Find the span of the argument. */ + while (ptr < size) { + c = raw[ptr++]; + + /* Escapes may be longer than one character, + but only the first can affect the parsing. */ + if (escape) + escape = 0; + /* Nested function and nested quotes can appear. */ + else if (ptr <= call_end) + ; + /* Quotes end with the same symbols as they start with, + and quotes automatically escape brackets. */ + /* \ can either start a functon call or an escape. */ + else if (c == '\\') { + /* It may not be an escape, but registering it + as an escape cannot harm us since we only + skip the first character, and a function call + cannot be that short. */ + escape = 1; + /* Nested quotes can appear at function calls. */ + call_end = get_end_of_call(raw, ptr, size); + } + /* " is the quote symbol. */ + else if (quote) + quote = (c != '"'); + else if (c == '"') + quote = 1; + /* End of argument? */ + else if (strchr(" )", c)) { + ptr--; + break; + } } - } - *end = raw + ptr; - - /* Copy the argument so that we have a NUL-terminates string. */ - fail_if (xmalloc(raw_argument, ptr + 1, char)); - memcpy(raw_argument, raw, ptr * sizeof(char)); - raw_argument[ptr] = '\0'; - - /* Evaluate argument. */ - *value = parse_string(tree, raw_argument, lineoff); - fail_if (*value == NULL); - - free(raw_argument); - return 0; - FAIL_BEGIN; - free(raw_argument); - FAIL_END; + *end = raw + ptr; + + /* Copy the argument so that we have a NUL-terminates string. */ + fail_if (xmalloc(raw_argument, ptr + 1, char)); + memcpy(raw_argument, raw, ptr * sizeof(char)); + raw_argument[ptr] = '\0'; + + /* Evaluate argument. */ + *value = parse_string(tree, raw_argument, lineoff); + fail_if (!*value); + + free(raw_argument); + return 0; + FAIL_BEGIN; + free(raw_argument); + FAIL_END; } @@ -1209,13 +1169,13 @@ static int parse_function_argument(mds_kbdc_tree_t* restrict tree, const char* r * @param macro_include_stack The include-stack for the macro * @return Zero on success, -1 on error */ -static int set_macro(mds_kbdc_tree_macro_t* restrict macro, - mds_kbdc_include_stack_t* macro_include_stack) +static int +set_macro(mds_kbdc_tree_macro_t *restrict macro, mds_kbdc_include_stack_t *macro_include_stack) { - fail_if (callables_set(macro->name, 0, (mds_kbdc_tree_t*)macro, macro_include_stack)); - return 0; - fail: - return -1; + fail_if (callables_set(macro->name, 0, (mds_kbdc_tree_t *)macro, macro_include_stack)); + return 0; +fail: + return -1; } @@ -1226,10 +1186,11 @@ static int set_macro(mds_kbdc_tree_macro_t* restrict macro, * @param macro Output parameter for the macro, `NULL` if not found * @param macro_include_stack Output parameter for the include-stack for the macro */ -static void get_macro_lax(const char* restrict macro_name, mds_kbdc_tree_macro_t** restrict macro, - mds_kbdc_include_stack_t** restrict macro_include_stack) +static void +get_macro_lax(const char *restrict macro_name, mds_kbdc_tree_macro_t **restrict macro, + mds_kbdc_include_stack_t **restrict macro_include_stack) { - callables_get(macro_name, 0, (mds_kbdc_tree_t**)macro, macro_include_stack); + callables_get(macro_name, 0, (mds_kbdc_tree_t **)macro, macro_include_stack); } @@ -1246,29 +1207,29 @@ static void get_macro_lax(const char* restrict macro_name, mds_kbdc_tree_macro_t * @param macro_include_stack Output parameter for the include-stack for the macro * @return Zero on success, -1 on error */ -static int get_macro(mds_kbdc_tree_macro_call_t* restrict macro_call, - mds_kbdc_tree_macro_t** restrict macro, - mds_kbdc_include_stack_t** restrict macro_include_stack) +static int +get_macro(mds_kbdc_tree_macro_call_t *restrict macro_call, + mds_kbdc_tree_macro_t **restrict macro, + mds_kbdc_include_stack_t **restrict macro_include_stack) { - char* code = result->source_code->lines[macro_call->loc_line]; - char* end = code + strlen(code) - 1; - - get_macro_lax(macro_call->name, macro, macro_include_stack); - if (*macro == NULL) - { - NEW_ERROR(macro_call, ERROR, "macro ‘%s’ has not been defined yet", macro_call->name); - while (*end == ' ') - end--; - error->end = (size_t)(++end - code); - macro_call->processed = PROCESS_LEVEL; - return 0; - } - if ((*macro)->processed == PROCESS_LEVEL) - *macro = NULL; - - return 0; - fail: - return -1; + char *code = result->source_code->lines[macro_call->loc_line]; + char *end = code + strlen(code) - 1; + + get_macro_lax(macro_call->name, macro, macro_include_stack); + if (!*macro) { + NEW_ERROR(macro_call, ERROR, "macro ‘%s’ has not been defined yet", macro_call->name); + while (*end == ' ') + end--; + error->end = (size_t)(++end - code); + macro_call->processed = PROCESS_LEVEL; + return 0; + } + if ((*macro)->processed == PROCESS_LEVEL) + *macro = NULL; + + return 0; +fail: + return -1; } @@ -1279,20 +1240,21 @@ static int get_macro(mds_kbdc_tree_macro_call_t* restrict macro_call, * @param function_include_stack The include-stack for the function * @return Zero on success, -1 on error */ -static int set_function(mds_kbdc_tree_function_t* restrict function, - mds_kbdc_include_stack_t* function_include_stack) +static int +set_function(mds_kbdc_tree_function_t *restrict function, + mds_kbdc_include_stack_t *function_include_stack) { - char* suffixless = function->name; - char* suffix_start = strchr(suffixless, '/'); - size_t arg_count = atoz(suffix_start + 1); - int r; - - *suffix_start = '\0'; - r = callables_set(suffixless, arg_count, (mds_kbdc_tree_t*)function, function_include_stack); - fail_if (*suffix_start = '/', r); - return 0; - fail: - return -1; + char *suffixless = function->name; + char *suffix_start = strchr(suffixless, '/'); + size_t arg_count = atoz(suffix_start + 1); + int r; + + *suffix_start = '\0'; + r = callables_set(suffixless, arg_count, (mds_kbdc_tree_t *)function, function_include_stack); + fail_if (*suffix_start = '/', r); + return 0; +fail: + return -1; } @@ -1304,11 +1266,12 @@ static int set_function(mds_kbdc_tree_function_t* restrict function, * @param function Output parameter for the function, `NULL` if not found * @param function_include_stack Output parameter for the include-stack for the function */ -static void get_function_lax(const char* restrict function_name, size_t arg_count, - mds_kbdc_tree_function_t** restrict function, - mds_kbdc_include_stack_t** restrict function_include_stack) +static void +get_function_lax(const char *restrict function_name, size_t arg_count, + mds_kbdc_tree_function_t **restrict function, + mds_kbdc_include_stack_t **restrict function_include_stack) { - callables_get(function_name, arg_count, (mds_kbdc_tree_t**)function, function_include_stack); + callables_get(function_name, arg_count, (mds_kbdc_tree_t **)function, function_include_stack); } @@ -1318,21 +1281,23 @@ static void get_function_lax(const char* restrict function_name, size_t arg_coun * @param value The value the function should return * @return Zero on success, 1 if no function is currently being called */ -static int set_return_value(char32_t* restrict value) +static int +set_return_value(char32_t *restrict value) { - if (current_return_value == NULL) - return free(value), 1; - free(*current_return_value); - *current_return_value = value; - return 0; + if (!current_return_value) + return free(value), 1; + free(*current_return_value); + *current_return_value = value; + return 0; } -static int add_mapping(mds_kbdc_tree_map_t* restrict mapping, mds_kbdc_include_stack_t* restrict include_stack) +static int +add_mapping(mds_kbdc_tree_map_t *restrict mapping, mds_kbdc_include_stack_t *restrict include_stack) { - mds_kbdc_tree_free((mds_kbdc_tree_t*)mapping); - mds_kbdc_include_stack_free(include_stack); - return 0; /* TODO */ + mds_kbdc_tree_free((mds_kbdc_tree_t *)mapping); + mds_kbdc_include_stack_free(include_stack); + return 0; /* TODO */ } @@ -1346,23 +1311,24 @@ static int add_mapping(mds_kbdc_tree_map_t* restrict mapping, mds_kbdc_include_s * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_include(mds_kbdc_tree_include_t* restrict tree) +static int +compile_include(mds_kbdc_tree_include_t *restrict tree) { - void* data; - int r; - fail_if (mds_kbdc_include_stack_push(tree, &data)); - r = compile_subtree(tree->inner); - mds_kbdc_include_stack_pop(data); - - /* For simplicity we set `last_value_statement` on includes, - * so we are sure `last_value_statement` has the same - * include-stack as its overriding statement. */ - last_value_statement = NULL; - - fail_if (r); - return 0; - fail: - return -1; + void *data; + int r; + fail_if (mds_kbdc_include_stack_push(tree, &data)); + r = compile_subtree(tree->inner); + mds_kbdc_include_stack_pop(data); + + /* For simplicity we set `last_value_statement` on includes, + * so we are sure `last_value_statement` has the same + * include-stack as its overriding statement. */ + last_value_statement = NULL; + + fail_if (r); + return 0; +fail: + return -1; } @@ -1372,39 +1338,39 @@ static int compile_include(mds_kbdc_tree_include_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_language(mds_kbdc_tree_information_language_t* restrict tree) +static int +compile_language(mds_kbdc_tree_information_language_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict data = NULL; - char** old = NULL; - int saved_errno; - - /* Make sure the language-list fits another entry. */ - if (result->languages_ptr == result->languages_size) - { - result->languages_size = result->languages_size ? (result->languages_size << 1) : 1; - fail_if (xxrealloc(old, result->languages, result->languages_size, char*)); - } - - /* Locate the first character in the language-string. */ - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - /* Evaluate function calls, variable dereferences and escapes in the language-string. */ - fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff), data == NULL); - if (tree->processed == PROCESS_LEVEL) - return free(data), 0; - /* We want the string in UTF-8, not UTF-16. */ - fail_if (code = string_encode(data), code == NULL); - free(data); - - /* Add the language to the language-list. */ - result->languages[result->languages_ptr++] = code; - - return 0; - FAIL_BEGIN; - free(old); - free(data); - FAIL_END; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict data = NULL; + char **old = NULL; + int saved_errno; + + /* Make sure the language-list fits another entry. */ + if (result->languages_ptr == result->languages_size) { + result->languages_size = result->languages_size ? (result->languages_size << 1) : 1; + fail_if (xxrealloc(old, result->languages, result->languages_size, char*)); + } + + /* Locate the first character in the language-string. */ + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + /* Evaluate function calls, variable dereferences and escapes in the language-string. */ + fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff))); + if (tree->processed == PROCESS_LEVEL) + return free(data), 0; + /* We want the string in UTF-8, not UTF-16. */ + fail_if (!(code = string_encode(data))); + free(data); + + /* Add the language to the language-list. */ + result->languages[result->languages_ptr++] = code; + + return 0; + FAIL_BEGIN; + free(old); + free(data); + FAIL_END; } @@ -1414,39 +1380,39 @@ static int compile_language(mds_kbdc_tree_information_language_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_country(mds_kbdc_tree_information_country_t* restrict tree) +static int +compile_country(mds_kbdc_tree_information_country_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict data = NULL; - char** old = NULL; - int saved_errno; - - /* Make sure the country-list fits another entry. */ - if (result->countries_ptr == result->countries_size) - { - result->countries_size = result->countries_size ? (result->countries_size << 1) : 1; - fail_if (xxrealloc(old, result->countries, result->countries_size, char*)); - } - - /* Locate the first character in the country-string. */ - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - /* Evaluate function calls, variable dereferences and escapes in the country-string. */ - fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff), data == NULL); - if (tree->processed == PROCESS_LEVEL) - return free(data), 0; - /* We want the string in UTF-8, not UTF-16. */ - fail_if (code = string_encode(data), code == NULL); - free(data); - - /* Add the country to the country-list. */ - result->countries[result->countries_ptr++] = code; - - return 0; - FAIL_BEGIN; - free(old); - free(data); - FAIL_END; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict data = NULL; + char **old = NULL; + int saved_errno; + + /* Make sure the country-list fits another entry. */ + if (result->countries_ptr == result->countries_size) { + result->countries_size = result->countries_size ? (result->countries_size << 1) : 1; + fail_if (xxrealloc(old, result->countries, result->countries_size, char *)); + } + + /* Locate the first character in the country-string. */ + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + /* Evaluate function calls, variable dereferences and escapes in the country-string. */ + fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff))); + if (tree->processed == PROCESS_LEVEL) + return free(data), 0; + /* We want the string in UTF-8, not UTF-16. */ + fail_if (!(code = string_encode(data))); + free(data); + + /* Add the country to the country-list. */ + result->countries[result->countries_ptr++] = code; + + return 0; + FAIL_BEGIN; + free(old); + free(data); + FAIL_END; } @@ -1456,39 +1422,39 @@ static int compile_country(mds_kbdc_tree_information_country_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_variant(mds_kbdc_tree_information_variant_t* restrict tree) +static int +compile_variant(mds_kbdc_tree_information_variant_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict data = NULL; - int saved_errno; - - /* Make sure the variant has not already been set. */ - if (result->variant) - { - if (multiple_variants == 0) - NEW_ERROR(tree, ERROR, "only one ‘variant’ is allowed"); - multiple_variants = 1; - return 0; - } - - /* Locate the first character in the variant-string. */ - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - /* Evaluate function calls, variable dereferences and escapes in the variant-string. */ - fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff), data == NULL); - if (tree->processed == PROCESS_LEVEL) - return free(data), 0; - /* We want the string in UTF-8, not UTF-16. */ - fail_if (code = string_encode(data), code == NULL); - free(data); - - /* Store the variant. */ - result->variant = code; - - return 0; - FAIL_BEGIN; - free(data); - FAIL_END; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict data = NULL; + int saved_errno; + + /* Make sure the variant has not already been set. */ + if (result->variant) { + if (!multiple_variants) + NEW_ERROR(tree, ERROR, "only one ‘variant’ is allowed"); + multiple_variants = 1; + return 0; + } + + /* Locate the first character in the variant-string. */ + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + /* Evaluate function calls, variable dereferences and escapes in the variant-string. */ + fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff))); + if (tree->processed == PROCESS_LEVEL) + return free(data), 0; + /* We want the string in UTF-8, not UTF-16. */ + fail_if (!(code = string_encode(data))); + free(data); + + /* Store the variant. */ + result->variant = code; + + return 0; + FAIL_BEGIN; + free(data); + FAIL_END; } @@ -1498,54 +1464,50 @@ static int compile_variant(mds_kbdc_tree_information_variant_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_have(mds_kbdc_tree_assumption_have_t* restrict tree) +static int +compile_have(mds_kbdc_tree_assumption_have_t *restrict tree) { - mds_kbdc_tree_t* node = tree->data; - char32_t* data = NULL; - char32_t** old = NULL; - size_t new_size = 0; - int saved_errno; - - /* Make sure we can fit all assumption in the assumption list (part 1/2). */ - new_size = (node->type == C(STRING)) ? result->assumed_strings_size : result->assumed_keys_size; - new_size = new_size ? (new_size << 1) : 1; - - if (node->type == C(STRING)) - { - /* Evaluate function calls, variable dereferences and escapes in the string. */ - fail_if (data = parse_string(node, node->string.string, node->loc_start), data == NULL); - if (node->processed == PROCESS_LEVEL) - return free(data), 0; - /* Make sure we can fit all strings in the assumption list (part 2/2). */ - if (result->assumed_strings_ptr == result->assumed_strings_size) - { - fail_if (xxrealloc(old, result->assumed_strings, new_size, char32_t*)); - result->assumed_strings_size = new_size; + mds_kbdc_tree_t *node = tree->data; + char32_t *data = NULL, **old = NULL; + size_t new_size = 0; + int saved_errno; + + /* Make sure we can fit all assumption in the assumption list (part 1/2). */ + new_size = (node->type == C(STRING)) ? result->assumed_strings_size : result->assumed_keys_size; + new_size = new_size ? (new_size << 1) : 1; + + if (node->type == C(STRING)) { + /* Evaluate function calls, variable dereferences and escapes in the string. */ + fail_if (!(data = parse_string(node, node->string.string, node->loc_start))); + if (node->processed == PROCESS_LEVEL) + return free(data), 0; + /* Make sure we can fit all strings in the assumption list (part 2/2). */ + if (result->assumed_strings_ptr == result->assumed_strings_size) + { + fail_if (xxrealloc(old, result->assumed_strings, new_size, char32_t*)); + result->assumed_strings_size = new_size; + } + /* Add the assumption to the list. */ + result->assumed_strings[result->assumed_strings_ptr++] = data; + } else { + /* Evaluate function calls, variable dereferences and escapes in the key-combination. */ + fail_if (!(data = parse_keys(node, node->keys.keys, node->loc_start))); + if (node->processed == PROCESS_LEVEL) + return free(data), 0; + /* Make sure we can fit all key-combinations in the assumption list (part 2/2). */ + if (result->assumed_keys_ptr == result->assumed_keys_size) { + fail_if (xxrealloc(old, result->assumed_keys, new_size, char32_t*)); + result->assumed_keys_size = new_size; + } + /* Add the assumption to the list. */ + result->assumed_keys[result->assumed_keys_ptr++] = data; } - /* Add the assumption to the list. */ - result->assumed_strings[result->assumed_strings_ptr++] = data; - } - else - { - /* Evaluate function calls, variable dereferences and escapes in the key-combination. */ - fail_if (data = parse_keys(node, node->keys.keys, node->loc_start), data == NULL); - if (node->processed == PROCESS_LEVEL) - return free(data), 0; - /* Make sure we can fit all key-combinations in the assumption list (part 2/2). */ - if (result->assumed_keys_ptr == result->assumed_keys_size) - { - fail_if (xxrealloc(old, result->assumed_keys, new_size, char32_t*)); - result->assumed_keys_size = new_size; - } - /* Add the assumption to the list. */ - result->assumed_keys[result->assumed_keys_ptr++] = data; - } - - return 0; - FAIL_BEGIN; - free(old); - free(data); - FAIL_END; + + return 0; + FAIL_BEGIN; + free(old); + free(data); + FAIL_END; } @@ -1555,47 +1517,46 @@ static int compile_have(mds_kbdc_tree_assumption_have_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_have_chars(mds_kbdc_tree_assumption_have_chars_t* restrict tree) +static int +compile_have_chars(mds_kbdc_tree_assumption_have_chars_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict data = NULL; - char32_t** old = NULL; - char32_t* restrict character; - size_t n; - int saved_errno; - - /* Locate the first character in the list. */ - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - /* Evaluate function calls, variable dereferences - and escapes in the charcter list. */ - fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->chars, lineoff), data == NULL); - if (tree->processed == PROCESS_LEVEL) - return free(data), 0; - - /* Make sure we can fit all characters in the assumption list. */ - for (n = 0; data[n] >= 0; n++); - if (result->assumed_strings_ptr + n > result->assumed_strings_size) - { - result->assumed_strings_size += n; - fail_if (xxrealloc(old, result->assumed_strings, result->assumed_strings_size, char32_t*)); - } - - /* Add all characters to the assumption list. */ - while (n--) - { - fail_if (xmalloc(character, 2, char32_t)); - character[0] = data[n]; - character[1] = -1; - result->assumed_strings[result->assumed_strings_ptr++] = character; - } - - free(data); - return 0; - FAIL_BEGIN; - free(data); - free(old); - FAIL_END; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict data = NULL; + char32_t **old = NULL; + char32_t *restrict character; + size_t n; + int saved_errno; + + /* Locate the first character in the list. */ + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + /* Evaluate function calls, variable dereferences + and escapes in the charcter list. */ + fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->chars, lineoff))); + if (tree->processed == PROCESS_LEVEL) + return free(data), 0; + + /* Make sure we can fit all characters in the assumption list. */ + for (n = 0; data[n] >= 0; n++); + if (result->assumed_strings_ptr + n > result->assumed_strings_size) { + result->assumed_strings_size += n; + fail_if (xxrealloc(old, result->assumed_strings, result->assumed_strings_size, char32_t *)); + } + + /* Add all characters to the assumption list. */ + while (n--) { + fail_if (xmalloc(character, 2, char32_t)); + character[0] = data[n]; + character[1] = -1; + result->assumed_strings[result->assumed_strings_ptr++] = character; + } + + free(data); + return 0; + FAIL_BEGIN; + free(data); + free(old); + FAIL_END; } @@ -1605,88 +1566,85 @@ static int compile_have_chars(mds_kbdc_tree_assumption_have_chars_t* restrict tr * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_have_range(mds_kbdc_tree_assumption_have_range_t* restrict tree) +static int +compile_have_range(mds_kbdc_tree_assumption_have_range_t *restrict tree) { - size_t lineoff_first; - size_t lineoff_last; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict first = NULL; - char32_t* restrict last = NULL; - char32_t** old = NULL; - char32_t* restrict character; - size_t n; - int saved_errno; - - - /* Locate the first characters of both bound strings. */ - for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++); - for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++); - - /* Duplicate bounds and evaluate function calls, - variable dereferences and escapes in the bounds. */ - fail_if (first = parse_string((mds_kbdc_tree_t*)tree, tree->first, lineoff_first), first == NULL); - fail_if (last = parse_string((mds_kbdc_tree_t*)tree, tree->last, lineoff_last), last == NULL); - - /* Did one of the bound not evaluate, then stop. */ - if (tree->processed == PROCESS_LEVEL) - goto done; - - - /* Check that the primary bound is single-character. */ - if ((first[0] == -1) || (first[1] != -1)) - { - NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); - error->start = lineoff_first, lineoff_first = 0; - error->end = error->start + strlen(tree->first); - } - /* Check that the secondary bound is single-character. */ - if ((last[0] == -1) || (last[1] != -1)) - { - NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); - error->start = lineoff_last, lineoff_last = 0; - error->end = error->start + strlen(tree->last); - } - - /* Was one of the bounds not single-character, then stop. */ - if ((lineoff_first == 0) || (lineoff_last == 0)) - goto done; - - - /* If the range is descending, swap the bounds so it is ascending. - (This cannot be done in for-loops as that may cause side-effects - to be created in the wrong order.) */ - if (*first > *last) - *first ^= *last, *last ^= *first, *first ^= *last; - - /* Make sure we can fit all characters in the assumption list. */ - n = (size_t)(*last - *first) + 1; - if (result->assumed_strings_ptr + n > result->assumed_strings_size) - { - result->assumed_strings_size += n; - fail_if (xxrealloc(old, result->assumed_strings, result->assumed_strings_size, char32_t*)); - } - - /* Add all characters to the assumption list. */ - for (;;) - { - fail_if (xmalloc(character, 2, char32_t)); - character[0] = *first; - character[1] = -1; - result->assumed_strings[result->assumed_strings_ptr++] = character; - /* Bounds are inclusive. */ - if ((*first)++ == *last) - break; - } - - done: - free(first); - free(last); - return 0; - FAIL_BEGIN; - free(first); - free(last); - free(old); - FAIL_END; + size_t lineoff_first; + size_t lineoff_last; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict first = NULL; + char32_t *restrict last = NULL; + char32_t **old = NULL; + char32_t *restrict character; + size_t n; + int saved_errno; + + + /* Locate the first characters of both bound strings. */ + for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++); + for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++); + + /* Duplicate bounds and evaluate function calls, + variable dereferences and escapes in the bounds. */ + fail_if (!(first = parse_string((mds_kbdc_tree_t*)tree, tree->first, lineoff_first))); + fail_if (!(last = parse_string((mds_kbdc_tree_t*)tree, tree->last, lineoff_last))); + + /* Did one of the bound not evaluate, then stop. */ + if (tree->processed == PROCESS_LEVEL) + goto done; + + + /* Check that the primary bound is single-character. */ + if (first[0] == -1 || first[1] != -1) { + NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); + error->start = lineoff_first, lineoff_first = 0; + error->end = error->start + strlen(tree->first); + } + /* Check that the secondary bound is single-character. */ + if (last[0] == -1 || last[1] != -1) { + NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); + error->start = lineoff_last, lineoff_last = 0; + error->end = error->start + strlen(tree->last); + } + + /* Was one of the bounds not single-character, then stop. */ + if (!lineoff_first || !lineoff_last) + goto done; + + + /* If the range is descending, swap the bounds so it is ascending. + (This cannot be done in for-loops as that may cause side-effects + to be created in the wrong order.) */ + if (*first > *last) + *first ^= *last, *last ^= *first, *first ^= *last; + + /* Make sure we can fit all characters in the assumption list. */ + n = (size_t)(*last - *first) + 1; + if (result->assumed_strings_ptr + n > result->assumed_strings_size) { + result->assumed_strings_size += n; + fail_if (xxrealloc(old, result->assumed_strings, result->assumed_strings_size, char32_t *)); + } + + /* Add all characters to the assumption list. */ + for (;;) { + fail_if (xmalloc(character, 2, char32_t)); + character[0] = *first; + character[1] = -1; + result->assumed_strings[result->assumed_strings_ptr++] = character; + /* Bounds are inclusive. */ + if ((*first)++ == *last) + break; + } + +done: + free(first); + free(last); + return 0; + FAIL_BEGIN; + free(first); + free(last); + free(old); + FAIL_END; } @@ -1696,47 +1654,48 @@ static int compile_have_range(mds_kbdc_tree_assumption_have_range_t* restrict tr * @param tree The tree to evaluate * @return Zero on success, -1 on error, 1 if an undefined macro is used */ -static int check_marco_calls(mds_kbdc_tree_t* restrict tree) +static int +check_marco_calls(mds_kbdc_tree_t *restrict tree) { -#define t(...) fail_if (rc |= r = (__VA_ARGS__), r < 0) - mds_kbdc_tree_macro_t* _macro; - mds_kbdc_include_stack_t* _macro_include_stack; - void* data; - int r, rc = 0; - again: - if (tree == NULL) - return rc; - - switch (tree->type) - { - case C(INCLUDE): - t (mds_kbdc_include_stack_push(&(tree->include), &data)); - t (r = check_marco_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r); - break; - - case C(FOR): - t (check_marco_calls(tree->for_.inner)); - break; - - case C(IF): - t (check_marco_calls(tree->if_.inner)); - t (check_marco_calls(tree->if_.otherwise)); - break; - - case C(MACRO_CALL): - t (get_macro(&(tree->macro_call), &_macro, &_macro_include_stack)); - break; - - default: - break; - } - - tree = tree->next; - goto again; - fail: - return -1; - (void) _macro; - (void) _macro_include_stack; +#define t(...) fail_if (rc |= r = (__VA_ARGS__), r < 0) + mds_kbdc_tree_macro_t *_macro; + mds_kbdc_include_stack_t *_macro_include_stack; + void *data; + int r, rc = 0; + +again: + if (!tree) + return rc; + + switch (tree->type) { + case C(INCLUDE): + t (mds_kbdc_include_stack_push(&(tree->include), &data)); + t (r = check_marco_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r); + break; + + case C(FOR): + t (check_marco_calls(tree->for_.inner)); + break; + + case C(IF): + t (check_marco_calls(tree->if_.inner)); + t (check_marco_calls(tree->if_.otherwise)); + break; + + case C(MACRO_CALL): + t (get_macro(&(tree->macro_call), &_macro, &_macro_include_stack)); + break; + + default: + break; + } + + tree = tree->next; + goto again; +fail: + return -1; + (void) _macro; + (void) _macro_include_stack; #undef t } @@ -1747,24 +1706,25 @@ static int check_marco_calls(mds_kbdc_tree_t* restrict tree) * @param tree The tree to evaluate * @return Zero on success, -1 on error, 1 if an undefined function is used */ -static int check_function_calls_in_for(const mds_kbdc_tree_for_t* restrict tree) +static int +check_function_calls_in_for(const mds_kbdc_tree_for_t *restrict tree) { -#define t(...) fail_if (rc |= r = check_function_calls_in_literal(__VA_ARGS__), r < 0) - size_t lineoff_first; - size_t lineoff_last; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - int r, rc = 0; - - for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++); - for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++); - for (lineoff_last += strlen("to"); code[lineoff_last] == ' '; lineoff_last++); - - t ((const mds_kbdc_tree_t*)tree, tree->first, lineoff_first); - t ((const mds_kbdc_tree_t*)tree, tree->last, lineoff_last); - - return rc; - fail: - return -1; +#define t(...) fail_if (rc |= r = check_function_calls_in_literal(__VA_ARGS__), r < 0) + size_t lineoff_first; + size_t lineoff_last; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + int r, rc = 0; + + for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++); + for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++); + for (lineoff_last += strlen("to"); code[lineoff_last] == ' '; lineoff_last++); + + t ((const mds_kbdc_tree_t *)tree, tree->first, lineoff_first); + t ((const mds_kbdc_tree_t *)tree, tree->last, lineoff_last); + + return rc; +fail: + return -1; #undef t } @@ -1775,17 +1735,18 @@ static int check_function_calls_in_for(const mds_kbdc_tree_for_t* restrict tree) * @param tree The tree to evaluate * @return Zero on success, -1 on error, 1 if an undefined function is used */ -static int check_function_calls_in_if(const mds_kbdc_tree_if_t* restrict tree) +static int +check_function_calls_in_if(const mds_kbdc_tree_if_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - int r; - - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - r = check_function_calls_in_literal((const mds_kbdc_tree_t*)tree, tree->condition, lineoff); - fail_if (r < 0); - fail: - return r; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + int r; + + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + r = check_function_calls_in_literal((const mds_kbdc_tree_t *)tree, tree->condition, lineoff); + fail_if (r < 0); +fail: + return r; } @@ -1795,13 +1756,14 @@ static int check_function_calls_in_if(const mds_kbdc_tree_if_t* restrict tree) * @param tree The tree to evaluate * @return Zero on success, -1 on error, 1 if an undefined function is used */ -static int check_function_calls_in_keys(const mds_kbdc_tree_keys_t* restrict tree) +static int +check_function_calls_in_keys(const mds_kbdc_tree_keys_t *restrict tree) { - int r; - r = check_function_calls_in_literal((const mds_kbdc_tree_t*)tree, tree->keys, tree->loc_start); - fail_if (r < 0); - fail: - return r; + int r; + r = check_function_calls_in_literal((const mds_kbdc_tree_t *)tree, tree->keys, tree->loc_start); + fail_if (r < 0); +fail: + return r; } @@ -1811,13 +1773,14 @@ static int check_function_calls_in_keys(const mds_kbdc_tree_keys_t* restrict tre * @param tree The tree to evaluate * @return Zero on success, -1 on error, 1 if an undefined function is used */ -static int check_function_calls_in_string(const mds_kbdc_tree_string_t* restrict tree) +static int +check_function_calls_in_string(const mds_kbdc_tree_string_t *restrict tree) { - int r; - r = check_function_calls_in_literal((const mds_kbdc_tree_t*)tree, tree->string, tree->loc_start); - fail_if (r < 0); - fail: - return r; + int r; + r = check_function_calls_in_literal((const mds_kbdc_tree_t *)tree, tree->string, tree->loc_start); + fail_if (r < 0); +fail: + return r; } @@ -1827,46 +1790,47 @@ static int check_function_calls_in_string(const mds_kbdc_tree_string_t* restrict * @param tree The tree to evaluate * @return Zero on success, -1 on error, 1 if an undefined function is used */ -static int check_function_calls(const mds_kbdc_tree_t* restrict tree) +static int +check_function_calls(const mds_kbdc_tree_t *restrict tree) { -#define t(...) fail_if (rc |= r = (__VA_ARGS__), r < 0) - void* data; - int r, rc = 0; - again: - if (tree == NULL) - return rc; - - switch (tree->type) - { - case C(INCLUDE): - t (mds_kbdc_include_stack_push(&(tree->include), &data)); - t (r = check_function_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r); - break; - - case C(FOR): - t (check_function_calls_in_for(&(tree->for_))); - t (check_function_calls(tree->for_.inner)); - break; - - case C(IF): - t (check_function_calls_in_if(&(tree->if_))); - t (check_function_calls(tree->if_.inner)); - t (check_function_calls(tree->if_.otherwise)); - break; - - case C(LET): t (check_function_calls(tree->let.value)); break; - case C(ARRAY): t (check_function_calls(tree->array.elements)); break; - case C(KEYS): t (check_function_calls_in_keys(&(tree->keys))); break; - case C(STRING): t (check_function_calls_in_string(&(tree->string))); break; - case C(MAP): t (check_function_calls(tree->map.sequence)); break; - default: - break; - } - - tree = tree->next; - goto again; - fail: - return -1; +#define t(...) fail_if (rc |= r = (__VA_ARGS__), r < 0) + void *data; + int r, rc = 0; + +again: + if (!tree) + return rc; + + switch (tree->type) { + case C(INCLUDE): + t (mds_kbdc_include_stack_push(&(tree->include), &data)); + t (r = check_function_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r); + break; + + case C(FOR): + t (check_function_calls_in_for(&(tree->for_))); + t (check_function_calls(tree->for_.inner)); + break; + + case C(IF): + t (check_function_calls_in_if(&(tree->if_))); + t (check_function_calls(tree->if_.inner)); + t (check_function_calls(tree->if_.otherwise)); + break; + + case C(LET): t (check_function_calls(tree->let.value)); break; + case C(ARRAY): t (check_function_calls(tree->array.elements)); break; + case C(KEYS): t (check_function_calls_in_keys(&(tree->keys))); break; + case C(STRING): t (check_function_calls_in_string(&(tree->string))); break; + case C(MAP): t (check_function_calls(tree->map.sequence)); break; + default: + break; + } + + tree = tree->next; + goto again; +fail: + return -1; #undef t } @@ -1877,52 +1841,50 @@ static int check_function_calls(const mds_kbdc_tree_t* restrict tree) * @param tree The tree to inspect * @return Zero on sucess, -1 on error, 1 if the name-suffix in invalid */ -static int check_name_suffix(struct mds_kbdc_tree_callable* restrict tree) +static int +check_name_suffix(struct mds_kbdc_tree_callable *restrict tree) { - const char* restrict name = strchr(tree->name, '/'); - const char* restrict code = result->source_code->real_lines[tree->loc_line]; - - /* A "/" must exist in the name to tell us how many parameters there are. */ - if (name == NULL) - { - NEW_ERROR(tree, ERROR, "name-suffix is missing"); - goto name_error; - } - /* Do not let the suffix by just "/". */ - if (*++name == '\0') - { - NEW_ERROR(tree, ERROR, "empty name-suffix"); - goto name_error; - } - - /* We are all good if the suffix is simply "/0" */ - if (!strcmp(name, "0")) - return 0; - - /* The suffix may not have leading zeroes. */ - if (*name == '0') - { - NEW_ERROR(tree, ERROR, "leading zero in name-suffix"); - goto name_error; - } - /* The suffix must be a decimal, non-negative number. */ - for (; *name; name++) - if ((*name < '0') || ('9' < *name)) - { - NEW_ERROR(tree, ERROR, "name-suffix may only contain digits"); - goto name_error; - } - - return 0; - fail: - return -1; - name_error: - error->start = tree->loc_end; - while (code[error->start] == ' ') - error->start++; - error->end = error->start + strlen(tree->name); - tree->processed = PROCESS_LEVEL; - return 1; + const char *restrict name = strchr(tree->name, '/'); + const char *restrict code = result->source_code->real_lines[tree->loc_line]; + + /* A "/" must exist in the name to tell us how many parameters there are. */ + if (!name) { + NEW_ERROR(tree, ERROR, "name-suffix is missing"); + goto name_error; + } + /* Do not let the suffix by just "/". */ + if (!*++name) { + NEW_ERROR(tree, ERROR, "empty name-suffix"); + goto name_error; + } + + /* We are all good if the suffix is simply "/0" */ + if (!strcmp(name, "0")) + return 0; + + /* The suffix may not have leading zeroes. */ + if (*name == '0') { + NEW_ERROR(tree, ERROR, "leading zero in name-suffix"); + goto name_error; + } + /* The suffix must be a decimal, non-negative number. */ + for (; *name; name++) { + if (*name < '0' || '9' < *name) { + NEW_ERROR(tree, ERROR, "name-suffix may only contain digits"); + goto name_error; + } + } + + return 0; +fail: + return -1; +name_error: + error->start = tree->loc_end; + while (code[error->start] == ' ') + error->start++; + error->end = error->start + strlen(tree->name); + tree->processed = PROCESS_LEVEL; + return 1; } @@ -1932,67 +1894,67 @@ static int check_name_suffix(struct mds_kbdc_tree_callable* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_function(mds_kbdc_tree_function_t* restrict tree) +static int +compile_function(mds_kbdc_tree_function_t *restrict tree) { -#define t(expr) fail_if (r = (expr), r < 0); if (r) tree->processed = PROCESS_LEVEL - mds_kbdc_tree_function_t* function; - mds_kbdc_include_stack_t* function_include_stack; - mds_kbdc_include_stack_t* our_include_stack = NULL; - char* suffixless; - char* suffix_start = NULL; - size_t arg_count; - int r, saved_errno; - - /* Check that the suffix if properly formatted. */ - t (check_name_suffix((struct mds_kbdc_tree_callable*)tree)); - if (r) return 0; - - /* Get the function's name without suffix, and parse the suffix. */ - suffixless = tree->name; - suffix_start = strchr(suffixless, '/'); - *suffix_start++ = '\0'; - arg_count = atoz(suffix_start--); - - /* Check that the function is not already defined as a builtin function. */ - if (builtin_function_defined(suffixless, arg_count)) - { - NEW_ERROR(tree, ERROR, "function ‘%s/%zu’ is already defined as a builtin function", - tree->name, arg_count); - *suffix_start = '/'; - return 0; - } - /* Check that the function is not already defined, - the include-stack is used in the error-clause as - well as later when we list the function as defined. */ - get_function_lax(suffixless, arg_count, &function, &function_include_stack); - fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL); - if (function) - { - *suffix_start = '/'; - NEW_ERROR(tree, ERROR, "function ‘%s’ is already defined", tree->name); - fail_if (mds_kbdc_include_stack_restore(function_include_stack)); - NEW_ERROR(function, NOTE, "previously defined here"); - fail_if (mds_kbdc_include_stack_restore(our_include_stack)); - mds_kbdc_include_stack_free(our_include_stack); - return 0; - } - - /* Check the the function does not call macros or functions - * before they are defined, otherwise they may get defined - * between the definition of the function and calls to it. */ - t (check_marco_calls(tree->inner)); - t (check_function_calls(tree->inner)); - - /* List the function as defined. */ - *suffix_start = '/', suffix_start = NULL; - t (set_function(tree, our_include_stack)); - - return 0; - FAIL_BEGIN; - if (suffix_start) - *suffix_start = '/'; - mds_kbdc_include_stack_free(our_include_stack); - FAIL_END; +#define t(expr) do { fail_if (r = (expr), r < 0); if (r) tree->processed = PROCESS_LEVEL; } while (0) + mds_kbdc_tree_function_t *function; + mds_kbdc_include_stack_t *function_include_stack; + mds_kbdc_include_stack_t *our_include_stack = NULL; + char *suffixless; + char *suffix_start = NULL; + size_t arg_count; + int r, saved_errno; + + /* Check that the suffix if properly formatted. */ + t (check_name_suffix((struct mds_kbdc_tree_callable*)tree)); + if (r) + return 0; + + /* Get the function's name without suffix, and parse the suffix. */ + suffixless = tree->name; + suffix_start = strchr(suffixless, '/'); + *suffix_start++ = '\0'; + arg_count = atoz(suffix_start--); + + /* Check that the function is not already defined as a builtin function. */ + if (builtin_function_defined(suffixless, arg_count)) { + NEW_ERROR(tree, ERROR, "function ‘%s/%zu’ is already defined as a builtin function", + tree->name, arg_count); + *suffix_start = '/'; + return 0; + } + /* Check that the function is not already defined, + the include-stack is used in the error-clause as + well as later when we list the function as defined. */ + get_function_lax(suffixless, arg_count, &function, &function_include_stack); + fail_if (!(our_include_stack = mds_kbdc_include_stack_save(), our_include_stack)); + if (function) { + *suffix_start = '/'; + NEW_ERROR(tree, ERROR, "function ‘%s’ is already defined", tree->name); + fail_if (mds_kbdc_include_stack_restore(function_include_stack)); + NEW_ERROR(function, NOTE, "previously defined here"); + fail_if (mds_kbdc_include_stack_restore(our_include_stack)); + mds_kbdc_include_stack_free(our_include_stack); + return 0; + } + + /* Check the the function does not call macros or functions + * before they are defined, otherwise they may get defined + * between the definition of the function and calls to it. */ + t (check_marco_calls(tree->inner)); + t (check_function_calls(tree->inner)); + + /* List the function as defined. */ + *suffix_start = '/', suffix_start = NULL; + t (set_function(tree, our_include_stack)); + + return 0; + FAIL_BEGIN; + if (suffix_start) + *suffix_start = '/'; + mds_kbdc_include_stack_free(our_include_stack); + FAIL_END; #undef t } @@ -2003,46 +1965,47 @@ static int compile_function(mds_kbdc_tree_function_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_macro(mds_kbdc_tree_macro_t* restrict tree) +static int +compile_macro(mds_kbdc_tree_macro_t *restrict tree) { -#define t(expr) fail_if (r = (expr), r < 0); if (r) tree->processed = PROCESS_LEVEL - mds_kbdc_tree_macro_t* macro; - mds_kbdc_include_stack_t* macro_include_stack; - mds_kbdc_include_stack_t* our_include_stack = NULL; - int r, saved_errno; - - /* Check that the suffix if properly formatted. */ - t (check_name_suffix((struct mds_kbdc_tree_callable*)tree)); - if (r) return 0; - - /* Check that the macro is not already defined, - the include-stack is used in the error-clause as - well as later when we list the macro as defined. */ - fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL); - get_macro_lax(tree->name, ¯o, ¯o_include_stack); - if (macro) - { - NEW_ERROR(tree, ERROR, "macro ‘%s’ is already defined", tree->name); - fail_if (mds_kbdc_include_stack_restore(macro_include_stack)); - NEW_ERROR(macro, NOTE, "previously defined here"); - fail_if (mds_kbdc_include_stack_restore(our_include_stack)); - mds_kbdc_include_stack_free(our_include_stack); - return 0; - } - - /* Check the the macro does not call macros or functions - * before they are defined, otherwise they may get defined - * between the definition of the macro and calls to it. */ - t (check_marco_calls(tree->inner)); - t (check_function_calls(tree->inner)); - - /* List the macro as defined. */ - t (set_macro(tree, our_include_stack)); - - return 0; - FAIL_BEGIN; - mds_kbdc_include_stack_free(our_include_stack); - FAIL_END; +#define t(expr) do { fail_if (r = (expr), r < 0); if (r) tree->processed = PROCESS_LEVEL; } while (0) + mds_kbdc_tree_macro_t *macro; + mds_kbdc_include_stack_t *macro_include_stack; + mds_kbdc_include_stack_t *our_include_stack = NULL; + int r, saved_errno; + + /* Check that the suffix if properly formatted. */ + t (check_name_suffix((struct mds_kbdc_tree_callable*)tree)); + if (r) + return 0; + + /* Check that the macro is not already defined, + the include-stack is used in the error-clause as + well as later when we list the macro as defined. */ + fail_if (!(our_include_stack = mds_kbdc_include_stack_save())); + get_macro_lax(tree->name, ¯o, ¯o_include_stack); + if (macro) { + NEW_ERROR(tree, ERROR, "macro ‘%s’ is already defined", tree->name); + fail_if (mds_kbdc_include_stack_restore(macro_include_stack)); + NEW_ERROR(macro, NOTE, "previously defined here"); + fail_if (mds_kbdc_include_stack_restore(our_include_stack)); + mds_kbdc_include_stack_free(our_include_stack); + return 0; + } + + /* Check the the macro does not call macros or functions + * before they are defined, otherwise they may get defined + * between the definition of the macro and calls to it. */ + t (check_marco_calls(tree->inner)); + t (check_function_calls(tree->inner)); + + /* List the macro as defined. */ + t (set_macro(tree, our_include_stack)); + + return 0; + FAIL_BEGIN; + mds_kbdc_include_stack_free(our_include_stack); + FAIL_END; #undef t } @@ -2053,94 +2016,92 @@ static int compile_macro(mds_kbdc_tree_macro_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_for(mds_kbdc_tree_for_t* restrict tree) +static int +compile_for(mds_kbdc_tree_for_t *restrict tree) { - size_t lineoff_first; - size_t lineoff_last; - size_t lineoff_var; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict first = NULL; - char32_t* restrict last = NULL; - char32_t diff; - char32_t character[2]; - size_t variable; - int possible_shadow = 1, saved_errno; - - - last_value_statement = NULL; - - - /* Locate the first character of the primary bound's string. */ - for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++); - /* Locate the first character of the secondary bound's string. */ - for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++); - for (lineoff_last += strlen("to"); code[lineoff_last] == ' '; lineoff_last++); - /* Locate the first character of the select variable. */ - for (lineoff_var = lineoff_last + strlen(tree->last); code[lineoff_var] == ' '; lineoff_var++); - for (lineoff_var += strlen("as"); code[lineoff_var] == ' '; lineoff_var++); - - /* Duplicate bounds and evaluate function calls, - variable dereferences and escapes in the bounds. */ - fail_if (first = parse_string((mds_kbdc_tree_t*)tree, tree->first, lineoff_first), first == NULL); - fail_if (last = parse_string((mds_kbdc_tree_t*)tree, tree->last, lineoff_last), last == NULL); - /* Get the index of the selected variable. */ - fail_if (variable = parse_variable((mds_kbdc_tree_t*)tree, tree->variable, lineoff_var), variable == 0); - - /* Did one of the bound not evaluate, then stop. */ - if (tree->processed == PROCESS_LEVEL) - goto done; - - - /* Check that the primary bound is single-character. */ - if ((first[0] == -1) || (first[1] != -1)) - { - NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); - error->start = lineoff_first, lineoff_first = 0; - error->end = error->start + strlen(tree->first); - } - /* Check that the secondary bound is single-character. */ - if ((last[0] == -1) || (last[1] != -1)) - { - NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); - error->start = lineoff_last, lineoff_last = 0; - error->end = error->start + strlen(tree->last); - } - - /* Was one of the bounds not single-character, then stop. */ - if ((lineoff_first == 0) || (lineoff_last == 0)) - goto done; - - - /* Iterate over the loop for as long as a `return` or `break` has not - been encountered (without being caught elsewhere). */ - character[1] = -1; - for (diff = (*first > *last) ? -1 : +1; break_level < 2; *first += diff) - { - break_level = 0; - character[0] = *first; - fail_if (let(variable, character, NULL, (mds_kbdc_tree_t*)tree, lineoff_var, possible_shadow)); - possible_shadow = 0; - fail_if (compile_subtree(tree->inner)); - /* Bounds are inclusive. */ - if (*first == *last) - break; - } - fail_if (variables_was_used_in_for(variable)); - - /* Catch `break` and `continue`, they may not propagate further. */ - if (break_level < 3) - break_level = 0; - - - done: - last_value_statement = NULL; - free(first); - free(last); - return 0; - FAIL_BEGIN; - free(first); - free(last); - FAIL_END; + size_t lineoff_first; + size_t lineoff_last; + size_t lineoff_var; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict first = NULL; + char32_t *restrict last = NULL; + char32_t diff; + char32_t character[2]; + size_t variable; + int possible_shadow = 1, saved_errno; + + + last_value_statement = NULL; + + + /* Locate the first character of the primary bound's string. */ + for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++); + /* Locate the first character of the secondary bound's string. */ + for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++); + for (lineoff_last += strlen("to"); code[lineoff_last] == ' '; lineoff_last++); + /* Locate the first character of the select variable. */ + for (lineoff_var = lineoff_last + strlen(tree->last); code[lineoff_var] == ' '; lineoff_var++); + for (lineoff_var += strlen("as"); code[lineoff_var] == ' '; lineoff_var++); + + /* Duplicate bounds and evaluate function calls, + variable dereferences and escapes in the bounds. */ + fail_if (!(first = parse_string((mds_kbdc_tree_t*)tree, tree->first, lineoff_first))); + fail_if (!(last = parse_string((mds_kbdc_tree_t*)tree, tree->last, lineoff_last))); + /* Get the index of the selected variable. */ + fail_if (variable = parse_variable((mds_kbdc_tree_t*)tree, tree->variable, lineoff_var), variable == 0); + + /* Did one of the bound not evaluate, then stop. */ + if (tree->processed == PROCESS_LEVEL) + goto done; + + + /* Check that the primary bound is single-character. */ + if (first[0] == -1 || first[1] != -1) { + NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); + error->start = lineoff_first, lineoff_first = 0; + error->end = error->start + strlen(tree->first); + } + /* Check that the secondary bound is single-character. */ + if (last[0] == -1 || last[1] != -1) { + NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); + error->start = lineoff_last, lineoff_last = 0; + error->end = error->start + strlen(tree->last); + } + + /* Was one of the bounds not single-character, then stop. */ + if (!lineoff_first || !lineoff_last) + goto done; + + + /* Iterate over the loop for as long as a `return` or `break` has not + been encountered (without being caught elsewhere). */ + character[1] = -1; + for (diff = (*first > *last) ? -1 : +1; break_level < 2; *first += diff) { + break_level = 0; + character[0] = *first; + fail_if (let(variable, character, NULL, (mds_kbdc_tree_t*)tree, lineoff_var, possible_shadow)); + possible_shadow = 0; + fail_if (compile_subtree(tree->inner)); + /* Bounds are inclusive. */ + if (*first == *last) + break; + } + fail_if (variables_was_used_in_for(variable)); + + /* Catch `break` and `continue`, they may not propagate further. */ + if (break_level < 3) + break_level = 0; + + +done: + last_value_statement = NULL; + free(first); + free(last); + return 0; + FAIL_BEGIN; + free(first); + free(last); + FAIL_END; } @@ -2150,36 +2111,37 @@ static int compile_for(mds_kbdc_tree_for_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_if(mds_kbdc_tree_if_t* restrict tree) +static int +compile_if(mds_kbdc_tree_if_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict data = NULL; - int ok, saved_errno; - size_t i; - - last_value_statement = NULL; - - /* Locate the first character in the condition. */ - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - /* Evaluate function calls, variable dereferences and escapes in the condition. */ - fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->condition, lineoff), data == NULL); - if (tree->processed == PROCESS_LEVEL) - return free(data), 0; - - /* Evaluate whether the evaluted value is true. */ - for (ok = 1, i = 0; data[i] >= 0; i++) - ok &= !!(data[i]); - free(data), data = NULL;; - - /* Compile the appropriate clause. */ - ok = compile_subtree(ok ? tree->inner : tree->otherwise); - last_value_statement = NULL; - fail_if (ok < 0); - return 0; - FAIL_BEGIN; - free(data); - FAIL_END; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict data = NULL; + int ok, saved_errno; + size_t i; + + last_value_statement = NULL; + + /* Locate the first character in the condition. */ + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + /* Evaluate function calls, variable dereferences and escapes in the condition. */ + fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->condition, lineoff))); + if (tree->processed == PROCESS_LEVEL) + return free(data), 0; + + /* Evaluate whether the evaluted value is true. */ + for (ok = 1, i = 0; data[i] >= 0; i++) + ok &= !!(data[i]); + free(data), data = NULL;; + + /* Compile the appropriate clause. */ + ok = compile_subtree(ok ? tree->inner : tree->otherwise); + last_value_statement = NULL; + fail_if (ok < 0); + return 0; + FAIL_BEGIN; + free(data); + FAIL_END; } @@ -2189,35 +2151,36 @@ static int compile_if(mds_kbdc_tree_if_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_let(mds_kbdc_tree_let_t* restrict tree) +static int +compile_let(mds_kbdc_tree_let_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - mds_kbdc_tree_t* value = NULL; - size_t variable; - int saved_errno; - - /* Get the index of the selected variable. */ - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - fail_if (variable = parse_variable((mds_kbdc_tree_t*)tree, tree->variable, lineoff), variable == 0); - if (tree->processed == PROCESS_LEVEL) - return 0; - - /* Duplicate arguments and evaluate function calls, - variable dereferences and escapes in the value. */ - fail_if (value = mds_kbdc_tree_dup(tree->value), value == NULL); - fail_if (compile_subtree(value)); - if ((tree->processed = value->processed) == PROCESS_LEVEL) - return mds_kbdc_tree_free(value), 0; - - /* Set the value of the variable. */ - fail_if (let(variable, NULL, value, NULL, 0, 0)); - - mds_kbdc_tree_free(value); - return 0; - FAIL_BEGIN; - free(value); - FAIL_END; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + mds_kbdc_tree_t* value = NULL; + size_t variable; + int saved_errno; + + /* Get the index of the selected variable. */ + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + fail_if (!(variable = parse_variable((mds_kbdc_tree_t *)tree, tree->variable, lineoff))); + if (tree->processed == PROCESS_LEVEL) + return 0; + + /* Duplicate arguments and evaluate function calls, + variable dereferences and escapes in the value. */ + fail_if (!(value = mds_kbdc_tree_dup(tree->value))); + fail_if (compile_subtree(value)); + if ((tree->processed = value->processed) == PROCESS_LEVEL) + return mds_kbdc_tree_free(value), 0; + + /* Set the value of the variable. */ + fail_if (let(variable, NULL, value, NULL, 0, 0)); + + mds_kbdc_tree_free(value); + return 0; + FAIL_BEGIN; + free(value); + FAIL_END; } @@ -2237,26 +2200,26 @@ static int compile_let(mds_kbdc_tree_let_t* restrict tree) * @param node The element to evaluate * @return Zero on success, -1 on error, 1 if the element is invalid */ -static int evaluate_element(mds_kbdc_tree_t* restrict node) +static int +evaluate_element(mds_kbdc_tree_t *restrict node) { - char32_t* restrict data = NULL; - int bad = 0; - - for (; node; node = node->next) - { - if (node->type == C(STRING)) - fail_if (data = parse_string(node, node->string.string, node->loc_start), data == NULL); - if (node->type == C(KEYS)) - fail_if (data = parse_keys(node, node->keys.keys, node->loc_start), data == NULL); - free(node->string.string); - node->type = (node->type == C(STRING)) ? C(COMPILED_STRING) : C(COMPILED_KEYS); - node->compiled_string.string = data; - bad |= (node->processed == PROCESS_LEVEL); - } - - return bad; - fail: - return -1; + char32_t *restrict data = NULL; + int bad = 0; + + for (; node; node = node->next) { + if (node->type == C(STRING)) + fail_if (!(data = parse_string(node, node->string.string, node->loc_start))); + if (node->type == C(KEYS)) + fail_if (!(data = parse_keys(node, node->keys.keys, node->loc_start))); + free(node->string.string); + node->type = (node->type == C(STRING)) ? C(COMPILED_STRING) : C(COMPILED_KEYS); + node->compiled_string.string = data; + bad |= (node->processed == PROCESS_LEVEL); + } + + return bad; +fail: + return -1; } @@ -2266,12 +2229,13 @@ static int evaluate_element(mds_kbdc_tree_t* restrict node) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_keys(mds_kbdc_tree_keys_t* restrict tree) +static int +compile_keys(mds_kbdc_tree_keys_t *restrict tree) { - fail_if (evaluate_element((mds_kbdc_tree_t*)tree) < 0); - return 0; - fail: - return -1; + fail_if (evaluate_element((mds_kbdc_tree_t *)tree) < 0); + return 0; +fail: + return -1; } @@ -2281,12 +2245,13 @@ static int compile_keys(mds_kbdc_tree_keys_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_string(mds_kbdc_tree_string_t* restrict tree) +static int +compile_string(mds_kbdc_tree_string_t *restrict tree) { - fail_if (evaluate_element((mds_kbdc_tree_t*)tree) < 0); - return 0; - fail: - return -1; + fail_if (evaluate_element((mds_kbdc_tree_t *)tree) < 0); + return 0; +fail: + return -1; } @@ -2296,15 +2261,16 @@ static int compile_string(mds_kbdc_tree_string_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_array(mds_kbdc_tree_array_t* restrict tree) +static int +compile_array(mds_kbdc_tree_array_t *restrict tree) { - int r = evaluate_element(tree->elements); - fail_if (r < 0); - if (r) - tree->processed = PROCESS_LEVEL; - return 0; - fail: - return -1; + int r = evaluate_element(tree->elements); + fail_if (r < 0); + if (r) + tree->processed = PROCESS_LEVEL; + return 0; +fail: + return -1; } @@ -2316,27 +2282,28 @@ static int compile_array(mds_kbdc_tree_array_t* restrict tree) * @return Zero on success, -1 on error, 1 if any of * the elements contain a NULL character */ -static int check_nonnul(mds_kbdc_tree_t* restrict tree) +static int +check_nonnul(mds_kbdc_tree_t *restrict tree) { - const char32_t* restrict string; - int rc = 0; - again: - if (tree == NULL) - return rc; - - for (string = tree->compiled_string.string; *string != -1; string++) - if (*string == 0) - { - NEW_ERROR(tree, ERROR, "NULL characters are not allowed in mappings"); - tree->processed = PROCESS_LEVEL; - rc = 1; - break; - } - - tree = tree->next; - goto again; - fail: - return -1; + const char32_t *restrict string; + int rc = 0; +again: + if (!tree) + return rc; + + for (string = tree->compiled_string.string; *string != -1; string++) { + if (!*string) { + NEW_ERROR(tree, ERROR, "NULL characters are not allowed in mappings"); + tree->processed = PROCESS_LEVEL; + rc = 1; + break; + } + } + + tree = tree->next; + goto again; +fail: + return -1; } @@ -2346,115 +2313,112 @@ static int check_nonnul(mds_kbdc_tree_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_map(mds_kbdc_tree_map_t* restrict tree) +static int +compile_map(mds_kbdc_tree_map_t *restrict tree) { - int bad = 0, old_have_side_effect = have_side_effect; - mds_kbdc_include_stack_t* restrict include_stack = NULL; - mds_kbdc_tree_t* seq = NULL; - mds_kbdc_tree_t* res = NULL; - mds_kbdc_tree_t* old_seq = tree->sequence; - mds_kbdc_tree_t* old_res = tree->result; - mds_kbdc_tree_map_t* dup_map = NULL; - int r, saved_errno; - mds_kbdc_tree_t* previous_last_value_statement = last_value_statement; - - have_side_effect = 0; - - /* Duplicate arguments and evaluate function calls, - variable dereferences and escapes in the mapping - input sequence. */ - fail_if (seq = mds_kbdc_tree_dup(old_seq), seq == NULL); - fail_if (bad |= evaluate_element(seq), bad < 0); - - /* Duplicate arguments and evaluate function calls, - variable dereferences and escapes in the mapping - output sequence, unless this is a value-statement. */ - if (tree->result) - { - fail_if (res = mds_kbdc_tree_dup(old_res), res == NULL); - fail_if (bad |= evaluate_element(res), bad < 0); - } - - /* Stop if any of the mapping-arguments could not be evaluated. */ - if (bad) - goto done; - - - if (tree->result) - { - /* Mapping-statement. */ - - /* Check for invalid characters in the mapping-arguments. */ - fail_if (bad |= check_nonnul(seq), bad < 0); - fail_if (bad |= check_nonnul(res), bad < 0); - if (bad) - goto done; - - /* Duplicate the mapping-statement but give it the evaluated mapping-arguments. */ - tree->sequence = NULL; - tree->result = NULL; - fail_if (dup_map = &(mds_kbdc_tree_dup((mds_kbdc_tree_t*)tree)->map), dup_map == NULL); - tree->sequence = old_seq, dup_map->sequence = seq, seq = NULL; - tree->result = old_res, dup_map->result = res, res = NULL; - - /* Enlist the mapping for assembling. */ - fail_if (include_stack = mds_kbdc_include_stack_save(), include_stack == NULL); - fail_if (add_mapping(dup_map, include_stack)); - - goto done; - } - - - /* Value-statement */ - - /* Save this statement so we can warn later if it is unnecessary, - * `set_return_value` will set it to `NULL` if there are side-effects, - * which would make this statement necessary (unless the overridding - * statement has identical side-effect, but we will not check for that). - * For simplicity, we do not store the include-stack, instead, we reset - * `last_value_statement` to `NULL` when we visit an include-statement. */ - last_value_statement = (mds_kbdc_tree_t*)tree; - - /* Add the value statement */ - r = set_return_value(seq->compiled_string.string); - seq->compiled_string.string = NULL; - - /* Check that the value-statement is inside a function call, or has - side-effects by directly or indirectly calling ‘\set/3’ on an - array that is not shadowed by an inner function- or macro-call. */ - if (r && !have_side_effect) - { - NEW_ERROR(tree, ERROR, "value-statement outside function without side-effects"); - tree->processed = PROCESS_LEVEL; - } - if (have_side_effect) - last_value_statement = NULL; - - /* Check whether we made a previous value-statement unnecessary. */ - if (previous_last_value_statement) - { - /* For simplicity we set `last_value_statement` on includes, - * so we are sure `last_value_statement` has the same include-stack. */ - - NEW_ERROR(previous_last_value_statement, WARNING, "value-statement has no effects"); - NEW_ERROR(tree, NOTE, "overridden here"); - } - - - done: - mds_kbdc_tree_free(seq); - mds_kbdc_tree_free(res); - have_side_effect |= old_have_side_effect; - return 0; - FAIL_BEGIN; - mds_kbdc_include_stack_free(include_stack); - mds_kbdc_tree_free((mds_kbdc_tree_t*)dup_map); - mds_kbdc_tree_free(seq); - mds_kbdc_tree_free(res); - tree->sequence = old_seq; - tree->result = old_res; - have_side_effect = old_have_side_effect; - FAIL_END; + int bad = 0, old_have_side_effect = have_side_effect; + mds_kbdc_include_stack_t *restrict include_stack = NULL; + mds_kbdc_tree_t *seq = NULL; + mds_kbdc_tree_t *res = NULL; + mds_kbdc_tree_t *old_seq = tree->sequence; + mds_kbdc_tree_t *old_res = tree->result; + mds_kbdc_tree_map_t *dup_map = NULL; + int r, saved_errno; + mds_kbdc_tree_t *previous_last_value_statement = last_value_statement; + + have_side_effect = 0; + + /* Duplicate arguments and evaluate function calls, + variable dereferences and escapes in the mapping + input sequence. */ + fail_if (!(seq = mds_kbdc_tree_dup(old_seq))); + fail_if ((bad |= evaluate_element(seq)) < 0); + + /* Duplicate arguments and evaluate function calls, + variable dereferences and escapes in the mapping + output sequence, unless this is a value-statement. */ + if (tree->result) { + fail_if (!(res = mds_kbdc_tree_dup(old_res))); + fail_if ((bad |= evaluate_element(res)) < 0); + } + + /* Stop if any of the mapping-arguments could not be evaluated. */ + if (bad) + goto done; + + + if (tree->result) { + /* Mapping-statement. */ + + /* Check for invalid characters in the mapping-arguments. */ + fail_if ((bad |= check_nonnul(seq)) < 0); + fail_if ((bad |= check_nonnul(res)) < 0); + if (bad) + goto done; + + /* Duplicate the mapping-statement but give it the evaluated mapping-arguments. */ + tree->sequence = NULL; + tree->result = NULL; + fail_if (!(dup_map = &mds_kbdc_tree_dup((mds_kbdc_tree_t *)tree)->map)); + tree->sequence = old_seq, dup_map->sequence = seq, seq = NULL; + tree->result = old_res, dup_map->result = res, res = NULL; + + /* Enlist the mapping for assembling. */ + fail_if (!(include_stack = mds_kbdc_include_stack_save())); + fail_if (add_mapping(dup_map, include_stack)); + + goto done; + } + + + /* Value-statement */ + + /* Save this statement so we can warn later if it is unnecessary, + * `set_return_value` will set it to `NULL` if there are side-effects, + * which would make this statement necessary (unless the overridding + * statement has identical side-effect, but we will not check for that). + * For simplicity, we do not store the include-stack, instead, we reset + * `last_value_statement` to `NULL` when we visit an include-statement. */ + last_value_statement = (mds_kbdc_tree_t *)tree; + + /* Add the value statement */ + r = set_return_value(seq->compiled_string.string); + seq->compiled_string.string = NULL; + + /* Check that the value-statement is inside a function call, or has + side-effects by directly or indirectly calling ‘\set/3’ on an + array that is not shadowed by an inner function- or macro-call. */ + if (r && !have_side_effect) { + NEW_ERROR(tree, ERROR, "value-statement outside function without side-effects"); + tree->processed = PROCESS_LEVEL; + } + if (have_side_effect) + last_value_statement = NULL; + + /* Check whether we made a previous value-statement unnecessary. */ + if (previous_last_value_statement) { + /* For simplicity we set `last_value_statement` on includes, + * so we are sure `last_value_statement` has the same include-stack. */ + + NEW_ERROR(previous_last_value_statement, WARNING, "value-statement has no effects"); + NEW_ERROR(tree, NOTE, "overridden here"); + } + + +done: + mds_kbdc_tree_free(seq); + mds_kbdc_tree_free(res); + have_side_effect |= old_have_side_effect; + return 0; + FAIL_BEGIN; + mds_kbdc_include_stack_free(include_stack); + mds_kbdc_tree_free((mds_kbdc_tree_t*)dup_map); + mds_kbdc_tree_free(seq); + mds_kbdc_tree_free(res); + tree->sequence = old_seq; + tree->result = old_res; + have_side_effect = old_have_side_effect; + FAIL_END; } @@ -2464,70 +2428,71 @@ static int compile_map(mds_kbdc_tree_map_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) +static int +compile_macro_call(mds_kbdc_tree_macro_call_t *restrict tree) { - mds_kbdc_tree_t* arg = NULL; - mds_kbdc_tree_t* arg_; - mds_kbdc_tree_macro_t* macro; - mds_kbdc_include_stack_t* macro_include_stack; - mds_kbdc_include_stack_t* our_include_stack = NULL; - size_t variable = 0; - int bad, saved_errno; - - last_value_statement = NULL; - - /* Push call-stack. */ - mds_kbdc_call_stack_push((mds_kbdc_tree_t*)tree, tree->loc_start, tree->loc_end); - - /* Duplicate arguments and evaluate function calls, - variable dereferences and escapes in the macro - call arguments. */ - if (tree->arguments) - fail_if (arg = mds_kbdc_tree_dup(tree->arguments), arg == NULL); - fail_if (bad = evaluate_element(arg), bad < 0); - if (bad) - return mds_kbdc_tree_free(arg), 0; - - /* Get the macro's subtree and include-stack, if it has - not been defined `get_macro` will add an error message - and return `NULL`. */ - fail_if (get_macro(tree, ¯o, ¯o_include_stack)); - if (macro == NULL) - goto done; - - - /* Push variable-stack and set parameters. */ - variables_stack_push(); - for (arg_ = arg; arg_; arg_ = arg_->next) - fail_if (let(++variable, NULL, arg_, NULL, 0, 0)); - - /* Switch include-stack to the macro's. */ - fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL); - fail_if (mds_kbdc_include_stack_restore(macro_include_stack)); - - /* Call the macro. */ - fail_if (compile_subtree(macro->inner)); - - /* Switch back the include-stack to ours. */ - fail_if (mds_kbdc_include_stack_restore(our_include_stack)); - mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL; - - /* Pop variable-stack. */ - variables_stack_pop(); - - done: - /* Pop call-stack. */ - mds_kbdc_call_stack_pop(); - - last_value_statement = NULL; - break_level = 0; - mds_kbdc_tree_free(arg); - return 0; - FAIL_BEGIN; - mds_kbdc_call_stack_pop(); - mds_kbdc_tree_free(arg); - mds_kbdc_include_stack_free(our_include_stack); - FAIL_END; + mds_kbdc_tree_t *arg = NULL; + mds_kbdc_tree_t *arg_; + mds_kbdc_tree_macro_t *macro; + mds_kbdc_include_stack_t *macro_include_stack; + mds_kbdc_include_stack_t *our_include_stack = NULL; + size_t variable = 0; + int bad, saved_errno; + + last_value_statement = NULL; + + /* Push call-stack. */ + mds_kbdc_call_stack_push((mds_kbdc_tree_t *)tree, tree->loc_start, tree->loc_end); + + /* Duplicate arguments and evaluate function calls, + variable dereferences and escapes in the macro + call arguments. */ + if (tree->arguments) + fail_if (!(arg = mds_kbdc_tree_dup(tree->arguments))); + fail_if (bad = evaluate_element(arg), bad < 0); + if (bad) + return mds_kbdc_tree_free(arg), 0; + + /* Get the macro's subtree and include-stack, if it has + not been defined `get_macro` will add an error message + and return `NULL`. */ + fail_if (get_macro(tree, ¯o, ¯o_include_stack)); + if (!macro) + goto done; + + + /* Push variable-stack and set parameters. */ + variables_stack_push(); + for (arg_ = arg; arg_; arg_ = arg_->next) + fail_if (let(++variable, NULL, arg_, NULL, 0, 0)); + + /* Switch include-stack to the macro's. */ + fail_if (!(our_include_stack = mds_kbdc_include_stack_save())); + fail_if (mds_kbdc_include_stack_restore(macro_include_stack)); + + /* Call the macro. */ + fail_if (compile_subtree(macro->inner)); + + /* Switch back the include-stack to ours. */ + fail_if (mds_kbdc_include_stack_restore(our_include_stack)); + mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL; + + /* Pop variable-stack. */ + variables_stack_pop(); + +done: + /* Pop call-stack. */ + mds_kbdc_call_stack_pop(); + + last_value_statement = NULL; + break_level = 0; + mds_kbdc_tree_free(arg); + return 0; + FAIL_BEGIN; + mds_kbdc_call_stack_pop(); + mds_kbdc_tree_free(arg); + mds_kbdc_include_stack_free(our_include_stack); + FAIL_END; } @@ -2537,64 +2502,64 @@ static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_subtree(mds_kbdc_tree_t* restrict tree) +static int +compile_subtree(mds_kbdc_tree_t *restrict tree) { -#define t(expr) fail_if ((expr) < 0) -#define c(type) t (compile_##type(&(tree->type))) -#define c_(type) t (compile_##type(&(tree->type##_))) - again: - if (tree == NULL) - return 0; - - if (tree->processed == PROCESS_LEVEL) - /* An error has occurred here before, let's skip it so - * we do not deluge the user with errors. */ - goto next; - - switch (tree->type) - { - case C(INFORMATION): - t (compile_subtree(tree->information.inner)); - break; - case C(INFORMATION_LANGUAGE): c (language); break; - case C(INFORMATION_COUNTRY): c (country); break; - case C(INFORMATION_VARIANT): c (variant); break; - case C(INCLUDE): c (include); break; - case C(FUNCTION): c (function); break; - case C(MACRO): c (macro); break; - case C(ASSUMPTION): - if (includes_ptr == 0) - fail_if (compile_subtree(tree->assumption.inner)); - break; - case C(ASSUMPTION_HAVE): c (have); break; - case C(ASSUMPTION_HAVE_CHARS): c (have_chars); break; - case C(ASSUMPTION_HAVE_RANGE): c (have_range); break; - case C(FOR): c_ (for); break; - case C(IF): c_ (if); break; - case C(LET): c (let); break; - case C(KEYS): c (keys); break; - case C(STRING): c (string); break; - case C(ARRAY): c (array); break; - case C(MAP): c (map); break; - case C(MACRO_CALL): c (macro_call); break; - case C(RETURN): break_level = 3; break; - case C(BREAK): break_level = 2; break; - case C(CONTINUE): break_level = 1; break; - default: - break; - } - +#define t(expr) fail_if ((expr) < 0) +#define c(type) t (compile_##type(&tree->type)) +#define c_(type) t (compile_##type(&tree->type##_)) +again: + if (!tree) + return 0; + + if (tree->processed == PROCESS_LEVEL) + /* An error has occurred here before, let's skip it so + * we do not deluge the user with errors. */ + goto next; + + switch (tree->type) { + case C(INFORMATION): + t (compile_subtree(tree->information.inner)); + break; + case C(INFORMATION_LANGUAGE): c (language); break; + case C(INFORMATION_COUNTRY): c (country); break; + case C(INFORMATION_VARIANT): c (variant); break; + case C(INCLUDE): c (include); break; + case C(FUNCTION): c (function); break; + case C(MACRO): c (macro); break; + case C(ASSUMPTION): + if (!includes_ptr) + fail_if (compile_subtree(tree->assumption.inner)); + break; + case C(ASSUMPTION_HAVE): c (have); break; + case C(ASSUMPTION_HAVE_CHARS): c (have_chars); break; + case C(ASSUMPTION_HAVE_RANGE): c (have_range); break; + case C(FOR): c_ (for); break; + case C(IF): c_ (if); break; + case C(LET): c (let); break; + case C(KEYS): c (keys); break; + case C(STRING): c (string); break; + case C(ARRAY): c (array); break; + case C(MAP): c (map); break; + case C(MACRO_CALL): c (macro_call); break; + case C(RETURN): break_level = 3; break; + case C(BREAK): break_level = 2; break; + case C(CONTINUE): break_level = 1; break; + default: + break; + } + next: - if (break_level) - /* If a `continue`, `break` or `return` has been encountered, - * we are done here and should return to whence we came and - * let the subcompiler of that construct deal with it. */ - return 0; - - tree = tree->next; - goto again; - fail: - return -1; + if (break_level) + /* If a `continue`, `break` or `return` has been encountered, + * we are done here and should return to whence we came and + * let the subcompiler of that construct deal with it. */ + return 0; + + tree = tree->next; + goto again; +fail: + return -1; #undef c_ #undef c #undef t @@ -2607,23 +2572,24 @@ static int compile_subtree(mds_kbdc_tree_t* restrict tree) * @param result_ `result` from `eliminate_dead_code`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int compile_layout(mds_kbdc_parsed_t* restrict result_) +int +compile_layout(mds_kbdc_parsed_t *restrict result_) { - int r, saved_errno; - result = result_; - mds_kbdc_include_stack_begin(result_); - mds_kbdc_call_stack_begin(result_); - r = compile_subtree(result_->tree); - saved_errno = errno; - mds_kbdc_call_stack_end(); - mds_kbdc_include_stack_end(); - variables_terminate(); - callables_terminate(); - errno = saved_errno; - fail_if (r); - return 0; - fail: - return -1; + int r, saved_errno; + result = result_; + mds_kbdc_include_stack_begin(result_); + mds_kbdc_call_stack_begin(result_); + r = compile_subtree(result_->tree); + saved_errno = errno; + mds_kbdc_call_stack_end(); + mds_kbdc_include_stack_end(); + variables_terminate(); + callables_terminate(); + errno = saved_errno; + fail_if (r); + return 0; +fail: + return -1; } @@ -2633,4 +2599,3 @@ int compile_layout(mds_kbdc_parsed_t* restrict result_) #undef NEW_ERROR #undef C #undef PROCESS_LEVEL - diff --git a/src/mds-kbdc/compile-layout.h b/src/mds-kbdc/compile-layout.h index 6911a71..86604e0 100644 --- a/src/mds-kbdc/compile-layout.h +++ b/src/mds-kbdc/compile-layout.h @@ -28,8 +28,7 @@ * @param result `result` from `eliminate_dead_code`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int compile_layout(mds_kbdc_parsed_t* restrict result); +int compile_layout(mds_kbdc_parsed_t *restrict result); #endif - diff --git a/src/mds-kbdc/eliminate-dead-code.c b/src/mds-kbdc/eliminate-dead-code.c index 039b6a8..5a8102f 100644 --- a/src/mds-kbdc/eliminate-dead-code.c +++ b/src/mds-kbdc/eliminate-dead-code.c @@ -27,7 +27,7 @@ /** * Tree type constant shortener */ -#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE +#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE /** * Add an error with “included from here”-notes to the error list @@ -38,20 +38,20 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(NODE, PTR, SEVERITY, ...) \ - NEW_ERROR_WITH_INCLUDES(NODE, PTR, SEVERITY, __VA_ARGS__) +#define NEW_ERROR(NODE, PTR, SEVERITY, ...)\ + NEW_ERROR_WITH_INCLUDES(NODE, PTR, SEVERITY, __VA_ARGS__) /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The parameter of `eliminate_dead_code` */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; /** * 2: Eliminating because of a return-statement @@ -68,7 +68,7 @@ static int elimination_level = 0; * @param tree The tree to reduce * @return Zero on success, -1 on error */ -static int eliminate_subtree(mds_kbdc_tree_t* restrict tree); +static int eliminate_subtree(mds_kbdc_tree_t *restrict tree); @@ -78,17 +78,18 @@ static int eliminate_subtree(mds_kbdc_tree_t* restrict tree); * @param tree The tree to reduce * @return Zero on success, -1 on error */ -static int eliminate_include(mds_kbdc_tree_include_t* restrict tree) +static int +eliminate_include(mds_kbdc_tree_include_t *restrict tree) { - void* data; - int r; - fail_if (mds_kbdc_include_stack_push(tree, &data)); - r = eliminate_subtree(tree->inner); - mds_kbdc_include_stack_pop(data); - fail_if (r); - return 0; - fail: - return -1; + void *data; + int r; + fail_if (mds_kbdc_include_stack_push(tree, &data)); + r = eliminate_subtree(tree->inner); + mds_kbdc_include_stack_pop(data); + fail_if (r); + return 0; +fail: + return -1; } @@ -98,17 +99,18 @@ static int eliminate_include(mds_kbdc_tree_include_t* restrict tree) * @param tree The tree to reduce * @return Zero on success, -1 on error */ -static int eliminate_if(mds_kbdc_tree_if_t* restrict tree) +static int +eliminate_if(mds_kbdc_tree_if_t *restrict tree) { - int elimination; - fail_if (eliminate_subtree(tree->inner)); - elimination = elimination_level, elimination_level = 0; - fail_if (eliminate_subtree(tree->otherwise)); - if (elimination > elimination_level) - elimination = elimination_level; - return 0; - fail: - return -1; + int elimination; + fail_if (eliminate_subtree(tree->inner)); + elimination = elimination_level, elimination_level = 0; + fail_if (eliminate_subtree(tree->otherwise)); + if (elimination > elimination_level) + elimination = elimination_level; + return 0; +fail: + return -1; } @@ -118,46 +120,51 @@ static int eliminate_if(mds_kbdc_tree_if_t* restrict tree) * @param tree The tree to reduce * @return Zero on success, -1 on error */ -static int eliminate_subtree(mds_kbdc_tree_t* restrict tree) +static int +eliminate_subtree(mds_kbdc_tree_t *restrict tree) { -#define e(type) fail_if (eliminate_##type(&(tree->type))) -#define E(type) fail_if (eliminate_##type(&(tree->type##_))) - again: - if (tree == NULL) - return 0; +#define e(type) fail_if (eliminate_##type(&tree->type)) +#define E(type) fail_if (eliminate_##type(&tree->type##_)) +again: + if (!tree) + return 0; - switch (tree->type) - { - case C(INCLUDE): e(include); break; - case C(IF): E(if); break; - case C(INFORMATION): - case C(FUNCTION): - case C(MACRO): - case C(ASSUMPTION): - case C(FOR): - fail_if (eliminate_subtree(tree->information.inner)); - if ((tree->type == C(FUNCTION)) || (tree->type == C(MACRO))) elimination_level = 0; - else if ((tree->type == C(FOR)) && (elimination_level == 1)) elimination_level = 0; - break; - case C(RETURN): - case C(BREAK): - case C(CONTINUE): - elimination_level = tree->type == C(RETURN) ? 2 : 1; - break; - default: - break; - } - - if (tree->next && elimination_level) - { - NEW_ERROR(tree->next, includes_ptr, WARNING, "statement is unreachable"); - mds_kbdc_tree_free(tree->next), tree->next = NULL; - } - - tree = tree->next; - goto again; - fail: - return -1; + switch (tree->type) { + case C(INCLUDE): + e(include); + break; + case C(IF): + E(if); + break; + case C(INFORMATION): + case C(FUNCTION): + case C(MACRO): + case C(ASSUMPTION): + case C(FOR): + fail_if (eliminate_subtree(tree->information.inner)); + if (tree->type == C(FUNCTION) || tree->type == C(MACRO)) + elimination_level = 0; + else if (tree->type == C(FOR) && elimination_level == 1) + elimination_level = 0; + break; + case C(RETURN): + case C(BREAK): + case C(CONTINUE): + elimination_level = tree->type == C(RETURN) ? 2 : 1; + break; + default: + break; + } + + if (tree->next && elimination_level) { + NEW_ERROR(tree->next, includes_ptr, WARNING, "statement is unreachable"); + mds_kbdc_tree_free(tree->next), tree->next = NULL; + } + + tree = tree->next; + goto again; +fail: + return -1; #undef E #undef e } @@ -169,20 +176,20 @@ static int eliminate_subtree(mds_kbdc_tree_t* restrict tree) * @param result_ `result` from `validate_tree`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int eliminate_dead_code(mds_kbdc_parsed_t* restrict result_) +int +eliminate_dead_code(mds_kbdc_parsed_t *restrict result_) { - int r; - mds_kbdc_include_stack_begin(result = result_); - r = eliminate_subtree(result_->tree); - mds_kbdc_include_stack_end(); - fail_if (r); - return 0; - fail: - return -1; + int r; + mds_kbdc_include_stack_begin(result = result_); + r = eliminate_subtree(result_->tree); + mds_kbdc_include_stack_end(); + fail_if (r); + return 0; +fail: + return -1; } #undef NEW_ERROR #undef C - diff --git a/src/mds-kbdc/eliminate-dead-code.h b/src/mds-kbdc/eliminate-dead-code.h index cbdf731..84bc3b6 100644 --- a/src/mds-kbdc/eliminate-dead-code.h +++ b/src/mds-kbdc/eliminate-dead-code.h @@ -28,8 +28,7 @@ * @param result `result` from `validate_tree`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int eliminate_dead_code(mds_kbdc_parsed_t* restrict result); +int eliminate_dead_code(mds_kbdc_parsed_t *restrict result); #endif - diff --git a/src/mds-kbdc/globals.c b/src/mds-kbdc/globals.c index 8e17020..01feca9 100644 --- a/src/mds-kbdc/globals.c +++ b/src/mds-kbdc/globals.c @@ -26,10 +26,9 @@ int argc; /** * The command line arguments */ -char** argv; +char **argv; /** * Whether ‘--force’ is used */ int argv_force = 0; - diff --git a/src/mds-kbdc/globals.h b/src/mds-kbdc/globals.h index b2b5cf1..1acf4bc 100644 --- a/src/mds-kbdc/globals.h +++ b/src/mds-kbdc/globals.h @@ -27,7 +27,7 @@ extern int argc; /** * The command line arguments */ -extern char** argv; +extern char **argv; /** * Whether ‘--force’ is used @@ -36,4 +36,3 @@ extern int argv_force; #endif - diff --git a/src/mds-kbdc/include-stack.c b/src/mds-kbdc/include-stack.c index 18b13d7..8ba787f 100644 --- a/src/mds-kbdc/include-stack.c +++ b/src/mds-kbdc/include-stack.c @@ -27,27 +27,27 @@ /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The `result` parameter of root procedure that requires the include-stack */ -static mds_kbdc_parsed_t* result; +static mds_kbdc_parsed_t *result; /** * The original value of `result->pathname` */ -static char* original_pathname; +static char *original_pathname; /** * The original value of `result->source_code` */ -static mds_kbdc_source_code_t* original_source_code; +static mds_kbdc_source_code_t *original_source_code; /** * Stack of visited include-statements */ -static const mds_kbdc_tree_include_t** restrict includes = NULL; +static const mds_kbdc_tree_include_t **restrict includes = NULL; /** * The number elements allocated for `includes` @@ -62,7 +62,7 @@ size_t includes_ptr = 0; /** * The latest saved include-stack */ -static mds_kbdc_include_stack_t* latest_save = NULL; +static mds_kbdc_include_stack_t *latest_save = NULL; @@ -72,23 +72,23 @@ static mds_kbdc_include_stack_t* latest_save = NULL; * @param ptr The number of “included from here”-notes * @return Zero on success, -1 on error */ -int mds_kbdc_include_stack_dump(size_t ptr) +int +mds_kbdc_include_stack_dump(size_t ptr) { - char* old_pathname = result->pathname; - mds_kbdc_source_code_t* old_source_code = result->source_code; - while (ptr--) - { - result->pathname = ptr ? includes[ptr - 1]->filename : original_pathname; - result->source_code = ptr ? includes[ptr - 1]->source_code : original_source_code; - NEW_ERROR_WITHOUT_INCLUDES(includes[ptr], NOTE, "included from here"); - } - result->pathname = old_pathname; - result->source_code = old_source_code; - return 0; - fail: - result->pathname = old_pathname; - result->source_code = old_source_code; - return -1; + char *old_pathname = result->pathname; + mds_kbdc_source_code_t *old_source_code = result->source_code; + while (ptr--) { + result->pathname = ptr ? includes[ptr - 1]->filename : original_pathname; + result->source_code = ptr ? includes[ptr - 1]->source_code : original_source_code; + NEW_ERROR_WITHOUT_INCLUDES(includes[ptr], NOTE, "included from here"); + } + result->pathname = old_pathname; + result->source_code = old_source_code; + return 0; +fail: + result->pathname = old_pathname; + result->source_code = old_source_code; + return -1; } @@ -97,11 +97,12 @@ int mds_kbdc_include_stack_dump(size_t ptr) * * @param result_ The `result` parameter of root procedure that requires the include-stack */ -void mds_kbdc_include_stack_begin(mds_kbdc_parsed_t* restrict result_) +void +mds_kbdc_include_stack_begin(mds_kbdc_parsed_t *restrict result_) { - result = result_; - original_pathname = result_->pathname; - original_source_code = result_->source_code; + result = result_; + original_pathname = result_->pathname; + original_source_code = result_->source_code; } @@ -109,13 +110,14 @@ void mds_kbdc_include_stack_begin(mds_kbdc_parsed_t* restrict result_) * Mark the root of the tree as no longer being visited, * and release clean up after the use of this module */ -void mds_kbdc_include_stack_end(void) +void +mds_kbdc_include_stack_end(void) { - latest_save = NULL; - result->pathname = original_pathname; - result->source_code = original_source_code; - free(includes), includes = NULL; - includes_size = includes_ptr = 0; + latest_save = NULL; + result->pathname = original_pathname; + result->source_code = original_source_code; + free(includes), includes = NULL; + includes_size = includes_ptr = 0; } @@ -128,30 +130,31 @@ void mds_kbdc_include_stack_end(void) * is undefined on error * @return Zero on success, -1 on error */ -int mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t* restrict tree, void** data) +int +mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t *restrict tree, void **data) { - const mds_kbdc_tree_include_t** old = NULL; - int saved_errno; - - if (includes_ptr == includes_size) - fail_if (xxrealloc(old, includes, includes_size += 4, const mds_kbdc_tree_include_t*)); - - fail_if (xmalloc(*data, 3, void*)); - - ((char**)(*data))[0] = result->pathname; - ((mds_kbdc_source_code_t**)(*data))[1] = result->source_code; - ((mds_kbdc_include_stack_t**)(*data))[2] = latest_save; - - includes[includes_ptr++] = tree; - result->pathname = tree->filename; - result->source_code = tree->source_code; - latest_save = NULL; - - return 0; - fail: - saved_errno = errno; - free(old); - return errno = saved_errno, -1; + const mds_kbdc_tree_include_t **old = NULL; + int saved_errno; + + if (includes_ptr == includes_size) + fail_if (xxrealloc(old, includes, includes_size += 4, const mds_kbdc_tree_include_t*)); + + fail_if (xmalloc(*data, 3, void*)); + + ((char **)(*data))[0] = result->pathname; + ((mds_kbdc_source_code_t **)(*data))[1] = result->source_code; + ((mds_kbdc_include_stack_t **)(*data))[2] = latest_save; + + includes[includes_ptr++] = tree; + result->pathname = tree->filename; + result->source_code = tree->source_code; + latest_save = NULL; + + return 0; +fail: + saved_errno = errno; + free(old); + return errno = saved_errno, -1; } @@ -162,15 +165,16 @@ int mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t* restrict tree, vo * * @param data `*data` from `mds_kbdc_include_stack_push` */ -void mds_kbdc_include_stack_pop(void* data) +void +mds_kbdc_include_stack_pop(void *data) { - int saved_errno = errno; - result->pathname = ((char**)data)[0]; - result->source_code = ((mds_kbdc_source_code_t**)data)[1]; - latest_save = ((mds_kbdc_include_stack_t**)data)[2]; - includes_ptr--; - free(data); - errno = saved_errno; + int saved_errno = errno; + result->pathname = ((char **)data)[0]; + result->source_code = ((mds_kbdc_source_code_t **)data)[1]; + latest_save = ((mds_kbdc_include_stack_t **)data)[2]; + includes_ptr--; + free(data); + errno = saved_errno; } @@ -179,34 +183,34 @@ void mds_kbdc_include_stack_pop(void* data) * * @return The include-stack, `NULL` on error */ -mds_kbdc_include_stack_t* mds_kbdc_include_stack_save(void) +mds_kbdc_include_stack_t * +mds_kbdc_include_stack_save(void) { - int saved_errno; - - if (latest_save) - { - latest_save->duplicates++; - return latest_save; - } - - fail_if (xmalloc(latest_save, 1, mds_kbdc_include_stack_t)); - - latest_save->stack = NULL; - latest_save->ptr = includes_ptr; - latest_save->duplicates = 0; - - if (latest_save->ptr == 0) - return latest_save; - - fail_if (xmemdup(latest_save->stack, includes, latest_save->ptr, const mds_kbdc_tree_include_t*)); - - return latest_save; - fail: - saved_errno = errno; - if (latest_save) - free(latest_save->stack), latest_save = NULL; - errno = saved_errno; - return NULL; + int saved_errno; + + if (latest_save) { + latest_save->duplicates++; + return latest_save; + } + + fail_if (xmalloc(latest_save, 1, mds_kbdc_include_stack_t)); + + latest_save->stack = NULL; + latest_save->ptr = includes_ptr; + latest_save->duplicates = 0; + + if (!latest_save->ptr) + return latest_save; + + fail_if (xmemdup(latest_save->stack, includes, latest_save->ptr, const mds_kbdc_tree_include_t*)); + + return latest_save; +fail: + saved_errno = errno; + if (latest_save) + free(latest_save->stack), latest_save = NULL; + errno = saved_errno; + return NULL; } @@ -216,23 +220,23 @@ mds_kbdc_include_stack_t* mds_kbdc_include_stack_save(void) * @param stack The include-stack * @return Zero on success, -1 on error */ -int mds_kbdc_include_stack_restore(mds_kbdc_include_stack_t* restrict stack) +int +mds_kbdc_include_stack_restore(mds_kbdc_include_stack_t *restrict stack) { - const mds_kbdc_tree_include_t** tmp; - - latest_save = stack; - - if (stack->ptr > includes_size) - { - fail_if (yrealloc(tmp, includes, stack->ptr, const mds_kbdc_tree_include_t*)); - includes_size = stack->ptr; - } - - memcpy(includes, stack->stack, stack->ptr * sizeof(const mds_kbdc_tree_include_t*)); - includes_ptr = stack->ptr; - return 0; - fail: - return -1; + const mds_kbdc_tree_include_t **tmp; + + latest_save = stack; + + if (stack->ptr > includes_size) { + fail_if (yrealloc(tmp, includes, stack->ptr, const mds_kbdc_tree_include_t *)); + includes_size = stack->ptr; + } + + memcpy(includes, stack->stack, stack->ptr * sizeof(const mds_kbdc_tree_include_t *)); + includes_ptr = stack->ptr; + return 0; +fail: + return -1; } @@ -241,13 +245,13 @@ int mds_kbdc_include_stack_restore(mds_kbdc_include_stack_t* restrict stack) * * @param stack The include-stack */ -void mds_kbdc_include_stack_free(mds_kbdc_include_stack_t* restrict stack) +void +mds_kbdc_include_stack_free(mds_kbdc_include_stack_t *restrict stack) { - if ((stack == NULL) || (stack->duplicates--)) - return; - free(stack->stack); - free(stack); - if (latest_save == stack) - latest_save = NULL; + if (!stack || stack->duplicates--) + return; + free(stack->stack); + free(stack); + if (latest_save == stack) + latest_save = NULL; } - diff --git a/src/mds-kbdc/include-stack.h b/src/mds-kbdc/include-stack.h index c077e2b..284bb02 100644 --- a/src/mds-kbdc/include-stack.h +++ b/src/mds-kbdc/include-stack.h @@ -31,17 +31,17 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR_WITHOUT_INCLUDES(NODE, SEVERITY, ...) \ - NEW_ERROR_(result, SEVERITY, 1, (NODE)->loc_line, \ - (NODE)->loc_start, (NODE)->loc_end, 1, __VA_ARGS__) +#define NEW_ERROR_WITHOUT_INCLUDES(NODE, SEVERITY, ...)\ + NEW_ERROR_(result, SEVERITY, 1, (NODE)->loc_line,\ + (NODE)->loc_start, (NODE)->loc_end, 1, __VA_ARGS__) /** * Add “included from here”-notes * * @param PTR:size_t The number of “included from here”-notes */ -#define DUMP_INCLUDE_STACK(PTR) \ - fail_if (mds_kbdc_include_stack_dump(PTR)) +#define DUMP_INCLUDE_STACK(PTR)\ + fail_if (mds_kbdc_include_stack_dump(PTR)) /** * Add an error with “included from here”-notes to the error list @@ -52,36 +52,32 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR_WITH_INCLUDES(NODE, PTR, SEVERITY, ...) \ - do \ - { \ - NEW_ERROR_WITHOUT_INCLUDES(NODE, SEVERITY, __VA_ARGS__); \ - DUMP_INCLUDE_STACK(PTR); \ - } \ - while (0) +#define NEW_ERROR_WITH_INCLUDES(NODE, PTR, SEVERITY, ...)\ + do {\ + NEW_ERROR_WITHOUT_INCLUDES(NODE, SEVERITY, __VA_ARGS__);\ + DUMP_INCLUDE_STACK(PTR);\ + } while (0) /** * A saved state of the include-stack */ -typedef struct mds_kbdc_include_stack -{ - /** - * Stack of visited include-statements - */ - const mds_kbdc_tree_include_t** stack; - - /** - * The number elements stored in `stack` (do not edit) - */ - size_t ptr; - - /** - * The number of duplicates there are of this object - */ - size_t duplicates; - +typedef struct mds_kbdc_include_stack { + /** + * Stack of visited include-statements + */ + const mds_kbdc_tree_include_t **stack; + + /** + * The number elements stored in `stack` (do not edit) + */ + size_t ptr; + + /** + * The number of duplicates there are of this object + */ + size_t duplicates; } mds_kbdc_include_stack_t; @@ -107,7 +103,7 @@ int mds_kbdc_include_stack_dump(size_t ptr); * * @param result The `result` parameter of root procedure that requires the include-stack */ -void mds_kbdc_include_stack_begin(mds_kbdc_parsed_t* restrict result); +void mds_kbdc_include_stack_begin(mds_kbdc_parsed_t *restrict result); /** * Mark the root of the tree as no longer being visited, @@ -124,7 +120,7 @@ void mds_kbdc_include_stack_end(void); * is undefined on error * @return Zero on success, -1 on error */ -int mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t* restrict tree, void** data); +int mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t *restrict tree, void **data); /** * Undo the lasted not-undone call to `mds_kbdc_include_stack_push` @@ -133,7 +129,7 @@ int mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t* restrict tree, vo * * @param data `*data` from `mds_kbdc_include_stack_push` */ -void mds_kbdc_include_stack_pop(void* data); +void mds_kbdc_include_stack_pop(void *data); /** * Save the current include-stack @@ -148,15 +144,14 @@ mds_kbdc_include_stack_t* mds_kbdc_include_stack_save(void); * @param stack The include-stack * @return Zero on success, -1 on error */ -int mds_kbdc_include_stack_restore(mds_kbdc_include_stack_t* restrict stack); +int mds_kbdc_include_stack_restore(mds_kbdc_include_stack_t *restrict stack); /** * Destroy a previous include-stack and free its allocation * * @param stack The include-stack */ -void mds_kbdc_include_stack_free(mds_kbdc_include_stack_t* restrict stack); +void mds_kbdc_include_stack_free(mds_kbdc_include_stack_t *restrict stack); #endif - diff --git a/src/mds-kbdc/make-tree.c b/src/mds-kbdc/make-tree.c index 1b5e8a5..f5bdf55 100644 --- a/src/mds-kbdc/make-tree.c +++ b/src/mds-kbdc/make-tree.c @@ -31,7 +31,7 @@ #ifndef DEBUG # define DEBUG_PROC(statements) #else -# define DEBUG_PROC(statements) statements +# define DEBUG_PROC(statements) statements #endif @@ -40,16 +40,14 @@ * as a compiler debugging feature and should be used from * inside `DEBUG_PROC` */ -#define PRINT_STACK \ - do \ - { \ - size_t i = stack_ptr; \ - fprintf(stderr, "stack {\n"); \ - while (i--) \ - fprintf(stderr, " %s\n", keyword_stack[i]); \ - fprintf(stderr, "}\n"); \ - } \ - while (0) +#define PRINT_STACK\ + do {\ + size_t i = stack_ptr;\ + fprintf(stderr, "stack {\n");\ + while (i--)\ + fprintf(stderr, " %s\n", keyword_stack[i]);\ + fprintf(stderr, "}\n");\ + } while (0) /** @@ -60,8 +58,8 @@ * @param UPPER:¿T? The upper bound, inclusive * @return :int 1 if `LOWER` ≤ `VALUE` ≤ `UPPER`, otherwise 0 */ -#define in_range(LOWER, VALUE, UPPER) \ - (((LOWER) <= (VALUE)) && ((VALUE) <= (UPPER))) +#define in_range(LOWER, VALUE, UPPER)\ + ((LOWER) <= (VALUE) && (VALUE) <= (UPPER)) /** @@ -70,23 +68,23 @@ * @param C:char The character * @return :int Zero if `C` is a valid callable name character or a forward slash, otherwise 0 */ -#define is_name_char(C) \ - (in_range('a', C, 'z') || in_range('A', C, 'Z') || strchr("0123456789_/", C)) +#define is_name_char(C)\ + (in_range('a', C, 'z') || in_range('A', C, 'Z') || strchr("0123456789_/", C)) /** * Pointer to the beginning of the current line */ -#define LINE \ - (result->source_code->lines[line_i]) +#define LINE\ + (result->source_code->lines[line_i]) /** * Update the tip of the stack to point to the address * of the current stack's tip's `next`-member */ -#define NEXT \ - tree_stack[stack_ptr] = &(tree_stack[stack_ptr][0]->next) +#define NEXT\ + tree_stack[stack_ptr] = &(tree_stack[stack_ptr][0]->next) /** @@ -97,9 +95,9 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(ERROR_IS_IN_FILE, SEVERITY, ...) \ - NEW_ERROR_(result, SEVERITY, ERROR_IS_IN_FILE, line_i, \ - (size_t)(line - LINE), (size_t)(end - LINE), 1, __VA_ARGS__) +#define NEW_ERROR(ERROR_IS_IN_FILE, SEVERITY, ...)\ + NEW_ERROR_(result, SEVERITY, ERROR_IS_IN_FILE, line_i,\ + (size_t)(line - LINE), (size_t)(end - LINE), 1, __VA_ARGS__) /** @@ -108,13 +106,13 @@ * @param LOWERCASE:identifier The keyword, for the node type, in lower case * @param UPPERCASE:identifier The keyword, for the node type, in upper case */ -#define NEW_NODE(LOWERCASE, UPPERCASE) \ - mds_kbdc_tree_##LOWERCASE##_t* node; \ - fail_if (xcalloc(node, 1, mds_kbdc_tree_##LOWERCASE##_t)); \ - node->type = MDS_KBDC_TREE_TYPE_##UPPERCASE; \ - node->loc_line = line_i; \ - node->loc_start = (size_t)(line - LINE); \ - node->loc_end = (size_t)(end - LINE) +#define NEW_NODE(LOWERCASE, UPPERCASE)\ + mds_kbdc_tree_##LOWERCASE##_t *node;\ + fail_if (xcalloc(node, 1, mds_kbdc_tree_##LOWERCASE##_t));\ + node->type = MDS_KBDC_TREE_TYPE_##UPPERCASE;\ + node->loc_line = line_i;\ + node->loc_start = (size_t)(line - LINE);\ + node->loc_end = (size_t)(end - LINE) /** @@ -123,13 +121,13 @@ * @param LOWERCASE:identifier The keyword, for the node type, in lower case * @param UPPERCASE:identifier The keyword, for the node type, in upper case */ -#define NEW_SUBNODE(LOWERCASE, UPPERCASE) \ - mds_kbdc_tree_##LOWERCASE##_t* subnode; \ - fail_if (xcalloc(subnode, 1, mds_kbdc_tree_##LOWERCASE##_t)); \ - subnode->type = MDS_KBDC_TREE_TYPE_##UPPERCASE; \ - subnode->loc_line = line_i; \ - subnode->loc_start = (size_t)(line - LINE); \ - subnode->loc_end = (size_t)(end - LINE) +#define NEW_SUBNODE(LOWERCASE, UPPERCASE)\ + mds_kbdc_tree_##LOWERCASE##_t *subnode;\ + fail_if (xcalloc(subnode, 1, mds_kbdc_tree_##LOWERCASE##_t));\ + subnode->type = MDS_KBDC_TREE_TYPE_##UPPERCASE;\ + subnode->loc_line = line_i;\ + subnode->loc_start = (size_t)(line - LINE);\ + subnode->loc_end = (size_t)(end - LINE) /** @@ -142,10 +140,10 @@ * * @param KEYWORD:const char* The keyword for the current node's type */ -#define BRANCH(KEYWORD) \ - (*(tree_stack[stack_ptr]) = (mds_kbdc_tree_t*)node, \ - tree_stack[stack_ptr + 1] = &(node->inner), \ - keyword_stack[stack_ptr++] = KEYWORD) +#define BRANCH(KEYWORD)\ + (*(tree_stack[stack_ptr]) = (mds_kbdc_tree_t *)node,\ + tree_stack[stack_ptr + 1] = &(node->inner),\ + keyword_stack[stack_ptr++] = KEYWORD) /** @@ -156,9 +154,9 @@ * This is what should be done when a leaf node has been * created and should be added to the result tree */ -#define LEAF \ - (*(tree_stack[stack_ptr]) = (mds_kbdc_tree_t*)node, \ - NEXT) +#define LEAF\ + (*(tree_stack[stack_ptr]) = (mds_kbdc_tree_t*)node,\ + NEXT) /** @@ -166,9 +164,9 @@ * * @param var:const char* The variable */ -#define SKIP_SPACES(var) \ - while (*var && (*var == ' ')) \ - var++ +#define SKIP_SPACES(var)\ + while (*var && *var == ' ')\ + var++ /** @@ -176,8 +174,8 @@ * * @param KEYWORD:const char* The keyword */ -#define NO_PARAMETERS(KEYWORD) \ - fail_if (no_parameters(KEYWORD)) +#define NO_PARAMETERS(KEYWORD)\ + fail_if (no_parameters(KEYWORD)) /** @@ -187,18 +185,18 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define NAMES_1(var) \ - fail_if (names_1(&(node->var))) +#define NAMES_1(var)\ + fail_if (names_1(&node->var)) /** * Suppress the next `line = STREND(line)` */ -#define NO_JUMP \ - (*end = prev_end_char, \ - end = line, \ - prev_end_char = *end, \ - *end = '\0') +#define NO_JUMP\ + (*end = prev_end_char,\ + end = line,\ + prev_end_char = *end,\ + *end = '\0') /** @@ -206,8 +204,8 @@ * * @param c:char The character */ -#define IS_END(c) \ - strchr(" >}])", c) +#define IS_END(c)\ + strchr(" >}])", c) /** @@ -217,31 +215,28 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define CHARS(var) \ - fail_if (chars(&(node->var))) +#define CHARS(var)\ + fail_if (chars(&node->var)) /** * Test that there are no more parameters */ -#define END \ - do \ - { \ - SKIP_SPACES(line); \ - if (*line) \ - { \ - NEW_ERROR(1, ERROR, "too many parameters"); \ - error->end = strlen(LINE); \ - } \ - } \ - while (0) +#define END\ + do {\ + SKIP_SPACES(line);\ + if (*line) {\ + NEW_ERROR(1, ERROR, "too many parameters");\ + error->end = strlen(LINE);\ + }\ + } while (0) /** * Test that the next parameter is in quotes */ -#define QUOTES \ - fail_if (quotes()) +#define QUOTES\ + fail_if (quotes()) /** @@ -251,14 +246,12 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define QUOTES_1(var) \ - do \ - { \ - QUOTES; \ - CHARS(var); \ - END; \ - } \ - while (0) +#define QUOTES_1(var)\ + do {\ + QUOTES;\ + CHARS(var);\ + END;\ + } while (0) /** @@ -266,8 +259,8 @@ * * @param KEYWORD:const char* The keyword */ -#define TEST_FOR_KEYWORD(KEYWORD) \ - fail_if (test_for_keyword(KEYWORD)) +#define TEST_FOR_KEYWORD(KEYWORD)\ + fail_if (test_for_keyword(KEYWORD)) /** @@ -277,8 +270,8 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define KEYS(var) \ - fail_if (keys(&(node->var))) +#define KEYS(var)\ + fail_if (keys(&node->var)) /** @@ -288,8 +281,8 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define PURE_KEYS(var) \ - fail_if (pure_keys(&(node->var))) +#define PURE_KEYS(var)\ + fail_if (pure_keys(&node->var)) @@ -299,23 +292,21 @@ * @param mapseq:int Whether this is a mapping sequence, otherwise * it is treated as macro call arguments */ -#define SEQUENCE(mapseq) \ - do /* for(;;) */ \ - { \ - *end = prev_end_char; \ - SKIP_SPACES(line); \ - if ((*line == '\0') || (*line == (mapseq ? ':' : ')'))) \ - break; \ - fail_if (sequence(mapseq, stack_orig)); \ - } \ - while (1) +#define SEQUENCE(mapseq)\ + do /* for(;;) */ {\ + *end = prev_end_char;\ + SKIP_SPACES(line);\ + if (!*line || *line == (mapseq ? ':' : ')'))\ + break;\ + fail_if (sequence(mapseq, stack_orig));\ + } while (1) /** * Check that the scopes created in `SEQUENCE` has all been popped */ -#define SEQUENCE_FULLY_POPPED \ - fail_if (sequence_fully_popped(stack_orig)) +#define SEQUENCE_FULLY_POPPED\ + fail_if (sequence_fully_popped(stack_orig)) /** @@ -325,14 +316,12 @@ * @param UPPERCASE:identifier The keyword, for the node type, in upper case * @param PARSE:expression Statement, without final semicolon, to retrieve members */ -#define MAKE_LEAF(LOWERCASE, UPPERCASE, PARSE) \ - do \ - { \ - NEW_NODE(LOWERCASE, UPPERCASE); \ - PARSE; \ - LEAF; \ - } \ - while (0) +#define MAKE_LEAF(LOWERCASE, UPPERCASE, PARSE)\ + do {\ + NEW_NODE(LOWERCASE, UPPERCASE);\ + PARSE;\ + LEAF;\ + } while (0) /** @@ -342,26 +331,24 @@ * @param UPPERCASE:identifier The keyword, for the node type, in upper case * @param PARSE:expression Statement, without final semicolon, to retrieve members */ -#define MAKE_BRANCH(LOWERCASE, UPPERCASE, PARSE) \ - do \ - { \ - NEW_NODE(LOWERCASE, UPPERCASE); \ - PARSE; \ - BRANCH(#LOWERCASE); \ - } \ - while (0) +#define MAKE_BRANCH(LOWERCASE, UPPERCASE, PARSE)\ + do {\ + NEW_NODE(LOWERCASE, UPPERCASE);\ + PARSE;\ + BRANCH(#LOWERCASE);\ + } while (0) /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * Output parameter for the parsing result */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; /** * The head of the parsing-stack @@ -371,12 +358,12 @@ static size_t stack_ptr; /** * The keyword portion of the parsing-stack */ -static const char** restrict keyword_stack; +static const char **restrict keyword_stack; /** * The tree portion of the parsing-stack */ -static mds_kbdc_tree_t*** restrict tree_stack; +static mds_kbdc_tree_t ***restrict tree_stack; /** * The index of the currently parsed line @@ -392,12 +379,12 @@ static int in_array; * The beginning of what has not get been parsed * on the current line */ -static char* line = NULL; +static char *line = NULL; /** * The end of what has been parsed on the current line */ -static char* end = NULL; +static char *end = NULL; /** * The previous value of `*end` @@ -408,7 +395,7 @@ static char prev_end_char; * Pointer to the first non-whitespace character * on the current line */ -static char* original; +static char *original; /** * Whether it has been identified that the @@ -427,40 +414,39 @@ static int too_few; * @param filename The filename of the parsed file * @return The value the caller should return, or 1 if the caller should not return, -1 on error */ -static int get_pathname(const char* restrict filename) +static int +get_pathname(const char *restrict filename) { - char* cwd = NULL; - int saved_errno; - - /* Get a non-relative pathname for the file, relative filenames - * can be misleading as the program can have changed working - * directory to be able to resolve filenames. */ - result->pathname = abspath(filename); - if (result->pathname == NULL) - { - fail_if (errno != ENOENT); - saved_errno = errno; - fail_if (cwd = curpath(), cwd == NULL); - fail_if (xstrdup(result->pathname, filename)); - NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 1, "no such file or directory in ‘%s’", cwd); - free(cwd); - return 0; - } - - /* Check that the file exists and can be read. */ - if (access(result->pathname, R_OK) < 0) - { - saved_errno = errno; - NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 0, NULL); - fail_if (xstrdup(error->description, strerror(saved_errno))); - return 0; - } - - return 1; - fail: - saved_errno = errno; - free(cwd); - return errno = saved_errno, -1; + char *cwd = NULL; + int saved_errno; + + /* Get a non-relative pathname for the file, relative filenames + * can be misleading as the program can have changed working + * directory to be able to resolve filenames. */ + result->pathname = abspath(filename); + if (!result->pathname) { + fail_if (errno != ENOENT); + saved_errno = errno; + fail_if (!(cwd = curpath())); + fail_if (xstrdup(result->pathname, filename)); + NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 1, "no such file or directory in ‘%s’", cwd); + free(cwd); + return 0; + } + + /* Check that the file exists and can be read. */ + if (access(result->pathname, R_OK) < 0) { + saved_errno = errno; + NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 0, NULL); + fail_if (xstrdup(error->description, strerror(saved_errno))); + return 0; + } + + return 1; +fail: + saved_errno = errno; + free(cwd); + return errno = saved_errno, -1; } @@ -469,25 +455,25 @@ static int get_pathname(const char* restrict filename) * * @return Zero on success, -1 on error */ -static int allocate_stacks(void) +static int +allocate_stacks(void) { - size_t max_line_length = 0, cur_line_length, line_n; - - /* The maximum line-length is needed because lines can have there own stacking, - * like sequence mapping lines, additionally, let statements can have one array. */ - for (line_i = 0, line_n = result->source_code->line_count; line_i < line_n; line_i++) - { - cur_line_length = strlen(LINE); - if (max_line_length < cur_line_length) - max_line_length = cur_line_length; - } - - fail_if (xmalloc(keyword_stack, line_n + max_line_length, const char*)); - fail_if (xmalloc(tree_stack, line_n + max_line_length + 1, mds_kbdc_tree_t**)); - - return 0; - fail: - return -1; + size_t max_line_length = 0, cur_line_length, line_n; + + /* The maximum line-length is needed because lines can have there own stacking, + * like sequence mapping lines, additionally, let statements can have one array. */ + for (line_i = 0, line_n = result->source_code->line_count; line_i < line_n; line_i++) { + cur_line_length = strlen(LINE); + if (max_line_length < cur_line_length) + max_line_length = cur_line_length; + } + + fail_if (xmalloc(keyword_stack, line_n + max_line_length, const char*)); + fail_if (xmalloc(tree_stack, line_n + max_line_length + 1, mds_kbdc_tree_t**)); + + return 0; +fail: + return -1; } @@ -496,14 +482,15 @@ static int allocate_stacks(void) * * @return Zero on success, -1 on error */ -static int read_source_code(void) +static int +read_source_code(void) { - /* Read the file and simplify it a bit. */ - fail_if (read_source_lines(result->pathname, result->source_code) < 0); - - return 0; - fail: - return -1; + /* Read the file and simplify it a bit. */ + fail_if (read_source_lines(result->pathname, result->source_code) < 0); + + return 0; +fail: + return -1; } @@ -517,34 +504,32 @@ static int read_source_code(void) * * @return Zero on success, -1 on error */ -static int check_for_premature_end_of_file(void) +static int +check_for_premature_end_of_file(void) { - /* Check that all scopes have been popped. */ - if (stack_ptr) - { - while (stack_ptr && keyword_stack[stack_ptr - 1] == NULL) - stack_ptr--; - if (stack_ptr) - { - NEW_ERROR(0, ERROR, "premature end of file"); - while (stack_ptr--) - { - if (keyword_stack[stack_ptr] == NULL) - continue; - line_i = tree_stack[stack_ptr][0]->loc_line; - line = LINE + tree_stack[stack_ptr][0]->loc_start; - end = LINE + tree_stack[stack_ptr][0]->loc_end; - if (!strcmp(keyword_stack[stack_ptr], "}")) - NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); - else - NEW_ERROR(1, NOTE, "missing associated ‘end %s’", keyword_stack[stack_ptr]); - } + /* Check that all scopes have been popped. */ + if (stack_ptr) { + while (stack_ptr && !keyword_stack[stack_ptr - 1]) + stack_ptr--; + if (stack_ptr) { + NEW_ERROR(0, ERROR, "premature end of file"); + while (stack_ptr--) { + if (!keyword_stack[stack_ptr]) + continue; + line_i = tree_stack[stack_ptr][0]->loc_line; + line = LINE + tree_stack[stack_ptr][0]->loc_start; + end = LINE + tree_stack[stack_ptr][0]->loc_end; + if (!strcmp(keyword_stack[stack_ptr], "}")) + NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); + else + NEW_ERROR(1, NOTE, "missing associated ‘end %s’", keyword_stack[stack_ptr]); + } + } } - } - - return 0; - fail: - return -1; + + return 0; +fail: + return -1; } @@ -555,16 +540,16 @@ static int check_for_premature_end_of_file(void) * * @return Zero on success, -1 on error */ -static int check_whether_file_is_empty(void) +static int +check_whether_file_is_empty(void) { - /* Warn about empty files. */ - if (result->tree == NULL) - if (result->errors_ptr == 0) - NEW_ERROR(0, WARNING, "file is empty"); - - return 0; - fail: - return -1; + /* Warn about empty files. */ + if (!result->tree && !result->errors_ptr) + NEW_ERROR(0, WARNING, "file is empty"); + + return 0; +fail: + return -1; } @@ -578,20 +563,20 @@ static int check_whether_file_is_empty(void) * @param keyword The keyword * @return Zero on success, -1 on error */ -static int no_parameters(const char* restrict keyword) +static int +no_parameters(const char *restrict keyword) { - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - if (*line) - { - end = STREND(line); - NEW_ERROR(1, ERROR, "extra token after ‘%s’", keyword); - } - - return 0; - fail: - return -1; + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + if (*line) { + end = STREND(line); + NEW_ERROR(1, ERROR, "extra token after ‘%s’", keyword); + } + + return 0; +fail: + return -1; } @@ -604,55 +589,51 @@ static int no_parameters(const char* restrict keyword) * node, where the parameter should be stored * @return Zero on success, -1 on error */ -static int names_1(char** restrict var) +static int +names_1(char **restrict var) { - char* name_end; - char* test; - int stray_char = 0; - char* end_end; - - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - if (*line == '\0') - { - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "a name is expected"); - } - else - { - name_end = line; - while (*name_end && is_name_char(*name_end)) - name_end++; - if (*name_end && (*name_end != ' ')) - { - end_end = name_end + 1; - while ((*end_end & 0xC0) == 0x80) - end_end++; - prev_end_char = *end_end, *end_end = '\0'; - NEW_ERROR(1, ERROR, "stray ‘%s’ character", name_end); - error->start = (size_t)(name_end - LINE); - error->end = (size_t)(end_end - LINE); - *end_end = prev_end_char; - stray_char = 1; + char *name_end; + char *test; + int stray_char = 0; + char *end_end; + + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + if (!*line) { + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "a name is expected"); + } else { + name_end = line; + while (*name_end && is_name_char(*name_end)) + name_end++; + if (*name_end && (*name_end != ' ')) { + end_end = name_end + 1; + while ((*end_end & 0xC0) == 0x80) + end_end++; + prev_end_char = *end_end, *end_end = '\0'; + NEW_ERROR(1, ERROR, "stray ‘%s’ character", name_end); + error->start = (size_t)(name_end - LINE); + error->end = (size_t)(end_end - LINE); + *end_end = prev_end_char; + stray_char = 1; + } + test = name_end; + SKIP_SPACES(test); + if (*test && !stray_char) { + NEW_ERROR(1, ERROR, "too many parameters"); + error->start = (size_t)(test - LINE); + error->end = strlen(LINE); + } + end = name_end; + prev_end_char = *end; + *end = '\0'; + fail_if (xstrdup(*var, line)); } - test = name_end; - SKIP_SPACES(test); - if (*test && !stray_char) - { - NEW_ERROR(1, ERROR, "too many parameters"); - error->start = (size_t)(test - LINE); - error->end = strlen(LINE); - } - end = name_end; - prev_end_char = *end; - *end = '\0'; - fail_if (xstrdup(*var, line)); - } - - return 0; - fail: - return -1; + + return 0; +fail: + return -1; } @@ -664,46 +645,49 @@ static int names_1(char** restrict var) * node, where the parameter should be stored * @return Zero on success, -1 on error */ -static int chars(char** restrict var) +static int +chars(char **restrict var) { - if (too_few) - return 0; - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - if (*line == '\0') - { - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "too few parameters"); - line = end, too_few = 1; - } - else - { - char* arg_end = line; - char* call_end = arg_end; - int escape = 0, quote = 0; - while (*arg_end) - { - char c = *arg_end++; - if (escape) escape = 0; - else if (arg_end <= call_end) ; - else if (c == '\\') - { - escape = 1; - call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); - } - else if (quote) quote = (c != '"'); - else if (IS_END(c)) { arg_end--; break; } - else quote = (c == '"'); + char *arg_end, *call_end, c; + int escape, quote; + if (too_few) + return 0; + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + if (!*line) { + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "too few parameters"); + line = end, too_few = 1; + } else { + arg_end = line; + call_end = arg_end; + escape = quote = 0; + while (*arg_end) { + c = *arg_end++; + if (escape) { + escape = 0; + } else if (arg_end <= call_end) { ; + } else if (c == '\\') { + escape = 1; + call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + } else if (quote) { + quote = c != '"'; + } else if (IS_END(c)) { + arg_end--; + break; + } else { + quote = c == '"'; + } + } + prev_end_char = *arg_end, *arg_end = '\0', end = arg_end; + fail_if (xstrdup(*var, line)); + line = end; } - prev_end_char = *arg_end, *arg_end = '\0', end = arg_end; - fail_if (xstrdup(*var, line)); - line = end; - } - - return 0; - fail: - return -1; + + return 0; +fail: + return -1; } @@ -712,25 +696,25 @@ static int chars(char** restrict var) * * @return Zero on success, -1 on error */ -static int quotes(void) +static int +quotes(void) { - char* line_ = line; - line = STREND(line); - *end = prev_end_char; - SKIP_SPACES(line); - if (*line && (*line != '"')) - { - char* arg_end = line; - SKIP_SPACES(arg_end); - NEW_ERROR(1, ERROR, "parameter must be in quotes"); - error->end = (size_t)(arg_end - LINE); - } - *end = '\0'; - line = line_; - - return 0; - fail: - return -1; + char *line_ = line, *arg_end; + line = STREND(line); + *end = prev_end_char; + SKIP_SPACES(line); + if (*line && *line != '"') { + arg_end = line; + SKIP_SPACES(arg_end); + NEW_ERROR(1, ERROR, "parameter must be in quotes"); + error->end = (size_t)(arg_end - LINE); + } + *end = '\0'; + line = line_; + + return 0; +fail: + return -1; } @@ -739,23 +723,23 @@ static int quotes(void) * * @return Whether the currently line has unparsed parameters, -1 on error */ -static int have_more_parameters(void) +static int +have_more_parameters(void) { - if (too_few) - return 0; - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - if (*line == '\0') - { - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "too few parameters"); - line = end, too_few = 1; - return 0; - } - return 1; - fail: - return -1; + if (too_few) + return 0; + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + if (!*line) { + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "too few parameters"); + line = end, too_few = 1; + return 0; + } + return 1; +fail: + return -1; } @@ -765,32 +749,33 @@ static int have_more_parameters(void) * @param keyword The keyword * @return Zero on success, -1 on error */ -static int test_for_keyword(const char* restrict keyword) +static int +test_for_keyword(const char *restrict keyword) { - int ok, r = have_more_parameters(); - fail_if (r < 0); - if (r == 0) - return 0; - - ok = (strstr(line, keyword) == line); - line += strlen(keyword); - ok = ok && ((*line == '\0') || (*line == ' ')); - if (ok) - { - end = line; - prev_end_char = *end, *end = '\0'; - return 0; - } - line -= strlen(keyword); - end = line; - SKIP_SPACES(end); - prev_end_char = *end, *end = '\0'; - NEW_ERROR(1, ERROR, "expecting keyword ‘%s’", keyword); - error->end = error->start + 1; - - return 0; - fail: - return -1; + int ok, r = have_more_parameters(); + fail_if (r < 0); + if (!r) + return 0; + + ok = (strstr(line, keyword) == line); + line += strlen(keyword); + ok = ok && (!*line || *line == ' '); + if (ok) { + end = line; + prev_end_char = *end; + *end = '\0'; + return 0; + } + line -= strlen(keyword); + end = line; + SKIP_SPACES(end); + prev_end_char = *end, *end = '\0'; + NEW_ERROR(1, ERROR, "expecting keyword ‘%s’", keyword); + error->end = error->start + 1; + + return 0; +fail: + return -1; } @@ -802,52 +787,53 @@ static int test_for_keyword(const char* restrict keyword) * node, where the parameter should be stored * @return Zero on success, -1 on error */ -static int keys(mds_kbdc_tree_t** restrict var) +static int +keys(mds_kbdc_tree_t **restrict var) { - char* arg_end; - char* call_end; - int r, escape = 0, quote = 0, triangle; - r = have_more_parameters(); - fail_if (r < 0); - if (r == 0) - return 0; - - arg_end = line; - call_end = arg_end; - triangle = (*arg_end == '<'); - while (*arg_end) - { - char c = *arg_end++ ; - if (escape) escape = 0; - else if (arg_end <= call_end) ; - else if (c == '\\') - { - escape = 1; - call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + char *arg_end, *call_end, c; + int r, escape = 0, quote = 0, triangle; + r = have_more_parameters(); + fail_if (r < 0); + if (!r) + return 0; + + arg_end = line; + call_end = arg_end; + triangle = *arg_end == '<'; + while (*arg_end) { + c = *arg_end++; + if (escape) { + escape = 0; + } else if (arg_end <= call_end) { ; + } else if (c == '\\') { + escape = 1; + call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + } else if (quote) { + quote = c != '"'; + } else if (c == '\"') { + quote = 1; + } else if (c == '>') { + triangle = 0; + } else if (IS_END(c) && !triangle) { + arg_end--; + break; + } } - else if (quote) quote = (c != '"'); - else if (c == '\"') quote = 1; - else if (c == '>') triangle = 0; - else if (IS_END(c) && !triangle) { arg_end--; break; } - } - prev_end_char = *arg_end, *arg_end = '\0', end = arg_end; - if (*line == '<') - { - NEW_SUBNODE(keys, KEYS); - *var = (mds_kbdc_tree_t*)subnode; - fail_if (xstrdup(subnode->keys, line)); - } - else - { - NEW_SUBNODE(string, STRING); - *var = (mds_kbdc_tree_t*)subnode; - fail_if (xstrdup(subnode->string, line)); - } - line = end; - - return 0; - fail: - return -1; + prev_end_char = *arg_end, *arg_end = '\0', end = arg_end; + if (*line == '<') { + NEW_SUBNODE(keys, KEYS); + *var = (mds_kbdc_tree_t *)subnode; + fail_if (xstrdup(subnode->keys, line)); + } else { + NEW_SUBNODE(string, STRING); + *var = (mds_kbdc_tree_t *)subnode; + fail_if (xstrdup(subnode->string, line)); + } + line = end; + + return 0; +fail: + return -1; } @@ -860,41 +846,45 @@ static int keys(mds_kbdc_tree_t** restrict var) * node, where the parameter should be stored * @return Zero on success, -1 on error */ -static int pure_keys(char** restrict var) +static int +pure_keys(char **restrict var) { - char* arg_end; - char* call_end; - int r, escape = 0, quote = 0, triangle; - r = have_more_parameters(); - fail_if (r < 0); - if (r == 0) - return 0; - - arg_end = line; - call_end = arg_end; - triangle = (*arg_end == '<'); - while (*arg_end) - { - char c = *arg_end++ ; - if (escape) escape = 0; - else if (arg_end <= call_end) ; - else if (c == '\\') - { - escape = 1; - call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + char *arg_end, *call_end, c; + int r, escape = 0, quote = 0, triangle; + r = have_more_parameters(); + fail_if (r < 0); + if (!r) + return 0; + + arg_end = line; + call_end = arg_end; + triangle = *arg_end == '<'; + while (*arg_end) { + c = *arg_end++; + if (escape) { + escape = 0; + } else if (arg_end <= call_end) { ; + } else if (c == '\\') { + escape = 1; + call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + } else if (quote) { + quote = c != '"'; + } else if (c == '\"') { + quote = 1; + } else if (c == '>') { + triangle = 0; + } else if (IS_END(c) && !triangle) { + arg_end--; + break; + } } - else if (quote) quote = (c != '"'); - else if (c == '\"') quote = 1; - else if (c == '>') triangle = 0; - else if (IS_END(c) && !triangle) { arg_end--; break; } - } - prev_end_char = *arg_end, *arg_end = '\0'; - fail_if (xstrdup(*var, line)); - end = arg_end, line = end; - - return 0; - fail: - return -1; + prev_end_char = *arg_end, *arg_end = '\0'; + fail_if (xstrdup(*var, line)); + end = arg_end, line = end; + + return 0; +fail: + return -1; } @@ -906,65 +896,54 @@ static int pure_keys(char** restrict var) * @param stack_orig The size of the stack when `SEQUENCE` was called * @return Zero on success, -1 on error */ -static int sequence(int mapseq, size_t stack_orig) +static int +sequence(int mapseq, size_t stack_orig) { - if (mapseq && (*line == '(')) - { - NEW_NODE(unordered, UNORDERED); - node->loc_end = node->loc_start + 1; - BRANCH(")"); - line++; - } - else if (*line == '[') - { - NEW_NODE(alternation, ALTERNATION); - node->loc_end = node->loc_start + 1; - BRANCH("]"); - line++; - } - else if (*line == '.') - { - NEW_NODE(nothing, NOTHING); - node->loc_end = node->loc_start + 1; - LEAF; - line++; - } - else if (strchr("])", *line)) - { - end = line + 1; - prev_end_char = *end, *end = '\0'; - if (stack_ptr == stack_orig) - NEW_ERROR(1, ERROR, "runaway ‘%s’", line); - else - { - stack_ptr--; - if (strcmp(line, keyword_stack[stack_ptr])) - NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); - NEXT; + if (mapseq && *line == '(') { + NEW_NODE(unordered, UNORDERED); + node->loc_end = node->loc_start + 1; + BRANCH(")"); + line++; + } else if (*line == '[') { + NEW_NODE(alternation, ALTERNATION); + node->loc_end = node->loc_start + 1; + BRANCH("]"); + line++; + } else if (*line == '.') { + NEW_NODE(nothing, NOTHING); + node->loc_end = node->loc_start + 1; + LEAF; + line++; + } else if (strchr("])", *line)) { + end = line + 1; + prev_end_char = *end, *end = '\0'; + if (stack_ptr == stack_orig) { + NEW_ERROR(1, ERROR, "runaway ‘%s’", line); + } else { + stack_ptr--; + if (strcmp(line, keyword_stack[stack_ptr])) + NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); + NEXT; + } + *end = prev_end_char; + line++; + } else if (*line == '<') { + NEW_NODE(keys, KEYS); + NO_JUMP; + PURE_KEYS(keys); + LEAF; + node->loc_end = (size_t)(line - LINE); + } else { + NEW_NODE(string, STRING); + NO_JUMP; + CHARS(string); + LEAF; + node->loc_end = (size_t)(line - LINE); } - *end = prev_end_char; - line++; - } - else if (*line == '<') - { - NEW_NODE(keys, KEYS); - NO_JUMP; - PURE_KEYS(keys); - LEAF; - node->loc_end = (size_t)(line - LINE); - } - else - { - NEW_NODE(string, STRING); - NO_JUMP; - CHARS(string); - LEAF; - node->loc_end = (size_t)(line - LINE); - } - - return 0; + + return 0; fail: - return -1; + return -1; } @@ -973,23 +952,23 @@ static int sequence(int mapseq, size_t stack_orig) * * @param stack_orig The size of the stack when `SEQUENCE` was called */ -static int sequence_fully_popped(size_t stack_orig) +static int +sequence_fully_popped(size_t stack_orig) { - if (stack_ptr == stack_orig) - return 0; - end = line + 1; - NEW_ERROR(1, ERROR, "premature end of sequence"); - while (stack_ptr > stack_orig) - { - stack_ptr--; - NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); - error->start = tree_stack[stack_ptr][0]->loc_start; - error->end = tree_stack[stack_ptr][0]->loc_end; - } - - return 0; - fail: - return -1; + if (stack_ptr == stack_orig) + return 0; + end = line + 1; + NEW_ERROR(1, ERROR, "premature end of sequence"); + while (stack_ptr > stack_orig) { + stack_ptr--; + NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); + error->start = tree_stack[stack_ptr][0]->loc_start; + error->end = tree_stack[stack_ptr][0]->loc_end; + } + + return 0; +fail: + return -1; } @@ -1002,62 +981,54 @@ static int sequence_fully_popped(size_t stack_orig) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_else(void) +static int +parse_else(void) { - size_t i; - if (stack_ptr == 0) - { - NEW_ERROR(1, ERROR, "runaway ‘else’ statement"); - return 0; - } - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - end = STREND(line); - SKIP_SPACES(line); - i = stack_ptr - 1; - while (keyword_stack[i] == NULL) - i--; - if (strcmp(keyword_stack[i], "if")) - { - stack_ptr--; - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "runaway ‘else’ statement"); - } - else if (*line == '\0') - { - /* else */ - mds_kbdc_tree_if_t* supernode = &(tree_stack[stack_ptr - 1][0]->if_); - if (supernode->otherwise) - { - line = strstr(LINE, "else"); - end = line + 4, prev_end_char = *end; - NEW_ERROR(1, ERROR, "multiple ‘else’ statements"); - mds_kbdc_tree_free(supernode->otherwise); - supernode->otherwise = NULL; + size_t i; + if (!stack_ptr) { + NEW_ERROR(1, ERROR, "runaway ‘else’ statement"); + return 0; } - tree_stack[stack_ptr] = &(supernode->otherwise); - } - else if ((strstr(line, "if") == line) && ((line[2] == ' ') || (line[2] == '\0'))) - { - /* else if */ - mds_kbdc_tree_if_t* supernode = &(tree_stack[stack_ptr - 1][0]->if_); - NEW_NODE(if, IF); - node->loc_end = node->loc_start + 2; - end = line += 2, prev_end_char = *end, *end = '\0'; - CHARS(condition); - END; - tree_stack[stack_ptr] = &(supernode->otherwise); - BRANCH(NULL); - } - else - { - NEW_ERROR(1, ERROR, "expecting nothing or ‘if’"); - stack_ptr--; - } - - return 0; - fail: - return -1; + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + end = STREND(line); + SKIP_SPACES(line); + i = stack_ptr - 1; + while (!keyword_stack[i]) + i--; + if (strcmp(keyword_stack[i], "if")) { + stack_ptr--; + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "runaway ‘else’ statement"); + } else if (!*line) { + /* else */ + mds_kbdc_tree_if_t *supernode = &tree_stack[stack_ptr - 1][0]->if_; + if (supernode->otherwise) { + line = strstr(LINE, "else"); + end = line + 4, prev_end_char = *end; + NEW_ERROR(1, ERROR, "multiple ‘else’ statements"); + mds_kbdc_tree_free(supernode->otherwise); + supernode->otherwise = NULL; + } + tree_stack[stack_ptr] = &supernode->otherwise; + } else if (strstr(line, "if") == line && (line[2] == ' ' || !line[2])) { + /* else if */ + mds_kbdc_tree_if_t *supernode = &tree_stack[stack_ptr - 1][0]->if_; + NEW_NODE(if, IF); + node->loc_end = node->loc_start + 2; + end = line += 2, prev_end_char = *end, *end = '\0'; + CHARS(condition); + END; + tree_stack[stack_ptr] = &(supernode->otherwise); + BRANCH(NULL); + } else { + NEW_ERROR(1, ERROR, "expecting nothing or ‘if’"); + stack_ptr--; + } + + return 0; +fail: + return -1; } @@ -1066,20 +1037,21 @@ static int parse_else(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_for(void) +static int +parse_for(void) { - NEW_NODE(for, FOR); - CHARS(first); - TEST_FOR_KEYWORD("to"); - CHARS(last); - TEST_FOR_KEYWORD("as"); - CHARS(variable); - END; - BRANCH("for"); - - return 0; - fail: - return -1; + NEW_NODE(for, FOR); + CHARS(first); + TEST_FOR_KEYWORD("to"); + CHARS(last); + TEST_FOR_KEYWORD("as"); + CHARS(variable); + END; + BRANCH("for"); + + return 0; +fail: + return -1; } @@ -1088,52 +1060,48 @@ static int parse_for(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_let(void) +static int +parse_let(void) { - NEW_NODE(let, LET); - CHARS(variable); - TEST_FOR_KEYWORD(":"); - *end = prev_end_char; - SKIP_SPACES(line); - if (*line == '{') + NEW_NODE(let, LET); + CHARS(variable); + TEST_FOR_KEYWORD(":"); + *end = prev_end_char; + SKIP_SPACES(line); + if (*line == '{') #define inner value - BRANCH(NULL); + BRANCH(NULL); #undef inner - else - LEAF; - if (*line == '\0') - { - line = original, end = STREND(line), prev_end_char = '\0'; - NEW_ERROR(1, ERROR, "too few parameters"); - } - else if (*line != '{') - { + else + LEAF; + if (!*line) { + line = original, end = STREND(line), prev_end_char = '\0'; + NEW_ERROR(1, ERROR, "too few parameters"); + } else if (*line != '{') { #define node subnode - NEW_NODE(string, STRING); - NO_JUMP; - CHARS(string); - node->loc_end = (size_t)(end - LINE); + NEW_NODE(string, STRING); + NO_JUMP; + CHARS(string); + node->loc_end = (size_t)(end - LINE); #undef node - node->value = (mds_kbdc_tree_t*)subnode; - END; - } - else - { + node->value = (mds_kbdc_tree_t*)subnode; + END; + } else { #define node subnode #define inner elements - NEW_NODE(array, ARRAY); - BRANCH("}"); - node->loc_end = node->loc_start + 1; + NEW_NODE(array, ARRAY); + BRANCH("}"); + node->loc_end = node->loc_start + 1; #undef inner #undef node - in_array = 1; - line++; - return 1; - } - - return 0; - fail: - return -1; + in_array = 1; + line++; + return 1; + } + + return 0; +fail: + return -1; } @@ -1142,29 +1110,28 @@ static int parse_let(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_end(void) +static int +parse_end(void) { - if (stack_ptr == 0) - { - NEW_ERROR(1, ERROR, "runaway ‘end’ statement"); - return 0; - } - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - while (keyword_stack[--stack_ptr] == NULL); - if (*line == '\0') - { - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "expecting a keyword after ‘end’"); - } - else if (strcmp(line, keyword_stack[stack_ptr])) - NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); - NEXT; - - return 0; - fail: - return -1; + if (!stack_ptr) { + NEW_ERROR(1, ERROR, "runaway ‘end’ statement"); + return 0; + } + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + while (!keyword_stack[--stack_ptr]); + if (!*line) { + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "expecting a keyword after ‘end’"); + } else if (strcmp(line, keyword_stack[stack_ptr])) { + NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); + } + NEXT; + + return 0; +fail: + return -1; } @@ -1173,57 +1140,56 @@ static int parse_end(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_map(void) +static int +parse_map(void) { - size_t stack_orig = stack_ptr + 1; - char* colon; + size_t stack_orig = stack_ptr + 1; + char *colon; #define node supernode #define inner sequence - NEW_NODE(map, MAP); - node->loc_end = node->loc_start; - BRANCH(":"); + NEW_NODE(map, MAP); + node->loc_end = node->loc_start; + BRANCH(":"); #undef inner #undef node - SEQUENCE(1); - SEQUENCE_FULLY_POPPED; + SEQUENCE(1); + SEQUENCE_FULLY_POPPED; #define node supernode #define inner result - stack_ptr--; - *end = prev_end_char; - supernode->loc_end = (size_t)(end - LINE); - SKIP_SPACES(line); - if (colon = line, *line++ != ':') - { - LEAF; - prev_end_char = *end; - return 0; /* Not an error in functions, or if \set is access, even indirectly. */ - } - BRANCH(":"); + stack_ptr--; + *end = prev_end_char; + supernode->loc_end = (size_t)(end - LINE); + SKIP_SPACES(line); + if (colon = line, *line++ != ':') { + LEAF; + prev_end_char = *end; + return 0; /* Not an error in functions, or if \set is access, even indirectly. */ + } + BRANCH(":"); #undef inner #undef node - SEQUENCE(1); - SEQUENCE_FULLY_POPPED; - stack_ptr--; - *end = prev_end_char; - supernode->loc_end = (size_t)(end - LINE); - SKIP_SPACES(line); + SEQUENCE(1); + SEQUENCE_FULLY_POPPED; + stack_ptr--; + *end = prev_end_char; + supernode->loc_end = (size_t)(end - LINE); + SKIP_SPACES(line); #define node supernode - LEAF; + LEAF; #undef node - if (supernode->result == NULL) - { - NEW_ERROR(1, ERROR, "output missing"); - error->start = (size_t)(colon - LINE); - error->end = error->start + 1; - } - if (*line == '\0') - return prev_end_char = *end, 0; - end = STREND(line), prev_end_char = *end; - NEW_ERROR(1, ERROR, "too many parameters"); - - return 0; - fail: - return -1; + if (!supernode->result) { + NEW_ERROR(1, ERROR, "output missing"); + error->start = (size_t)(colon - LINE); + error->end = error->start + 1; + } + if (!*line) + return prev_end_char = *end, 0; + end = STREND(line), prev_end_char = *end; + NEW_ERROR(1, ERROR, "too many parameters"); + + return 0; +fail: + return -1; } @@ -1232,63 +1198,59 @@ static int parse_map(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_macro_call(void) +static int +parse_macro_call(void) { - char* old_end = end; - char old_prev_end_char = prev_end_char; - size_t stack_orig = stack_ptr + 1; - *end = prev_end_char; - end = strchrnul(line, '('); - prev_end_char = *end, *end = '\0'; - if (prev_end_char) - { + char *old_end = end; + char old_prev_end_char = prev_end_char; + size_t stack_orig = stack_ptr + 1; + *end = prev_end_char; + end = strchrnul(line, '('); + prev_end_char = *end, *end = '\0'; + if (prev_end_char) { #define node supernode #define inner arguments - NEW_NODE(macro_call, MACRO_CALL); - old_end = end, old_prev_end_char = prev_end_char; - NO_JUMP; - *old_end = '\0'; - CHARS(name); - BRANCH(NULL); - end = old_end, prev_end_char = old_prev_end_char; - line++; + NEW_NODE(macro_call, MACRO_CALL); + old_end = end, old_prev_end_char = prev_end_char; + NO_JUMP; + *old_end = '\0'; + CHARS(name); + BRANCH(NULL); + end = old_end, prev_end_char = old_prev_end_char; + line++; #undef inner #undef node - SEQUENCE(0); - SEQUENCE_FULLY_POPPED; + SEQUENCE(0); + SEQUENCE_FULLY_POPPED; #define node supernode - if (*line == ')') - { - line++; - SKIP_SPACES(line); - if (*line) - { - NEW_ERROR(1, ERROR, "extra token after macro call"); - error->end = strlen(LINE); - } - } - else - { - NEW_ERROR(1, ERROR, "missing ‘)’"); - error->start = (size_t)(strchr(LINE, '(') - LINE); - error->end = error->start + 1; - } - stack_ptr--; - NEXT; - return 0; + if (*line == ')') { + line++; + SKIP_SPACES(line); + if (*line) { + NEW_ERROR(1, ERROR, "extra token after macro call"); + error->end = strlen(LINE); + } + } else { + NEW_ERROR(1, ERROR, "missing ‘)’"); + error->start = (size_t)(strchr(LINE, '(') - LINE); + error->end = error->start + 1; + } + stack_ptr--; + NEXT; + return 0; #undef node - } - *old_end = '\0'; - end = old_end; - prev_end_char = old_prev_end_char; - if (strchr("}", *line)) - NEW_ERROR(1, ERROR, "runaway ‘%c’", *line); - else - NEW_ERROR(1, ERROR, "invalid syntax ‘%s’", line); - - return 0; - fail: - return -1; + } + *old_end = '\0'; + end = old_end; + prev_end_char = old_prev_end_char; + if (strchr("}", *line)) + NEW_ERROR(1, ERROR, "runaway ‘%c’", *line); + else + NEW_ERROR(1, ERROR, "invalid syntax ‘%s’", line); + + return 0; +fail: + return -1; } @@ -1297,48 +1259,44 @@ static int parse_macro_call(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_array_elements(void) +static int +parse_array_elements(void) { - for (;;) - { - SKIP_SPACES(line); - if (*line == '\0') - return 0; - else if (*line == '}') - { - line++; - end = STREND(line); - END; - line = end, prev_end_char = '\0'; - goto done; + for (;;) { + SKIP_SPACES(line); + if (!*line) { + return 0; + } else if (*line == '}') { + line++; + end = STREND(line); + END; + line = end, prev_end_char = '\0'; + goto done; + } else { + NEW_NODE(string, STRING); + if (strchr("[]()<>{}", *line)) { + mds_kbdc_tree_free((mds_kbdc_tree_t*)node); + NEW_ERROR(1, ERROR, "x-stray ‘%c’", *line); + error->end = error->start + 1; + goto done; + } + NO_JUMP; + CHARS(string); + LEAF; + node->loc_end = (size_t)(end - LINE); + *end = prev_end_char; + line = end; + } } - else - { - NEW_NODE(string, STRING); - if (strchr("[]()<>{}", *line)) - { - mds_kbdc_tree_free((mds_kbdc_tree_t*)node); - NEW_ERROR(1, ERROR, "x-stray ‘%c’", *line); - error->end = error->start + 1; - goto done; - } - NO_JUMP; - CHARS(string); - LEAF; - node->loc_end = (size_t)(end - LINE); - *end = prev_end_char; - line = end; - } - } - - fail: - return -1; - - done: - in_array = 0; - stack_ptr -= 2; - NEXT; - return 0; + +fail: + return -1; + +done: + in_array = 0; + stack_ptr -= 2; + NEXT; + return 0; } @@ -1347,50 +1305,47 @@ static int parse_array_elements(void) * * @return Zero on success, -1 on error */ -static int parse_line(void) +static int +parse_line(void) { -#define p(function) \ - do \ - { \ - fail_if (r = function(), r < 0); \ - if (r > 0) \ - goto redo; \ - } \ - while (0) - - int r; - - redo: - if (in_array) p (parse_array_elements); - else if (!strcmp(line, "have_chars")) - MAKE_LEAF(assumption_have_chars, ASSUMPTION_HAVE_CHARS, QUOTES_1(chars)); - else if (!strcmp(line, "have_range")) - MAKE_LEAF(assumption_have_range, ASSUMPTION_HAVE_RANGE, CHARS(first); CHARS(last); END); - else if (!strcmp(line, "have")) MAKE_LEAF(assumption_have, ASSUMPTION_HAVE, KEYS(data); END); - else if (!strcmp(line, "information")) MAKE_BRANCH(information, INFORMATION, NO_PARAMETERS("information")); - else if (!strcmp(line, "assumption")) MAKE_BRANCH(assumption, ASSUMPTION, NO_PARAMETERS("assumption")); - else if (!strcmp(line, "return")) MAKE_LEAF(return, RETURN, NO_PARAMETERS("return")); - else if (!strcmp(line, "continue")) MAKE_LEAF(continue, CONTINUE, NO_PARAMETERS("continue")); - else if (!strcmp(line, "break")) MAKE_LEAF(break, BREAK, NO_PARAMETERS("break")); - else if (!strcmp(line, "language")) MAKE_LEAF(information_language, INFORMATION_LANGUAGE, QUOTES_1(data)); - else if (!strcmp(line, "country")) MAKE_LEAF(information_country, INFORMATION_COUNTRY, QUOTES_1(data)); - else if (!strcmp(line, "variant")) MAKE_LEAF(information_variant, INFORMATION_VARIANT, QUOTES_1(data)); - else if (!strcmp(line, "include")) MAKE_LEAF(include, INCLUDE, QUOTES_1(filename)); - else if (!strcmp(line, "function")) MAKE_BRANCH(function, FUNCTION, NAMES_1(name)); - else if (!strcmp(line, "macro")) MAKE_BRANCH(macro, MACRO, NAMES_1(name)); - else if (!strcmp(line, "if")) MAKE_BRANCH(if, IF, CHARS(condition); END); - else if (!strcmp(line, "else")) p (parse_else); - else if (!strcmp(line, "for")) p (parse_for); - else if (!strcmp(line, "let")) p (parse_let); - else if (!strcmp(line, "end")) p (parse_end); - else if (strchr("\\\"<([0123456789", *line)) p (parse_map); - else p (parse_macro_call); - - *end = prev_end_char; - - return 0; - fail: - return -1; +#define p(function)\ + do {\ + fail_if ((r = function()) < 0);\ + if (r > 0)\ + goto redo;\ + } while (0) + + int r; + +redo: + if (in_array) p (parse_array_elements); + else if (!strcmp(line, "have_chars")) MAKE_LEAF(assumption_have_chars, ASSUMPTION_HAVE_CHARS, QUOTES_1(chars)); + else if (!strcmp(line, "have_range")) MAKE_LEAF(assumption_have_range, ASSUMPTION_HAVE_RANGE, CHARS(first); CHARS(last); END); + else if (!strcmp(line, "have")) MAKE_LEAF(assumption_have, ASSUMPTION_HAVE, KEYS(data); END); + else if (!strcmp(line, "information")) MAKE_BRANCH(information, INFORMATION, NO_PARAMETERS("information")); + else if (!strcmp(line, "assumption")) MAKE_BRANCH(assumption, ASSUMPTION, NO_PARAMETERS("assumption")); + else if (!strcmp(line, "return")) MAKE_LEAF(return, RETURN, NO_PARAMETERS("return")); + else if (!strcmp(line, "continue")) MAKE_LEAF(continue, CONTINUE, NO_PARAMETERS("continue")); + else if (!strcmp(line, "break")) MAKE_LEAF(break, BREAK, NO_PARAMETERS("break")); + else if (!strcmp(line, "language")) MAKE_LEAF(information_language, INFORMATION_LANGUAGE, QUOTES_1(data)); + else if (!strcmp(line, "country")) MAKE_LEAF(information_country, INFORMATION_COUNTRY, QUOTES_1(data)); + else if (!strcmp(line, "variant")) MAKE_LEAF(information_variant, INFORMATION_VARIANT, QUOTES_1(data)); + else if (!strcmp(line, "include")) MAKE_LEAF(include, INCLUDE, QUOTES_1(filename)); + else if (!strcmp(line, "function")) MAKE_BRANCH(function, FUNCTION, NAMES_1(name)); + else if (!strcmp(line, "macro")) MAKE_BRANCH(macro, MACRO, NAMES_1(name)); + else if (!strcmp(line, "if")) MAKE_BRANCH(if, IF, CHARS(condition); END); + else if (!strcmp(line, "else")) p (parse_else); + else if (!strcmp(line, "for")) p (parse_for); + else if (!strcmp(line, "let")) p (parse_let); + else if (!strcmp(line, "end")) p (parse_end); + else if (strchr("\\\"<([0123456789", *line)) p (parse_map); + else p (parse_macro_call); + + *end = prev_end_char; + + return 0; +fail: + return -1; #undef p } @@ -1406,63 +1361,62 @@ static int parse_line(void) * @param result_ Output parameter for the parsing result * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int parse_to_tree(const char* restrict filename, mds_kbdc_parsed_t* restrict result_) +int +parse_to_tree(const char *restrict filename, mds_kbdc_parsed_t *restrict result_) { - size_t line_n; - int r, saved_errno; - - - /* Prepare parsing. */ - result = result_; - stack_ptr = 0; - keyword_stack = NULL; - tree_stack = NULL; - in_array = 0; - - fail_if (xmalloc(result->source_code, 1, mds_kbdc_source_code_t)); - mds_kbdc_source_code_initialise(result->source_code); - - r = get_pathname(filename); - fail_if (r < 0); - if (r == 0) - return 0; - - fail_if (read_source_code()); - fail_if (allocate_stacks()); - - - /* Create a node-slot for the tree root. */ - *tree_stack = &(result->tree); - - /* Parse the file. */ - for (line_i = 0, line_n = result->source_code->line_count; line_i < line_n; line_i++) - { - line = LINE; - SKIP_SPACES(line); - if (end = strchrnul(line, ' '), end == line) - continue; - prev_end_char = *end, *end = '\0'; - original = line; - too_few = 0; - - parse_line(); - } - - - /* Check parsing state. */ - fail_if (check_for_premature_end_of_file()); - fail_if (check_whether_file_is_empty()); - - /* Clean up. */ - free(keyword_stack); - free(tree_stack); - return 0; - - fail: - saved_errno = errno; - free(keyword_stack); - free(tree_stack); - return errno = saved_errno, -1; + size_t line_n; + int r, saved_errno; + + + /* Prepare parsing. */ + result = result_; + stack_ptr = 0; + keyword_stack = NULL; + tree_stack = NULL; + in_array = 0; + + fail_if (xmalloc(result->source_code, 1, mds_kbdc_source_code_t)); + mds_kbdc_source_code_initialise(result->source_code); + + fail_if ((r = get_pathname(filename)) < 0); + if (!r) + return 0; + + fail_if (read_source_code()); + fail_if (allocate_stacks()); + + + /* Create a node-slot for the tree root. */ + *tree_stack = &(result->tree); + + /* Parse the file. */ + for (line_i = 0, line_n = result->source_code->line_count; line_i < line_n; line_i++) { + line = LINE; + SKIP_SPACES(line); + if ((end = strchrnul(line, ' ')) == line) + continue; + prev_end_char = *end, *end = '\0'; + original = line; + too_few = 0; + + parse_line(); + } + + + /* Check parsing state. */ + fail_if (check_for_premature_end_of_file()); + fail_if (check_whether_file_is_empty()); + + /* Clean up. */ + free(keyword_stack); + free(tree_stack); + return 0; + +fail: + saved_errno = errno; + free(keyword_stack); + free(tree_stack); + return errno = saved_errno, -1; } @@ -1493,4 +1447,3 @@ int parse_to_tree(const char* restrict filename, mds_kbdc_parsed_t* restrict res #undef in_range #undef PRINT_STACK #undef DEBUG_PROC - diff --git a/src/mds-kbdc/make-tree.h b/src/mds-kbdc/make-tree.h index c645d94..0878414 100644 --- a/src/mds-kbdc/make-tree.h +++ b/src/mds-kbdc/make-tree.h @@ -29,8 +29,7 @@ * @param result Output parameter for the parsing result * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int parse_to_tree(const char* restrict filename, mds_kbdc_parsed_t* restrict result); +int parse_to_tree(const char *restrict filename, mds_kbdc_parsed_t *restrict result); #endif - diff --git a/src/mds-kbdc/mds-kbdc.c b/src/mds-kbdc/mds-kbdc.c index 1c5a6e8..0f668e4 100644 --- a/src/mds-kbdc/mds-kbdc.c +++ b/src/mds-kbdc/mds-kbdc.c @@ -37,15 +37,13 @@ /** * Parse command line arguments */ -static void parse_cmdline(void) +static void +parse_cmdline(void) { - int i; - for (i = 0; i < argc; i++) - { - char* arg = argv[i]; - if (strequals(arg, "--force")) - argv_force = 1; - } + int i; + for (i = 0; i < argc; i++) + if (strequals(argv[i], "--force")) + argv_force = 1; } @@ -56,39 +54,39 @@ static void parse_cmdline(void) * @param argv_ The command line arguments * @return Zero on and only one success */ -int main(int argc_, char** argv_) +int +main(int argc_, char **argv_) { -#define process(expr) \ - fail_if ((expr) < 0); \ - if (fatal = mds_kbdc_parsed_is_fatal(&result), fatal) \ - goto stop; - - mds_kbdc_parsed_t result; - int fatal; - - argc = argc_; - argv = argv_; - - parse_cmdline(); - - mds_kbdc_parsed_initialise(&result); - process (parse_to_tree(argv[1], &result)); - process (simplify_tree(&result)); - process (process_includes(&result)); - process (validate_tree(&result)); - process (eliminate_dead_code(&result)); - process (compile_layout(&result)); - /* TODO process (assemble_layout(&result)); */ - stop: - /* mds_kbdc_tree_print(result.tree, stderr); // for testing passes parse_to_tree–eliminate_dead_code */ - mds_kbdc_parsed_print_errors(&result, stderr); - mds_kbdc_parsed_destroy(&result); - return fatal; - - fail: - xperror(*argv); - mds_kbdc_parsed_destroy(&result); - return 1; +#define process(expr)\ + fail_if ((expr) < 0);\ + if ((fatal = mds_kbdc_parsed_is_fatal(&result)))\ + goto stop; + + mds_kbdc_parsed_t result; + int fatal; + + argc = argc_; + argv = argv_; + + parse_cmdline(); + + mds_kbdc_parsed_initialise(&result); + process (parse_to_tree(argv[1], &result)); + process (simplify_tree(&result)); + process (process_includes(&result)); + process (validate_tree(&result)); + process (eliminate_dead_code(&result)); + process (compile_layout(&result)); + /* TODO process (assemble_layout(&result)); */ +stop: + /* mds_kbdc_tree_print(result.tree, stderr); // for testing passes parse_to_tree–eliminate_dead_code */ + mds_kbdc_parsed_print_errors(&result, stderr); + mds_kbdc_parsed_destroy(&result); + return fatal; + +fail: + xperror(*argv); + mds_kbdc_parsed_destroy(&result); + return 1; #undef process } - diff --git a/src/mds-kbdc/mds-kbdc.h b/src/mds-kbdc/mds-kbdc.h index a0f0d0f..8cf6204 100644 --- a/src/mds-kbdc/mds-kbdc.h +++ b/src/mds-kbdc/mds-kbdc.h @@ -23,4 +23,3 @@ #endif - diff --git a/src/mds-kbdc/parse-error.c b/src/mds-kbdc/parse-error.c index 242b730..6a31424 100644 --- a/src/mds-kbdc/parse-error.c +++ b/src/mds-kbdc/parse-error.c @@ -32,46 +32,45 @@ * @param output The output file * @param desc The description of the error */ -static void print(const mds_kbdc_parse_error_t* restrict this, FILE* restrict output, const char* restrict desc) +static void +print(const mds_kbdc_parse_error_t *restrict this, FILE *restrict output, const char *restrict desc) { - size_t i, n, start = 0, end = 0; - const char* restrict code = this->code; - char* restrict path = relpath(this->pathname, NULL); - - /* Convert bytes count to character count for the code position. */ - for (i = 0, n = this->start; i < n; i++) - if ((code[i] & 0xC0) != 0x80) - start++; - for (n = this->end; i < n; i++) - if ((code[i] & 0xC0) != 0x80) - end++; - end += start; - - /* Print error information. */ - fprintf(output, "\033[01m%s\033[21m:", path ? path : this->pathname); - free(path); - if (this->error_is_in_file) - fprintf(output, "%zu:%zu–%zu:", this->line + 1, start, end); - switch (this->severity) - { - case MDS_KBDC_PARSE_ERROR_NOTE: fprintf(output, " \033[01;36mnote:\033[00m "); break; - case MDS_KBDC_PARSE_ERROR_WARNING: fprintf(output, " \033[01;35mwarning:\033[00m "); break; - case MDS_KBDC_PARSE_ERROR_ERROR: fprintf(output, " \033[01;31merror:\033[00m "); break; - case MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR: fprintf(output, " \033[01;31minternal error:\033[00m "); break; - default: - abort(); - break; - } - if (this->error_is_in_file) - { - fprintf(output, "%s\n %s\n \033[01;32m", desc, code); - i = 0; - for (n = start; i < n; i++) fputc(' ', output); - for (n = end; i < n; i++) fputc('^', output); - } - else - fprintf(output, "%s\n", desc); - fprintf(output, "\033[00m\n"); + size_t i, n, start = 0, end = 0; + const char *restrict code = this->code; + char *restrict path = relpath(this->pathname, NULL); + + /* Convert bytes count to character count for the code position. */ + for (i = 0, n = this->start; i < n; i++) + if ((code[i] & 0xC0) != 0x80) + start++; + for (n = this->end; i < n; i++) + if ((code[i] & 0xC0) != 0x80) + end++; + end += start; + + /* Print error information. */ + fprintf(output, "\033[01m%s\033[21m:", path ? path : this->pathname); + free(path); + if (this->error_is_in_file) + fprintf(output, "%zu:%zu–%zu:", this->line + 1, start, end); + switch (this->severity) { + case MDS_KBDC_PARSE_ERROR_NOTE: fprintf(output, " \033[01;36mnote:\033[00m "); break; + case MDS_KBDC_PARSE_ERROR_WARNING: fprintf(output, " \033[01;35mwarning:\033[00m "); break; + case MDS_KBDC_PARSE_ERROR_ERROR: fprintf(output, " \033[01;31merror:\033[00m "); break; + case MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR: fprintf(output, " \033[01;31minternal error:\033[00m "); break; + default: + abort(); + break; + } + if (this->error_is_in_file) { + fprintf(output, "%s\n %s\n \033[01;32m", desc, code); + i = 0; + for (n = start; i < n; i++) fputc(' ', output); + for (n = end; i < n; i++) fputc('^', output); + } else { + fprintf(output, "%s\n", desc); + } + fprintf(output, "\033[00m\n"); } @@ -81,49 +80,57 @@ static void print(const mds_kbdc_parse_error_t* restrict this, FILE* restrict ou * @param this The error structure * @param output The output file */ -void mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t* restrict this, FILE* restrict output) +void +mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t *restrict this, FILE *restrict output) { - ssize_t m; - size_t n; - char* desc; - char* dend = this->description + strlen(this->description); - char* dstart; - char* dptr; - char* p; - char* q; - - /* Count the number points in the description we should modify to format it. */ - for (p = this->description, n = 0;;) - { - if (q = strstr(p, "‘"), q == NULL) q = dend; - if (p = strstr(p, "’"), p == NULL) p = dend; - if (q < p) p = q; - if (*p++) n++; - else break; - } - - /* Allocate string for the formatted description. */ - n = 1 + strlen(this->description) + strlen("\033[xxm’") * n; - dptr = desc = alloca(n * sizeof(char)); - - /* Format description. */ - for (p = this->description;;) - { - dstart = p; - if (q = strstr(p, "‘"), q == NULL) q = dend; - if (p = strstr(p, "’"), p == NULL) p = dend; - if (q < p) p = q; - if ((n = (size_t)(p - dstart))) - memcpy(dptr, dstart, n), dptr += n; - if (p == dend) - break; - if (strstr(p, "‘") == p) sprintf(dptr, "\033[01m‘%zn", &m), dptr += (size_t)m, p += strlen("‘"); - else sprintf(dptr, "’\033[21m%zn", &m), dptr += (size_t)m, p += strlen("’"); - } - *dptr = '\0'; - - /* Print the error. */ - print(this, output, desc); + size_t n; + char *desc; + char *dend = this->description + strlen(this->description); + char *dstart; + char *dptr; + char *p; + char *q; + + /* Count the number points in the description we should modify to format it. */ + for (p = this->description, n = 0;;) { + if (!(q = strstr(p, "‘"))) + q = dend; + if (!(p = strstr(p, "’"))) + p = dend; + if (q < p) + p = q; + if (*p++) + n++; + else + break; + } + + /* Allocate string for the formatted description. */ + n = 1 + strlen(this->description) + strlen("\033[xxm’") * n; + dptr = desc = alloca(n * sizeof(char)); + + /* Format description. */ + for (p = this->description;;) { + dstart = p; + if (!(q = strstr(p, "‘"))) + q = dend; + if (!(p = strstr(p, "’"))) + p = dend; + if (q < p) + p = q; + if ((n = (size_t)(p - dstart))) + memcpy(dptr, dstart, n), dptr += n; + if (p == dend) + break; + if (strstr(p, "‘") == p) + dptr += sprintf(dptr, "\033[01m‘"), p += strlen("‘"); + else + dptr += sprintf(dptr, "’\033[21m"), p += strlen("’"); + } + *dptr = '\0'; + + /* Print the error. */ + print(this, output, desc); } @@ -133,13 +140,14 @@ void mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t* restrict this, FIL * * @param this The error structure */ -void mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t* restrict this) +void +mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t *restrict this) { - if (this == NULL) - return; - free(this->pathname), this->pathname = NULL; - free(this->code), this->code = NULL; - free(this->description), this->description = NULL; + if (!this) + return; + free(this->pathname), this->pathname = NULL; + free(this->code), this->code = NULL; + free(this->description), this->description = NULL; } @@ -149,10 +157,11 @@ void mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t* restrict this) * * @param this The error structure */ -void mds_kbdc_parse_error_free(mds_kbdc_parse_error_t* restrict this) +void +mds_kbdc_parse_error_free(mds_kbdc_parse_error_t *restrict this) { - mds_kbdc_parse_error_destroy(this); - free(this); + mds_kbdc_parse_error_destroy(this); + free(this); } @@ -162,13 +171,14 @@ void mds_kbdc_parse_error_free(mds_kbdc_parse_error_t* restrict this) * * @param this The group of error structures */ -void mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t** restrict these) +void +mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t **restrict these) { - mds_kbdc_parse_error_t* restrict that; - if (these == NULL) - return; - while (that = *these, that != NULL) - mds_kbdc_parse_error_free(that), *these++ = NULL; + mds_kbdc_parse_error_t *restrict that; + if (!these) + return; + while ((that = *these)) + mds_kbdc_parse_error_free(that), *these++ = NULL; } @@ -178,9 +188,9 @@ void mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t** restrict these) * * @param this The group of error structures */ -void mds_kbdc_parse_error_free_all(mds_kbdc_parse_error_t** restrict these) +void +mds_kbdc_parse_error_free_all(mds_kbdc_parse_error_t**restrict these) { - mds_kbdc_parse_error_destroy_all(these); - free(these); + mds_kbdc_parse_error_destroy_all(these); + free(these); } - diff --git a/src/mds-kbdc/parse-error.h b/src/mds-kbdc/parse-error.h index b7e879c..9668f8f 100644 --- a/src/mds-kbdc/parse-error.h +++ b/src/mds-kbdc/parse-error.h @@ -27,74 +27,72 @@ /** * Not an error, simply a note about the previous error or warning */ -#define MDS_KBDC_PARSE_ERROR_NOTE 1 +#define MDS_KBDC_PARSE_ERROR_NOTE 1 /** * A warning, must likely an error that is not fatal to the compilation */ -#define MDS_KBDC_PARSE_ERROR_WARNING 2 +#define MDS_KBDC_PARSE_ERROR_WARNING 2 /** * An error, the compilation will halt */ -#define MDS_KBDC_PARSE_ERROR_ERROR 3 +#define MDS_KBDC_PARSE_ERROR_ERROR 3 /** * Internal compiler error or system error, compilation halts */ -#define MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR 4 +#define MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR 4 /** * Description of an parsing error */ -typedef struct mds_kbdc_parse_error -{ - /** - * Either of: - * - `MDS_KBDC_PARSE_ERROR_NOTE` - * - `MDS_KBDC_PARSE_ERROR_WARNING` - * - `MDS_KBDC_PARSE_ERROR_ERROR` - * - `MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR` - */ - int severity; - - /** - * If zero, disregard `.line`, `.start`, `.end` and `.code` - */ - int error_is_in_file; - - /** - * The pathname of the file with the error - */ - char* pathname; - - /** - * The line where the error occurred, zero-based - */ - size_t line; - - /** - * The byte where the error started, inclusive, zero-based - */ - size_t start; - - /** - * The byte where the error ended, exclusive, zero-based - */ - size_t end; - - /** - * The code on the line where the error occurred - */ - char* code; - - /** - * Description of the error - */ - char* description; - +typedef struct mds_kbdc_parse_error { + /** + * Either of: + * - `MDS_KBDC_PARSE_ERROR_NOTE` + * - `MDS_KBDC_PARSE_ERROR_WARNING` + * - `MDS_KBDC_PARSE_ERROR_ERROR` + * - `MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR` + */ + int severity; + + /** + * If zero, disregard `.line`, `.start`, `.end` and `.code` + */ + int error_is_in_file; + + /** + * The pathname of the file with the error + */ + char *pathname; + + /** + * The line where the error occurred, zero-based + */ + size_t line; + + /** + * The byte where the error started, inclusive, zero-based + */ + size_t start; + + /** + * The byte where the error ended, exclusive, zero-based + */ + size_t end; + + /** + * The code on the line where the error occurred + */ + char *code; + + /** + * Description of the error + */ + char *description; } mds_kbdc_parse_error_t; @@ -105,7 +103,7 @@ typedef struct mds_kbdc_parse_error * @param this The error structure * @param output The output file */ -void mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t* restrict this, FILE* restrict output); +void mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t *restrict this, FILE *restrict output); /** @@ -113,7 +111,7 @@ void mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t* restrict this, FIL * * @param this The error structure */ -void mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t* restrict this); +void mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t *restrict this); /** * Release all resources allocated in a `mds_kbdc_parse_error_t*` @@ -121,7 +119,7 @@ void mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t* restrict this); * * @param this The error structure */ -void mds_kbdc_parse_error_free(mds_kbdc_parse_error_t* restrict this); +void mds_kbdc_parse_error_free(mds_kbdc_parse_error_t *restrict this); /** * Release all resources allocated in a `NULL`-terminated group @@ -129,7 +127,7 @@ void mds_kbdc_parse_error_free(mds_kbdc_parse_error_t* restrict this); * * @param this The group of error structures */ -void mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t** restrict these); +void mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t **restrict these); /** * Release all resources allocated in a `NULL`-terminated group of @@ -137,9 +135,8 @@ void mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t** restrict these); * * @param this The group of error structures */ -void mds_kbdc_parse_error_free_all(mds_kbdc_parse_error_t** restrict these); +void mds_kbdc_parse_error_free_all(mds_kbdc_parse_error_t **restrict these); #endif - diff --git a/src/mds-kbdc/parsed.c b/src/mds-kbdc/parsed.c index d9c8f23..e4c23dc 100644 --- a/src/mds-kbdc/parsed.c +++ b/src/mds-kbdc/parsed.c @@ -28,9 +28,10 @@ * * @param this The `mds_kbdc_parsed_t*` */ -void mds_kbdc_parsed_initialise(mds_kbdc_parsed_t* restrict this) +void +mds_kbdc_parsed_initialise(mds_kbdc_parsed_t *restrict this) { - memset(this, 0, sizeof(mds_kbdc_parsed_t)); + memset(this, 0, sizeof(mds_kbdc_parsed_t)); } @@ -39,27 +40,28 @@ void mds_kbdc_parsed_initialise(mds_kbdc_parsed_t* restrict this) * * @param this The `mds_kbdc_parsed_t*` */ -void mds_kbdc_parsed_destroy(mds_kbdc_parsed_t* restrict this) +void +mds_kbdc_parsed_destroy(mds_kbdc_parsed_t *restrict this) { - mds_kbdc_tree_free(this->tree); - mds_kbdc_source_code_destroy(this->source_code); - free(this->source_code); - free(this->pathname); - mds_kbdc_parse_error_free_all(this->errors); - while (this->languages_ptr--) - free(this->languages[this->languages_ptr]); - free(this->languages); - while (this->countries_ptr--) - free(this->countries[this->countries_ptr]); - free(this->countries); - free(this->variant); - while (this->assumed_strings_ptr--) - free(this->assumed_strings[this->assumed_strings_ptr]); - free(this->assumed_strings); - while (this->assumed_keys_ptr--) - free(this->assumed_keys[this->assumed_keys_ptr]); - free(this->assumed_keys); - memset(this, 0, sizeof(mds_kbdc_parsed_t)); + mds_kbdc_tree_free(this->tree); + mds_kbdc_source_code_destroy(this->source_code); + free(this->source_code); + free(this->pathname); + mds_kbdc_parse_error_free_all(this->errors); + while (this->languages_ptr--) + free(this->languages[this->languages_ptr]); + free(this->languages); + while (this->countries_ptr--) + free(this->countries[this->countries_ptr]); + free(this->countries); + free(this->variant); + while (this->assumed_strings_ptr--) + free(this->assumed_strings[this->assumed_strings_ptr]); + free(this->assumed_strings); + while (this->assumed_keys_ptr--) + free(this->assumed_keys[this->assumed_keys_ptr]); + free(this->assumed_keys); + memset(this, 0, sizeof(mds_kbdc_parsed_t)); } @@ -69,9 +71,10 @@ void mds_kbdc_parsed_destroy(mds_kbdc_parsed_t* restrict this) * @param this The parsing result * @return Whether a fatal errors has occurred */ -int mds_kbdc_parsed_is_fatal(mds_kbdc_parsed_t* restrict this) +int +mds_kbdc_parsed_is_fatal(mds_kbdc_parsed_t *restrict this) { - return this->severest_error_level >= MDS_KBDC_PARSE_ERROR_ERROR; + return this->severest_error_level >= MDS_KBDC_PARSE_ERROR_ERROR; } @@ -81,23 +84,22 @@ int mds_kbdc_parsed_is_fatal(mds_kbdc_parsed_t* restrict this) * @param this The parsing result * @param output The output file */ -void mds_kbdc_parsed_print_errors(mds_kbdc_parsed_t* restrict this, FILE* output) +void +mds_kbdc_parsed_print_errors(mds_kbdc_parsed_t *restrict this, FILE *output) { - mds_kbdc_parse_error_t** errors = this->errors; - char* env = getenv("MDS_KBDC_ERRORS_ORDER"); - if (errors == NULL) - return; - if (env && (strcasecmp(env, "reversed") || strcasecmp(env, "reverse"))) - { - while (*errors) - errors++; - while (errors-- != this->errors) - mds_kbdc_parse_error_print(*errors, output); - } - else - while (*errors) - mds_kbdc_parse_error_print(*errors++, output); - + mds_kbdc_parse_error_t **errors = this->errors; + char *env = getenv("MDS_KBDC_ERRORS_ORDER"); + if (!errors) { + return; + } else if (env && (strcasecmp(env, "reversed") || strcasecmp(env, "reverse"))) { + while (*errors) + errors++; + while (errors-- != this->errors) + mds_kbdc_parse_error_print(*errors, output); + } else { + while (*errors) + mds_kbdc_parse_error_print(*errors++, output); + } } @@ -112,49 +114,47 @@ void mds_kbdc_parsed_print_errors(mds_kbdc_parsed_t* restrict this, FILE* output * @param end The byte where the error ended, on the line, exclusive, zero-based * @return The new error on success, `NULL` on error */ -mds_kbdc_parse_error_t* mds_kbdc_parsed_new_error(mds_kbdc_parsed_t* restrict this, int severity, - int error_is_in_file, size_t line, size_t start, size_t end) +mds_kbdc_parse_error_t * +mds_kbdc_parsed_new_error(mds_kbdc_parsed_t *restrict this, int severity, + int error_is_in_file, size_t line, size_t start, size_t end) { - mds_kbdc_parse_error_t* error = NULL; - size_t old_errors_ptr = this->errors_ptr; - int saved_errno; - - if (this->errors_ptr + 1 >= this->errors_size) - { - size_t new_errors_size = this->errors_size ? (this->errors_size << 1) : 2; - mds_kbdc_parse_error_t** new_errors = this->errors; - - fail_if (xrealloc(new_errors, new_errors_size, mds_kbdc_parse_error_t*)); - this->errors = new_errors; - this->errors_size = new_errors_size; - } - - fail_if (xcalloc(error, 1, mds_kbdc_parse_error_t)); - this->errors[this->errors_ptr + 0] = error; - this->errors[this->errors_ptr + 1] = NULL; - this->errors_ptr++; - - error->severity = severity; - if (this->severest_error_level < severity) - this->severest_error_level = severity; - - fail_if (xstrdup(error->pathname, this->pathname)); - - if ((error->error_is_in_file = error_is_in_file)) - { - error->line = line; - error->start = start; - error->end = end; - fail_if (xstrdup(error->code, this->source_code->real_lines[line])); - } - - return error; - fail: - saved_errno = errno; - free(error); - this->errors_ptr = old_errors_ptr; - this->errors[this->errors_ptr] = NULL; - errno = saved_errno; - return NULL; -} + mds_kbdc_parse_error_t *error = NULL, **new_errors; + size_t old_errors_ptr = this->errors_ptr, new_errors_size; + int saved_errno; + + if (this->errors_ptr + 1 >= this->errors_size) { + new_errors_size = this->errors_size ? (this->errors_size << 1) : 2; + new_errors = this->errors; + + fail_if (xrealloc(new_errors, new_errors_size, mds_kbdc_parse_error_t*)); + this->errors = new_errors; + this->errors_size = new_errors_size; + } + + fail_if (xcalloc(error, 1, mds_kbdc_parse_error_t)); + this->errors[this->errors_ptr + 0] = error; + this->errors[this->errors_ptr + 1] = NULL; + this->errors_ptr++; + error->severity = severity; + if (this->severest_error_level < severity) + this->severest_error_level = severity; + + fail_if (xstrdup(error->pathname, this->pathname)); + + if ((error->error_is_in_file = error_is_in_file)) { + error->line = line; + error->start = start; + error->end = end; + fail_if (xstrdup(error->code, this->source_code->real_lines[line])); + } + + return error; +fail: + saved_errno = errno; + free(error); + this->errors_ptr = old_errors_ptr; + this->errors[this->errors_ptr] = NULL; + errno = saved_errno; + return NULL; +} diff --git a/src/mds-kbdc/parsed.h b/src/mds-kbdc/parsed.h index 7d01695..58ad6fa 100644 --- a/src/mds-kbdc/parsed.h +++ b/src/mds-kbdc/parsed.h @@ -42,15 +42,13 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR_(RESULT, SEVERITY, ERROR_IS_IN_FILE, LINE, START, END, WITH_DESCRIPTION, ...) \ - do \ - { \ - error = mds_kbdc_parsed_new_error(RESULT, MDS_KBDC_PARSE_ERROR_##SEVERITY, \ - ERROR_IS_IN_FILE, LINE, START, END); \ - fail_if (error == NULL); \ - fail_if (WITH_DESCRIPTION && xasprintf(error->description, __VA_ARGS__)); \ - } \ - while (0) +#define NEW_ERROR_(RESULT, SEVERITY, ERROR_IS_IN_FILE, LINE, START, END, WITH_DESCRIPTION, ...)\ + do {\ + error = mds_kbdc_parsed_new_error(RESULT, MDS_KBDC_PARSE_ERROR_##SEVERITY,\ + ERROR_IS_IN_FILE, LINE, START, END);\ + fail_if (!error);\ + fail_if (WITH_DESCRIPTION && xasprintf(error->description, __VA_ARGS__));\ + } while (0) @@ -58,115 +56,113 @@ * Structure with parsed tree, error list * source code and the file's pathname */ -typedef struct mds_kbdc_parsed -{ - /** - * The parsed tree - */ - mds_kbdc_tree_t* tree; - - /** - * The source code of the parsed file - */ - mds_kbdc_source_code_t* source_code; - - /** - * A non-relative pathname to the parsed file. - * Relative filenames can be misleading as the - * program can have changed working directory - * to be able to resolve filenames. - */ - char* pathname; - - /** - * `NULL`-terminated list of found errors - * `NULL` if no errors that could be listed - * were found - */ - mds_kbdc_parse_error_t** errors; - - /** - * The number of elements allocated to `errors` - */ - size_t errors_size; - - /** - * The number of elements stored in `errors` - */ - size_t errors_ptr; - - /** - * The level of the severest countered error, - * 0 if none has been encountered. - */ - int severest_error_level; - - /** - * List of languages for which the layout is designed - */ - char** languages; - - /** - * The number of elements allocated to `languages` - */ - size_t languages_size; - - /** - * The number of elements stored in `languages` - */ - size_t languages_ptr; - - /** - * List of countries for which the layout is designed - */ - char** countries; - - /** - * The number of elements allocated to `countries` - */ - size_t countries_size; - - /** - * The number of elements stored in `countries` - */ - size_t countries_ptr; - - /** - * The variant of the keyboard for the languages/countries, - * `NULL` if not specified - */ - char* variant; - - /** - * List of strings the assembler should assume are provided - */ - char32_t** assumed_strings; - - /** - * The number of elements allocated to `assumed_strings` - */ - size_t assumed_strings_size; - - /** - * The number of elements stored in `assumed_strings` - */ - size_t assumed_strings_ptr; - - /** - * List of keys the assembler should assume are provided - */ - char32_t** assumed_keys; - - /** - * The number of elements allocated to `assumed_keys` - */ - size_t assumed_keys_size; - - /** - * The number of elements stored in `assumed_keys` - */ - size_t assumed_keys_ptr; - +typedef struct mds_kbdc_parsed { + /** + * The parsed tree + */ + mds_kbdc_tree_t *tree; + + /** + * The source code of the parsed file + */ + mds_kbdc_source_code_t *source_code; + + /** + * A non-relative pathname to the parsed file. + * Relative filenames can be misleading as the + * program can have changed working directory + * to be able to resolve filenames. + */ + char *pathname; + + /** + * `NULL`-terminated list of found errors + * `NULL` if no errors that could be listed + * were found + */ + mds_kbdc_parse_error_t **errors; + + /** + * The number of elements allocated to `errors` + */ + size_t errors_size; + + /** + * The number of elements stored in `errors` + */ + size_t errors_ptr; + + /** + * The level of the severest countered error, + * 0 if none has been encountered. + */ + int severest_error_level; + + /** + * List of languages for which the layout is designed + */ + char **languages; + + /** + * The number of elements allocated to `languages` + */ + size_t languages_size; + + /** + * The number of elements stored in `languages` + */ + size_t languages_ptr; + + /** + * List of countries for which the layout is designed + */ + char **countries; + + /** + * The number of elements allocated to `countries` + */ + size_t countries_size; + + /** + * The number of elements stored in `countries` + */ + size_t countries_ptr; + + /** + * The variant of the keyboard for the languages/countries, + * `NULL` if not specified + */ + char *variant; + + /** + * List of strings the assembler should assume are provided + */ + char32_t **assumed_strings; + + /** + * The number of elements allocated to `assumed_strings` + */ + size_t assumed_strings_size; + + /** + * The number of elements stored in `assumed_strings` + */ + size_t assumed_strings_ptr; + + /** + * List of keys the assembler should assume are provided + */ + char32_t **assumed_keys; + + /** + * The number of elements allocated to `assumed_keys` + */ + size_t assumed_keys_size; + + /** + * The number of elements stored in `assumed_keys` + */ + size_t assumed_keys_ptr; } mds_kbdc_parsed_t; @@ -176,14 +172,14 @@ typedef struct mds_kbdc_parsed * * @param this The `mds_kbdc_parsed_t*` */ -void mds_kbdc_parsed_initialise(mds_kbdc_parsed_t* restrict this); +void mds_kbdc_parsed_initialise(mds_kbdc_parsed_t *restrict this); /** * Release all resources allocated in a `mds_kbdc_parsed_t*` * * @param this The `mds_kbdc_parsed_t*` */ -void mds_kbdc_parsed_destroy(mds_kbdc_parsed_t* restrict this); +void mds_kbdc_parsed_destroy(mds_kbdc_parsed_t *restrict this); /** * Check whether a fatal errors has occurred @@ -191,7 +187,8 @@ void mds_kbdc_parsed_destroy(mds_kbdc_parsed_t* restrict this); * @param this The parsing result * @return Whether a fatal errors has occurred */ -int mds_kbdc_parsed_is_fatal(mds_kbdc_parsed_t* restrict this) __attribute__((pure)); +__attribute__((pure)) +int mds_kbdc_parsed_is_fatal(mds_kbdc_parsed_t *restrict this); /** * Print all encountered errors @@ -199,7 +196,7 @@ int mds_kbdc_parsed_is_fatal(mds_kbdc_parsed_t* restrict this) __attribute__((pu * @param this The parsing result * @param output The output file */ -void mds_kbdc_parsed_print_errors(mds_kbdc_parsed_t* restrict this, FILE* output); +void mds_kbdc_parsed_print_errors(mds_kbdc_parsed_t *restrict this, FILE *output); /** * Add a new error to the list @@ -212,9 +209,8 @@ void mds_kbdc_parsed_print_errors(mds_kbdc_parsed_t* restrict this, FILE* output * @param end The byte where the error ended, on the line, exclusive, zero-based * @return The new error on success, `NULL` on error */ -mds_kbdc_parse_error_t* mds_kbdc_parsed_new_error(mds_kbdc_parsed_t* restrict this, int severity, - int error_is_in_file, size_t line, size_t start, size_t end); +mds_kbdc_parse_error_t *mds_kbdc_parsed_new_error(mds_kbdc_parsed_t *restrict this, int severity, + int error_is_in_file, size_t line, size_t start, size_t end); #endif - diff --git a/src/mds-kbdc/paths.c b/src/mds-kbdc/paths.c index 53ae6fa..70bddf1 100644 --- a/src/mds-kbdc/paths.c +++ b/src/mds-kbdc/paths.c @@ -31,32 +31,32 @@ * * @return The current working directory */ -char* curpath(void) +char * +curpath(void) { - static size_t cwd_size = 4096; - char* cwd = NULL; - char* old = NULL; - int saved_errno; - - /* glibc offers ways to do this in just one function call, - * but we will not assume that glibc is used here. */ - for (;;) - { - fail_if (xxrealloc(old, cwd, cwd_size + 1, char)); - if (getcwd(cwd, cwd_size)) - break; - else - fail_if (errno != ERANGE); - cwd_size <<= 1; - } - - return cwd; - fail: - saved_errno = errno; - free(old); - free(cwd); - errno = saved_errno; - return NULL; + static size_t cwd_size = 4096; + char *cwd = NULL; + char *old = NULL; + int saved_errno; + + /* glibc offers ways to do this in just one function call, + * but we will not assume that glibc is used here. */ + for (;;) { + fail_if (xxrealloc(old, cwd, cwd_size + 1, char)); + if (getcwd(cwd, cwd_size)) + break; + else + fail_if (errno != ERANGE); + cwd_size <<= 1; + } + + return cwd; +fail: + saved_errno = errno; + free(old); + free(cwd); + errno = saved_errno; + return NULL; } @@ -66,53 +66,51 @@ char* curpath(void) * @param path The filename of the file * @return The file's absolute path, `NULL` on error */ -char* abspath(const char* path) +char * +abspath(const char *path) { - char* cwd = NULL; - char* buf = NULL; - int saved_errno, slash = 1; - size_t size, p; - - if (*path == '/') - { - fail_if (xstrdup(buf, path)); - return buf; - } - - fail_if (cwd = curpath(), cwd == NULL); - size = (p = strlen(cwd)) + strlen(path) + 2; - fail_if (xmalloc(buf, size + 1, char)); - memcpy(buf, cwd, (p + 1) * sizeof(char)); - if (buf[p - 1] != '/') - buf[p++] = '/'; - - while (*path) - if (slash && (path[0] == '/')) - path += 1; - else if (slash && (path[0] == '.') && (path[1] == '/')) - path += 2; - else if (slash && (path[0] == '.') && (path[1] == '.') && (path[2] == '/')) - { - path += 3; - p--; - while (p && (buf[--p] != '/')); - p++; - } - else - { - buf[p++] = *path; - slash = (*path++ == '/'); - } - - buf[p] = '\0'; - - free(cwd); - return buf; - fail: - saved_errno = errno; - free(cwd); - errno = saved_errno; - return NULL; + char *cwd = NULL; + char *buf = NULL; + int saved_errno, slash = 1; + size_t size, p; + + if (*path == '/') { + fail_if (xstrdup(buf, path)); + return buf; + } + + fail_if (!(cwd = curpath())); + size = (p = strlen(cwd)) + strlen(path) + 2; + fail_if (xmalloc(buf, size + 1, char)); + memcpy(buf, cwd, (p + 1) * sizeof(char)); + if (buf[p - 1] != '/') + buf[p++] = '/'; + + while (*path) { + if (slash && path[0] == '/') { + path += 1; + } else if (slash && path[0] == '.' && path[1] == '/') { + path += 2; + } else if (slash && path[0] == '.' && path[1] == '.' && path[2] == '/') { + path += 3; + p--; + while (p && buf[--p] != '/'); + p++; + } else { + buf[p++] = *path; + slash = *path++ == '/'; + } + } + + buf[p] = '\0'; + + free(cwd); + return buf; +fail: + saved_errno = errno; + free(cwd); + errno = saved_errno; + return NULL; } @@ -124,46 +122,46 @@ char* abspath(const char* path) * `NULL` for the current working directroy * @return The file's relative path, `NULL` on error */ -char* relpath(const char* path, const char* base) +char * +relpath(const char *path, const char *base) { - char* abs = abspath(path); - char* absbase = NULL; - char* buf = NULL; - char* old = NULL; - int saved_errno; - size_t p, slash = 1, back = 0; - - fail_if (abs == NULL); - absbase = base ? abspath(base) : curpath(); - fail_if (absbase == NULL); - - if (absbase[strlen(absbase) - 1] != '/') - /* Both `abspath` and `curpath` (and `relpath`) allocates one extra slot. */ - absbase[strlen(absbase) + 1] = '\0', absbase[strlen(absbase)] = '/'; - - for (p = 1; abs[p] && absbase[p] && (abs[p] == absbase[p]); p++) - if (abs[p] == '/') - slash = p + 1; - - for (p = slash; absbase[p]; p++) - if (absbase[p] == '/') - back++; - - fail_if (xmalloc(buf, back * 3 + strlen(abs + slash) + 2, char)); - - for (p = 0; back--;) - buf[p++] = '.', buf[p++] = '.', buf[p++] = '/'; - memcpy(buf + p, abs + slash, (strlen(abs + slash) + 1) * sizeof(char)); - - free(abs); - free(absbase); - return buf; - fail: - saved_errno = errno; - free(abs); - free(absbase); - free(old); - errno = saved_errno; - return NULL; -} + char *abs = abspath(path); + char *absbase = NULL; + char *buf = NULL; + char *old = NULL; + int saved_errno; + size_t p, slash = 1, back = 0; + fail_if (!abs); + absbase = base ? abspath(base) : curpath(); + fail_if (!absbase); + + if (absbase[strlen(absbase) - 1] != '/') + /* Both `abspath` and `curpath` (and `relpath`) allocates one extra slot. */ + absbase[strlen(absbase) + 1] = '\0', absbase[strlen(absbase)] = '/'; + + for (p = 1; abs[p] && absbase[p] && abs[p] == absbase[p]; p++) + if (abs[p] == '/') + slash = p + 1; + + for (p = slash; absbase[p]; p++) + if (absbase[p] == '/') + back++; + + fail_if (xmalloc(buf, back * 3 + strlen(abs + slash) + 2, char)); + + for (p = 0; back--;) + buf[p++] = '.', buf[p++] = '.', buf[p++] = '/'; + memcpy(buf + p, abs + slash, (strlen(abs + slash) + 1) * sizeof(char)); + + free(abs); + free(absbase); + return buf; +fail: + saved_errno = errno; + free(abs); + free(absbase); + free(old); + errno = saved_errno; + return NULL; +} diff --git a/src/mds-kbdc/paths.h b/src/mds-kbdc/paths.h index 6c24042..6dbe007 100644 --- a/src/mds-kbdc/paths.h +++ b/src/mds-kbdc/paths.h @@ -24,7 +24,7 @@ * * @return The current working directory */ -char* curpath(void); +char *curpath(void); /** * Get the absolute path of a file @@ -32,7 +32,7 @@ char* curpath(void); * @param path The filename of the file * @return The file's absolute path, `NULL` on error */ -char* abspath(const char* path); +char *abspath(const char *path); /** * Get a relative path of a file @@ -42,8 +42,7 @@ char* abspath(const char* path); * `NULL` for the current working directroy * @return The file's relative path, `NULL` on error */ -char* relpath(const char* path, const char* base); +char *relpath(const char* path, const char *base); #endif - diff --git a/src/mds-kbdc/process-includes.c b/src/mds-kbdc/process-includes.c index 69b9c73..a46533c 100644 --- a/src/mds-kbdc/process-includes.c +++ b/src/mds-kbdc/process-includes.c @@ -32,7 +32,7 @@ /** * Tree type constant shortener */ -#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE +#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE /** * Add an error to the error list @@ -42,26 +42,26 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(NODE, SEVERITY, ...) \ - NEW_ERROR_(result, SEVERITY, 1, (NODE)->loc_line, \ - (NODE)->loc_start, (NODE)->loc_end, 1, __VA_ARGS__) +#define NEW_ERROR(NODE, SEVERITY, ...)\ + NEW_ERROR_(result, SEVERITY, 1, (NODE)->loc_line,\ + (NODE)->loc_start, (NODE)->loc_end, 1, __VA_ARGS__) /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The parameter of `process_includes` */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; /** * Stack of attributes of already included files */ -static struct stat* restrict included; +static struct stat *restrict included; /** * The number elements allocated for `included` @@ -81,66 +81,62 @@ static size_t included_ptr = 0; * @param subresult The results of the processed include * @param tree The include statement */ -static int transfer_errors(mds_kbdc_parsed_t* restrict subresult, mds_kbdc_tree_include_t* restrict tree) +static int +transfer_errors(mds_kbdc_parsed_t *restrict subresult, mds_kbdc_tree_include_t *restrict tree) { - mds_kbdc_parse_error_t** errors = NULL; - mds_kbdc_parse_error_t* suberror; - size_t errors_ptr = 0; - int saved_errno, annotated = 0; - - /* Allocate temporary list for errors. */ - if (subresult->errors_ptr == 0) - return 0; - fail_if (xmalloc(errors, subresult->errors_ptr * 2, mds_kbdc_parse_error_t*)); - - /* List errors backwards, so that we can easily handle errors and add “included from here”-note. */ - while (subresult->errors_ptr--) - { - suberror = subresult->errors[subresult->errors_ptr]; - - /* If it is more severe than a note, we want to say there it was included. */ - if (annotated == 0) - { - NEW_ERROR(tree, NOTE, "included from here"); - errors[errors_ptr++] = error; - result->errors[--(result->errors_ptr)] = NULL; - annotated = 1; + mds_kbdc_parse_error_t **errors = NULL, *suberror, **new_errors; + size_t errors_ptr = 0, new_errors_size; + int saved_errno, annotated = 0; + + /* Allocate temporary list for errors. */ + if (!subresult->errors_ptr) + return 0; + fail_if (xmalloc(errors, subresult->errors_ptr * 2, mds_kbdc_parse_error_t*)); + + /* List errors backwards, so that we can easily handle errors and add “included from here”-note. */ + while (subresult->errors_ptr--) { + suberror = subresult->errors[subresult->errors_ptr]; + + /* If it is more severe than a note, we want to say there it was included. */ + if (!annotated) { + NEW_ERROR(tree, NOTE, "included from here"); + errors[errors_ptr++] = error; + result->errors[--(result->errors_ptr)] = NULL; + annotated = 1; + } + + /* Include error. */ + errors[errors_ptr++] = suberror; + subresult->errors[subresult->errors_ptr] = NULL; + + /* Make sure when there are nested inclusions that the outermost inclusion * is annotated last. */ + if (suberror->severity > MDS_KBDC_PARSE_ERROR_NOTE) + annotated = 0; } - - /* Include error. */ - errors[errors_ptr++] = suberror; - subresult->errors[subresult->errors_ptr] = NULL; - - /* Make sure when there are nested inclusions that the outermost inclusion * is annotated last. */ - if (suberror->severity > MDS_KBDC_PARSE_ERROR_NOTE) - annotated = 0; - } - - /* Append errors. */ - for (; errors_ptr--; errors[errors_ptr] = NULL) - { - if (result->errors_ptr + 1 >= result->errors_size) - { - size_t new_errors_size = result->errors_size ? (result->errors_size << 1) : 2; - mds_kbdc_parse_error_t** new_errors = result->errors; - - fail_if (xrealloc(new_errors, new_errors_size, mds_kbdc_parse_error_t*)); - result->errors = new_errors; - result->errors_size = new_errors_size; + + /* Append errors. */ + for (; errors_ptr--; errors[errors_ptr] = NULL) { + if (result->errors_ptr + 1 >= result->errors_size) { + new_errors_size = result->errors_size ? (result->errors_size << 1) : 2; + new_errors = result->errors; + + fail_if (xrealloc(new_errors, new_errors_size, mds_kbdc_parse_error_t*)); + result->errors = new_errors; + result->errors_size = new_errors_size; + } + + result->errors[result->errors_ptr++] = errors[errors_ptr]; + result->errors[result->errors_ptr] = NULL; } - - result->errors[result->errors_ptr++] = errors[errors_ptr]; - result->errors[result->errors_ptr] = NULL; - } - - free(errors); - return 0; - fail: - saved_errno = errno; - while (errors_ptr--) - mds_kbdc_parse_error_free(errors[errors_ptr]); - free(errors); - return errno = saved_errno, -1; + + free(errors); + return 0; +fail: + saved_errno = errno; + while (errors_ptr--) + mds_kbdc_parse_error_free(errors[errors_ptr]); + free(errors); + return errno = saved_errno, -1; } @@ -150,86 +146,83 @@ static int transfer_errors(mds_kbdc_parsed_t* restrict subresult, mds_kbdc_tree_ * @param tree The include-statement * @return Zero on success, -1 on error */ -static int process_include(mds_kbdc_tree_include_t* restrict tree) +static int +process_include(mds_kbdc_tree_include_t *restrict tree) { -#define process(expr) \ - fail_if ((expr) < 0); \ - if (mds_kbdc_parsed_is_fatal(&subresult)) \ - goto stop; - - mds_kbdc_parsed_t subresult; - mds_kbdc_parsed_t* our_result; - char* dirname = NULL; - char* cwd = NULL; - char* old = NULL; - size_t cwd_size = 4096 >> 1; - int saved_errno; - - /* Initialise result structure for the included file. */ - mds_kbdc_parsed_initialise(&subresult); - - /* Get dirname of current file. */ - fail_if (xstrdup(dirname, result->pathname)); - *(strrchr(dirname, '/')) = '\0'; - - /* Get the current working directory. */ - /* glibc offers ways to do this in just one function call, - * but we will not assume that glibc is used here. */ - for (;;) - { - fail_if (xxrealloc(old, cwd, cwd_size <<= 1, char)); - if (getcwd(cwd, cwd_size)) - break; - else - fail_if (errno != ERANGE); - } - - /* Switch working directory. */ - fail_if (chdir(dirname)); - free(dirname), dirname = NULL; - - /* Store `result` as it will be switched by the inner `process_includes`. */ - our_result = result; - - /* Process include. */ - old = tree->filename, tree->filename = NULL; - tree->filename = parse_raw_string(old); - fail_if (tree->filename == NULL); - free(old), old = NULL; - process (parse_to_tree(tree->filename, &subresult)); - process (simplify_tree(&subresult)); - process (process_includes(&subresult)); - stop: - - /* Switch back `result`. */ - result = our_result; - - /* Switch back to the old working directory. */ - fail_if (chdir(cwd)); - free(cwd), cwd = NULL; - - /* Move over data to our result. */ - free(tree->filename); - tree->filename = subresult.pathname, subresult.pathname = NULL; - tree->source_code = subresult.source_code, subresult.source_code = NULL; - tree->inner = subresult.tree, subresult.tree = NULL; - if (result->severest_error_level < subresult.severest_error_level) - result->severest_error_level = subresult.severest_error_level; - - /* Move over errors. */ - fail_if (transfer_errors(&subresult, tree)); - - /* Release resources. */ - mds_kbdc_parsed_destroy(&subresult); - - return 0; - fail: - saved_errno = errno; - free(dirname); - free(cwd); - free(old); - mds_kbdc_parsed_destroy(&subresult); - return errno = saved_errno, -1; +#define process(expr)\ + fail_if ((expr) < 0);\ + if (mds_kbdc_parsed_is_fatal(&subresult))\ + goto stop; + + mds_kbdc_parsed_t subresult, *our_result; + char *dirname = NULL, *cwd = NULL, *old = NULL; + size_t cwd_size = 4096 >> 1; + int saved_errno; + + /* Initialise result structure for the included file. */ + mds_kbdc_parsed_initialise(&subresult); + + /* Get dirname of current file. */ + fail_if (xstrdup(dirname, result->pathname)); + *(strrchr(dirname, '/')) = '\0'; + + /* Get the current working directory. */ + /* glibc offers ways to do this in just one function call, + * but we will not assume that glibc is used here. */ + for (;;) { + fail_if (xxrealloc(old, cwd, cwd_size <<= 1, char)); + if (getcwd(cwd, cwd_size)) + break; + else + fail_if (errno != ERANGE); + } + + /* Switch working directory. */ + fail_if (chdir(dirname)); + free(dirname), dirname = NULL; + + /* Store `result` as it will be switched by the inner `process_includes`. */ + our_result = result; + + /* Process include. */ + old = tree->filename, tree->filename = NULL; + tree->filename = parse_raw_string(old); + fail_if (tree->filename == NULL); + free(old), old = NULL; + process (parse_to_tree(tree->filename, &subresult)); + process (simplify_tree(&subresult)); + process (process_includes(&subresult)); +stop: + + /* Switch back `result`. */ + result = our_result; + + /* Switch back to the old working directory. */ + fail_if (chdir(cwd)); + free(cwd), cwd = NULL; + + /* Move over data to our result. */ + free(tree->filename); + tree->filename = subresult.pathname, subresult.pathname = NULL; + tree->source_code = subresult.source_code, subresult.source_code = NULL; + tree->inner = subresult.tree, subresult.tree = NULL; + if (result->severest_error_level < subresult.severest_error_level) + result->severest_error_level = subresult.severest_error_level; + + /* Move over errors. */ + fail_if (transfer_errors(&subresult, tree)); + + /* Release resources. */ + mds_kbdc_parsed_destroy(&subresult); + + return 0; +fail: + saved_errno = errno; + free(dirname); + free(cwd); + free(old); + mds_kbdc_parsed_destroy(&subresult); + return errno = saved_errno, -1; #undef process } @@ -240,32 +233,32 @@ static int process_include(mds_kbdc_tree_include_t* restrict tree) * @param tree The tree * @return Zero on success, -1 on error */ -static int process_includes_in_tree(mds_kbdc_tree_t* restrict tree) +static int +process_includes_in_tree(mds_kbdc_tree_t *restrict tree) { -#define p(expr) fail_if (process_includes_in_tree(tree->expr)) - again: - if (tree == NULL) - return 0; - - switch (tree->type) - { - case C(INFORMATION): p (information.inner); break; - case C(FUNCTION): p (function.inner); break; - case C(MACRO): p (macro.inner); break; - case C(ASSUMPTION): p (assumption.inner); break; - case C(FOR): p (for_.inner); break; - case C(IF): p (if_.inner); p (if_.otherwise); break; - case C(INCLUDE): - fail_if (process_include(&(tree->include))); - break; - default: - break; - } - - tree = tree->next; - goto again; - fail: - return -1; +#define p(expr) fail_if (process_includes_in_tree(tree->expr)) +again: + if (!tree) + return 0; + + switch (tree->type) { + case C(INFORMATION): p (information.inner); break; + case C(FUNCTION): p (function.inner); break; + case C(MACRO): p (macro.inner); break; + case C(ASSUMPTION): p (assumption.inner); break; + case C(FOR): p (for_.inner); break; + case C(IF): p (if_.inner); p (if_.otherwise); break; + case C(INCLUDE): + fail_if (process_include(&(tree->include))); + break; + default: + break; + } + + tree = tree->next; + goto again; +fail: + return -1; #undef p } @@ -276,45 +269,43 @@ static int process_includes_in_tree(mds_kbdc_tree_t* restrict tree) * @param result_ `result` from `simplify_tree`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int process_includes(mds_kbdc_parsed_t* restrict result_) +int +process_includes(mds_kbdc_parsed_t *restrict result_) { - int r, saved_errno; - struct stat attr; - size_t i; - - result = result_; - - fail_if (stat(result->pathname, &attr)); - - if (included_ptr == included_size) - { - struct stat* old; - if (xxrealloc(old, included, included_size += 4, struct stat)) - fail_if (included = old, 1); - } - - for (i = 0; i < included_ptr; i++) - if ((included[i].st_dev == attr.st_dev) && (included[i].st_ino == attr.st_ino)) - { - NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 1, "resursive inclusion"); - return 0; - } - - included[included_ptr++] = attr; - - r = process_includes_in_tree(result_->tree); - saved_errno = errno; - - if (--included_ptr == 0) - free(included), included_size = 0; - - return errno = saved_errno, r; - fail: - return -1; + int r, saved_errno; + struct stat attr, *old; + size_t i; + + result = result_; + + fail_if (stat(result->pathname, &attr)); + + if (included_ptr == included_size) { + if (xxrealloc(old, included, included_size += 4, struct stat)) + fail_if (included = old, 1); + } + + for (i = 0; i < included_ptr; i++) { + if ((included[i].st_dev == attr.st_dev) && (included[i].st_ino == attr.st_ino)) { + NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 1, "resursive inclusion"); + return 0; + } + } + + included[included_ptr++] = attr; + + r = process_includes_in_tree(result_->tree); + saved_errno = errno; + + if (!--included_ptr) + free(included), included_size = 0; + + return errno = saved_errno, r; +fail: + return -1; } #undef NEW_ERROR #undef C - diff --git a/src/mds-kbdc/process-includes.h b/src/mds-kbdc/process-includes.h index 5644dd9..6146600 100644 --- a/src/mds-kbdc/process-includes.h +++ b/src/mds-kbdc/process-includes.h @@ -28,8 +28,7 @@ * @param result `result` from `simplify_tree`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int process_includes(mds_kbdc_parsed_t* restrict result); +int process_includes(mds_kbdc_parsed_t *restrict result); #endif - diff --git a/src/mds-kbdc/raw-data.c b/src/mds-kbdc/raw-data.c index e40be68..2b89840 100644 --- a/src/mds-kbdc/raw-data.c +++ b/src/mds-kbdc/raw-data.c @@ -39,14 +39,15 @@ * * @param this The `mds_kbdc_source_code_t*` */ -void mds_kbdc_source_code_initialise(mds_kbdc_source_code_t* restrict this) +void +mds_kbdc_source_code_initialise(mds_kbdc_source_code_t *restrict this) { - this->lines = NULL; - this->real_lines = NULL; - this->content = NULL; - this->real_content = NULL; - this->line_count = 0; - this->duplicates = 0; + this->lines = NULL; + this->real_lines = NULL; + this->content = NULL; + this->real_content = NULL; + this->line_count = 0; + this->duplicates = 0; } @@ -55,16 +56,17 @@ void mds_kbdc_source_code_initialise(mds_kbdc_source_code_t* restrict this) * * @param this The `mds_kbdc_source_code_t*` */ -void mds_kbdc_source_code_destroy(mds_kbdc_source_code_t* restrict this) +void +mds_kbdc_source_code_destroy(mds_kbdc_source_code_t *restrict this) { - if (this == NULL) - return; - if (this->duplicates--) - return; - free(this->lines), this->lines = NULL; - free(this->real_lines), this->real_lines = NULL; - free(this->content), this->content = NULL; - free(this->real_content), this->real_content = NULL; + if (!this) + return; + if (this->duplicates--) + return; + free(this->lines), this->lines = NULL; + free(this->real_lines), this->real_lines = NULL; + free(this->content), this->content = NULL; + free(this->real_content), this->real_content = NULL; } @@ -73,17 +75,18 @@ void mds_kbdc_source_code_destroy(mds_kbdc_source_code_t* restrict this) * * @param this The `mds_kbdc_source_code_t*` */ -void mds_kbdc_source_code_free(mds_kbdc_source_code_t* restrict this) +void +mds_kbdc_source_code_free(mds_kbdc_source_code_t *restrict this) { - if (this == NULL) - return; - if (this->duplicates--) - return; - free(this->lines); - free(this->real_lines); - free(this->content); - free(this->real_content); - free(this); + if (!this) + return; + if (this->duplicates--) + return; + free(this->lines); + free(this->real_lines); + free(this->content); + free(this->real_content); + free(this); } /** @@ -92,10 +95,11 @@ void mds_kbdc_source_code_free(mds_kbdc_source_code_t* restrict this) * @param this The `mds_kbdc_source_code_t*` * @return `this` is returned */ -mds_kbdc_source_code_t* mds_kbdc_source_code_dup(mds_kbdc_source_code_t* restrict this) +mds_kbdc_source_code_t * +mds_kbdc_source_code_dup(mds_kbdc_source_code_t *restrict this) { - this->duplicates++; - return this; + this->duplicates++; + return this; } @@ -107,51 +111,51 @@ mds_kbdc_source_code_t* mds_kbdc_source_code_dup(mds_kbdc_source_code_t* restric * @param size Output parameter for the size of the read content, in char:s * @return The read content, `NULL` on error */ -static char* read_file(const char* restrict pathname, size_t* restrict size) +static char * +read_file(const char *restrict pathname, size_t *restrict size) { - size_t buf_size = 8096; - size_t buf_ptr = 0; - char* restrict content = NULL; - char* restrict old = NULL; - int fd = -1; - ssize_t got; - - /* Allocate buffer for the file's content. */ - fail_if (xmalloc(content, buf_size, char)); - /* Open the file to compile. */ - fail_if ((fd = open(pathname, O_RDONLY)) < 0); - - /* Read the file to compile. */ - for (;;) - { - /* Make sure the buffer is not small. */ - if (buf_size - buf_ptr < 2048) - fail_if (xxrealloc(old, content, buf_size <<= 1, char)); - /* Read a chunk of the file. */ - got = read(fd, content + buf_ptr, (buf_size - buf_ptr) * sizeof(char)); - if ((got < 0) && (errno == EINTR)) continue; - if (got == 0) break; - fail_if (got < 0); - buf_ptr += (size_t)got; - } - - /* Shrink the buffer so it is not excessively large. */ - if (buf_ptr) /* Simplest way to handle empty files: let the have the initial allocation size. */ - fail_if (xxrealloc(old, content, buf_ptr, char)); - - /* Close file decriptor for the file. */ - xclose(fd); - - *size = buf_ptr; - return content; - - fail: - xperror(*argv); - free(old); - free(content); - if (fd >= 0) - xclose(fd); - return NULL; + size_t buf_size = 8096; + size_t buf_ptr = 0; + char *restrict content = NULL; + char *restrict old = NULL; + int fd = -1; + ssize_t got; + + /* Allocate buffer for the file's content. */ + fail_if (xmalloc(content, buf_size, char)); + /* Open the file to compile. */ + fail_if ((fd = open(pathname, O_RDONLY)) < 0); + + /* Read the file to compile. */ + for (;;) { + /* Make sure the buffer is not small. */ + if (buf_size - buf_ptr < 2048) + fail_if (xxrealloc(old, content, buf_size <<= 1, char)); + /* Read a chunk of the file. */ + got = read(fd, content + buf_ptr, (buf_size - buf_ptr) * sizeof(char)); + if (got < 0 && errno == EINTR) continue; + if (got == 0) break; + fail_if (got < 0); + buf_ptr += (size_t)got; + } + + /* Shrink the buffer so it is not excessively large. */ + if (buf_ptr) /* Simplest way to handle empty files: let the have the initial allocation size. */ + fail_if (xxrealloc(old, content, buf_ptr, char)); + + /* Close file decriptor for the file. */ + xclose(fd); + + *size = buf_ptr; + return content; + +fail: + xperror(*argv); + free(old); + free(content); + if (fd >= 0) + xclose(fd); + return NULL; } @@ -167,54 +171,59 @@ static char* read_file(const char* restrict pathname, size_t* restrict size) * or `size` if the call do not end (that is, the code ends * prematurely), or zero if there is no function call at `offset` */ -size_t get_end_of_call(const char* restrict content, size_t offset, size_t size) +size_t +get_end_of_call(const char *restrict content, size_t offset, size_t size) { -#define C content[ptr] -#define r(lower, upper) (((lower) <= C) && (C <= (upper))) - - size_t ptr = offset, call_end = 0; - int escape = 0, quote = 0; - - /* Skip to end of function name. */ - while ((ptr < size) && (r('a', 'z') || r('A', 'Z') || r('0', '9') || (C == '_'))) - ptr++; - - /* Check that it is a function call. */ - if ((ptr == size) || (ptr == offset) || (C != '(')) - return 0; - - /* Find the end of the function call. */ - while (ptr < size) - { - char c = content[ptr++]; - - /* Escapes may be longer than one character, - but only the first can affect the parsing. */ - if (escape) escape = 0; - /* Nested function and nested quotes can appear. */ - else if (ptr <= call_end) ; - /* Quotes end with the same symbols as they start with, - and quotes automatically escape brackets. */ - /* \ can either start a functon call or an escape. */ - else if (c == '\\') - { - /* It may not be an escape, but registering it - as an escape cannot harm us since we only - skip the first character, and a function call - cannot be that short. */ - escape = 1; - /* Nested quotes can appear at function calls. */ - call_end = get_end_of_call(content, ptr, size); +#define C content[ptr] +#define r(lower, upper) ((lower) <= C && C <= (upper)) + + size_t ptr = offset, call_end = 0; + int escape = 0, quote = 0; + char c; + + /* Skip to end of function name. */ + while (ptr < size && (r('a', 'z') || r('A', 'Z') || r('0', '9') || (C == '_'))) + ptr++; + + /* Check that it is a function call. */ + if (ptr == size || ptr == offset || C != '(') + return 0; + + /* Find the end of the function call. */ + while (ptr < size) { + c = content[ptr++]; + + if (escape) { + /* Escapes may be longer than one character, + but only the first can affect the parsing. */ + escape = 0; + } else if (ptr <= call_end) { + /* Nested function and nested quotes can appear. */; + } else if (c == '\\') { + /* Quotes end with the same symbols as they start with, + and quotes automatically escape brackets. */ + /* \ can either start a functon call or an escape. */ + + /* It may not be an escape, but registering it + as an escape cannot harm us since we only + skip the first character, and a function call + cannot be that short. */ + escape = 1; + /* Nested quotes can appear at function calls. */ + call_end = get_end_of_call(content, ptr, size); + } else if (quote) { + quote = (c != '"'); + } else if (c == ')') { + /* End of function call, end of fun. */ + break; + } else if (c == '"') { + /* " is the quote symbol. */ + quote = 1; + } } - else if (quote) quote = (c != '"'); - /* End of function call, end of fun. */ - else if (c == ')') break; - /* " is the quote symbol. */ - else if (c == '"') quote = 1; - } - - return ptr; - + + return ptr; + #undef r #undef C } @@ -227,55 +236,58 @@ size_t get_end_of_call(const char* restrict content, size_t offset, size_t size) * @param size The size of `content`, in char:s * @return The new size of `content`, in char:s; this function cannot fail */ -static size_t remove_comments(char* restrict content, size_t size) +static size_t +remove_comments(char *restrict content, size_t size) { -#define t content[n_ptr++] = c - - size_t n_ptr = 0, o_ptr = 0, call_end = 0; - int comment = 0, quote = 0, escape = 0; - - while (o_ptr < size) - { - char c = content[o_ptr++]; - /* Remove comment. */ - if (comment) - { - if (c == '\n') t, comment = 0; - } - /* Escapes may be longer than one character, - but only the first can affect the parsing. */ - else if (escape) t, escape = 0; - /* Nested quotes can appear at function calls. */ - else if (o_ptr <= call_end) t; - /* \ can either start a functon call or an escape. */ - else if (c == '\\') - { - t; - /* It may not be an escape, but registering it - as an escape cannot harm us since we only - skip the first character, and a function call - cannot be that short. */ - escape = 1; - /* Nested quotes can appear at function calls. */ - call_end = get_end_of_call(content, o_ptr, size); - } - /* Quotes end with the same symbols as they start with, - and quotes automatically escape comments. */ - else if (quote) - { - t; - if (strchr("\"\n", c)) quote = 0; +#define t content[n_ptr++] = c + + size_t n_ptr = 0, o_ptr = 0, call_end = 0; + int comment = 0, quote = 0, escape = 0; + char c; + + while (o_ptr < size) { + c = content[o_ptr++]; + if (comment) { + /* Remove comment. */ + if (c == '\n') + t, comment = 0; + } else if (escape) { + /* Escapes may be longer than one character, + but only the first can affect the parsing. */ + t, escape = 0; + } else if (o_ptr <= call_end) { + /* Nested quotes can appear at function calls. */ + t; + } else if (c == '\\') { + /* \ can either start a functon call or an escape. */ + t; + /* It may not be an escape, but registering it + as an escape cannot harm us since we only + skip the first character, and a function call + cannot be that short. */ + escape = 1; + /* Nested quotes can appear at function calls. */ + call_end = get_end_of_call(content, o_ptr, size); + } else if (quote) { + /* Quotes end with the same symbols as they start with, + and quotes automatically escape comments. */ + t; + if (strchr("\"\n", c)) + quote = 0; + } else if (c == '#') { + /* # is the comment symbol. */ + comment = 1; + } else if (c == '"') { + /* " is the quote symbol. */ + t, quote = 1; + } else { + /* Code and whitespace. */ + t; + } } - /* # is the comment symbol. */ - else if (c == '#') comment = 1; - /* " is the quote symbol. */ - else if (c == '"') t, quote = 1; - /* Code and whitespace. */ - else t; - } - - return n_ptr; - + + return n_ptr; + #undef t } @@ -298,36 +310,35 @@ static size_t remove_comments(char* restrict content, size_t size) * `NULL` is returned, and `content` will not * have been modified. */ -static char** line_split(char* content, size_t length) +static char ** +line_split(char *content, size_t length) { - char** restrict lines = NULL; - size_t count = 0; - size_t i, j; - int new_line = 1; - - for (i = 0; i < length; i++) - if (content[i] == '\n') - count++; - - fail_if (xmalloc(lines, count + 1, char*)); - lines[count] = NULL; - - for (i = j = 0; i < length; i++) - { - if (new_line) - new_line = 0, lines[j++] = content + i; - if (content[i] == '\n') - { - new_line = 1; - content[i] = '\0'; + char **restrict lines = NULL; + size_t count = 0; + size_t i, j; + int new_line = 1; + + for (i = 0; i < length; i++) + if (content[i] == '\n') + count++; + + fail_if (xmalloc(lines, count + 1, char*)); + lines[count] = NULL; + + for (i = j = 0; i < length; i++) { + if (new_line) + new_line = 0, lines[j++] = content + i; + if (content[i] == '\n') { + new_line = 1; + content[i] = '\0'; + } } - } - - return lines; - - fail: - xperror(*argv); - return NULL; + + return lines; + +fail: + xperror(*argv); + return NULL; } @@ -338,40 +349,44 @@ static char** line_split(char* content, size_t length) * @param content_size Input and output parameter for the size of the file's content * @return Zero on success, -1 on error */ -static int expand(char** restrict content, size_t* restrict content_size) +static int +expand(char **restrict content, size_t *restrict content_size) { - size_t extra = 0, added = 0, ptr, col, n = *content_size; - char* restrict data = *content; - - /* Calculate the new size of the file. */ - for (ptr = col = 0; ptr < n; ptr++) - if (data[ptr] == '\n') - col = 0; - else if (data[ptr] == '\t') - extra += 8 - (col % 8) - 1; - - /* Extend the allocation. */ - if (extra == 0) - return 0; - *content_size += extra; - fail_if (xrealloc(data, *content_size, char)); - *content = data; - - /* Expand tab spaces. */ - memmove(data + extra, data, n); - for (ptr = 0; ptr < n; ptr++, added--) - if (data[ptr + extra] == '\n') - data[ptr + added++] = data[ptr + extra], col = 0; - else if (data[ptr + extra] != '\t') - data[ptr + added++] = data[ptr + extra], col++; - else - do - data[ptr + added++] = ' '; - while (++col % 8); - - return 0; - fail: - return -1; + size_t extra = 0, added = 0, ptr, col, n = *content_size; + char *restrict data = *content; + + /* Calculate the new size of the file. */ + for (ptr = col = 0; ptr < n; ptr++) { + if (data[ptr] == '\n') + col = 0; + else if (data[ptr] == '\t') + extra += 8 - (col % 8) - 1; + } + + /* Extend the allocation. */ + if (!extra) + return 0; + *content_size += extra; + fail_if (xrealloc(data, *content_size, char)); + *content = data; + + /* Expand tab spaces. */ + memmove(data + extra, data, n); + for (ptr = 0; ptr < n; ptr++, added--) { + if (data[ptr + extra] == '\n') { + data[ptr + added++] = data[ptr + extra], col = 0; + } else if (data[ptr + extra] != '\t') { + data[ptr + added++] = data[ptr + extra], col++; + } else { + do + data[ptr + added++] = ' '; + while (++col % 8); + } + } + + return 0; +fail: + return -1; } @@ -382,60 +397,60 @@ static int expand(char** restrict content, size_t* restrict content_size) * @param source_code Output parameter for read data * @return Zero on success, -1 on error */ -int read_source_lines(const char* restrict pathname, mds_kbdc_source_code_t* restrict source_code) +int +read_source_lines(const char *restrict pathname, mds_kbdc_source_code_t *restrict source_code) { - char* content = NULL; - char* real_content = NULL; - char* old = NULL; - size_t content_size; - size_t real_content_size; - char** lines = NULL; - char** real_lines = NULL; - size_t line_count = 0; - - /* Read the file. */ - content = read_file(pathname, &content_size); - fail_if (content == NULL); - - /* Expand tab spaces. */ - fail_if (expand(&content, &content_size)); - - /* Make sure the content ends with a new line. */ - if (!content_size || (content[content_size - 1] != '\n')) - { - fail_if (xxrealloc(old, content, content_size + 1, char)); - content[content_size++] = '\n'; - } - - /* Simplify file. */ - fail_if (xmemdup(real_content, content, content_size, char)); - real_content_size = content_size; - content_size = remove_comments(content, content_size); - fail_if (xxrealloc(old, content, content_size, char)); - - /* Split by line. */ - fail_if ((lines = line_split(content, content_size)) == NULL); - fail_if ((real_lines = line_split(real_content, real_content_size)) == NULL); - - /* Count the number of lines. */ - while (lines[line_count] != NULL) - line_count++; - - source_code->lines = lines; - source_code->real_lines = real_lines; - source_code->content = content; - source_code->real_content = real_content; - source_code->line_count = line_count; - return 0; - - fail: - xperror(*argv); - free(old); - free(content); - free(real_content); - free(lines); - free(real_lines); - return -1; + char *content = NULL; + char *real_content = NULL; + char *old = NULL; + size_t content_size; + size_t real_content_size; + char **lines = NULL; + char **real_lines = NULL; + size_t line_count = 0; + + /* Read the file. */ + content = read_file(pathname, &content_size); + fail_if (!content); + + /* Expand tab spaces. */ + fail_if (expand(&content, &content_size)); + + /* Make sure the content ends with a new line. */ + if (!content_size || content[content_size - 1] != '\n') { + fail_if (xxrealloc(old, content, content_size + 1, char)); + content[content_size++] = '\n'; + } + + /* Simplify file. */ + fail_if (xmemdup(real_content, content, content_size, char)); + real_content_size = content_size; + content_size = remove_comments(content, content_size); + fail_if (xxrealloc(old, content, content_size, char)); + + /* Split by line. */ + fail_if (!(lines = line_split(content, content_size))); + fail_if (!(real_lines = line_split(real_content, real_content_size))); + + /* Count the number of lines. */ + while (lines[line_count]) + line_count++; + + source_code->lines = lines; + source_code->real_lines = real_lines; + source_code->content = content; + source_code->real_content = real_content; + source_code->line_count = line_count; + return 0; + +fail: + xperror(*argv); + free(old); + free(content); + free(real_content); + free(lines); + free(real_lines); + return -1; } @@ -446,24 +461,25 @@ int read_source_lines(const char* restrict pathname, mds_kbdc_source_code_t* res * @param character The character * @return The of the character in `buffer`, `NULL` on error */ -static char* encode_utf8(char* buffer, char32_t character) +static char * +encode_utf8(char *buffer, char32_t character) { - char32_t text[2]; - char* restrict str; - char* restrict str_; - - text[0] = character; - text[1] = -1; - - fail_if (str_ = str = string_encode(text), str == NULL); - - while (*str) - *buffer++ = *str++; - - free(str_); - return buffer; - fail: - return NULL; + char32_t text[2]; + char *restrict str; + char *restrict str_; + + text[0] = character; + text[1] = -1; + + fail_if (!(str_ = str = string_encode(text))); + + while (*str) + *buffer++ = *str++; + + free(str_); + return buffer; +fail: + return NULL; } @@ -473,53 +489,57 @@ static char* encode_utf8(char* buffer, char32_t character) * @param string The string * @return The string in machine-readable format, `NULL` on error */ -char* parse_raw_string(const char* restrict string) +char * +parse_raw_string(const char *restrict string) { -#define r(cond, lower, upper) ((cond) && ((lower) <= c) && (c <= (upper))) - char* rc; - char* p; - int escape = 0; - char32_t buf = 0; - char c; - - /* We know that the output string can only be shorter because - * it is surrounded by 2 quotes and escape can only be longer - * then what they escape, for example \uA0, is four characters, - * but when parsed it generateds 2 bytes in UTF-8, and their - * is not code point whose UTF-8 encoding is longer than its - * hexadecimal representation. */ - fail_if (xmalloc(p = rc, strlen(string), char)); - - while ((c = *string++)) - if (r(escape == 8, '0', '7')) buf = (buf << 3) | (c & 15); - else if (r(escape == 16, '0', '9')) buf = (buf << 4) | (c & 15); - else if (r(escape == 16, 'a', 'f')) buf = (buf << 4) | ((c & 15) + 9); - else if (r(escape == 16, 'A', 'F')) buf = (buf << 4) | ((c & 15) + 9); - else if (escape > 1) - { - escape = 0; - fail_if ((p = encode_utf8(p, buf), p == NULL)); - if (c != '.') - *p++ = c; - } - else if (escape == 1) - { - escape = 0, buf = 0; - switch (c) - { - case '0': escape = 8; break; - case 'u': escape = 16; break; - default: *p++ = c; break; - } - } - else if (c == '\\') escape = 1; - else if (c != '\"') *p++ = c; - - *p = '\0'; - return rc; - fail: - free(rc); - return NULL; +#define r(cond, lower, upper) ((cond) && ((lower) <= c) && (c <= (upper))) + char *rc, *p; + int escape = 0; + char32_t buf = 0; + char c; + + /* We know that the output string can only be shorter because + * it is surrounded by 2 quotes and escape can only be longer + * then what they escape, for example \uA0, is four characters, + * but when parsed it generateds 2 bytes in UTF-8, and their + * is not code point whose UTF-8 encoding is longer than its + * hexadecimal representation. */ + fail_if (xmalloc(p = rc, strlen(string), char)); + + while ((c = *string++)) { + if (r(escape == 8, '0', '7')) { + buf = (buf << 3) | (c & 15); + } else if (r(escape == 16, '0', '9')) { + buf = (buf << 4) | (c & 15); + } else if (r(escape == 16, 'a', 'f')) { + buf = (buf << 4) | ((c & 15) + 9); + } else if (r(escape == 16, 'A', 'F')) { + buf = (buf << 4) | ((c & 15) + 9); + } else if (escape > 1) { + escape = 0; + fail_if (!(p = encode_utf8(p, buf))); + if (c != '.') + *p++ = c; + } else if (escape == 1) { + escape = 0; + buf = 0; + if (c == '0') + escape = 8; + else if (c == 'u') + escape = 16; + else + *p++ = c; + } else if (c == '\\') { + escape = 1; + } else if (c != '\"') { + *p++ = c; + } + } + + *p = '\0'; + return rc; +fail: + free(rc); + return NULL; #undef r } - diff --git a/src/mds-kbdc/raw-data.h b/src/mds-kbdc/raw-data.h index 3638042..bdc1078 100644 --- a/src/mds-kbdc/raw-data.h +++ b/src/mds-kbdc/raw-data.h @@ -25,42 +25,40 @@ /** * Source code by lines, with and without comments */ -typedef struct mds_kbdc_source_code -{ - /** - * Source code by lines without comments, - * `NULL`-terminated. - */ - char** restrict lines; - - /** - * Source code by lines with comments, - * `NULL`-terminated. - */ - char** restrict real_lines; - - /** - * Data for `lines` (internal data) - */ - char* content; - - /** - * Data for `real_lines` (internal data) - */ - char* real_content; - - /** - * The number of lines, that is, the number of - * elements in `lines` and `real_lines`. - */ - size_t line_count; - - /** - * The number of duplicates there are of this - * structure that shared the memory - */ - size_t duplicates; - +typedef struct mds_kbdc_source_code { + /** + * Source code by lines without comments, + * `NULL`-terminated. + */ + char **restrict lines; + + /** + * Source code by lines with comments, + * `NULL`-terminated. + */ + char **restrict real_lines; + + /** + * Data for `lines` (internal data) + */ + char *content; + + /** + * Data for `real_lines` (internal data) + */ + char *real_content; + + /** + * The number of lines, that is, the number of + * elements in `lines` and `real_lines`. + */ + size_t line_count; + + /** + * The number of duplicates there are of this + * structure that shared the memory + */ + size_t duplicates; } mds_kbdc_source_code_t; @@ -69,21 +67,21 @@ typedef struct mds_kbdc_source_code * * @param this The `mds_kbdc_source_code_t*` */ -void mds_kbdc_source_code_initialise(mds_kbdc_source_code_t* restrict this); +void mds_kbdc_source_code_initialise(mds_kbdc_source_code_t *restrict this); /** * Release all data in a `mds_kbdc_source_code_t*` * * @param this The `mds_kbdc_source_code_t*` */ -void mds_kbdc_source_code_destroy(mds_kbdc_source_code_t* restrict this); +void mds_kbdc_source_code_destroy(mds_kbdc_source_code_t *restrict this); /** * Release all data in a `mds_kbdc_source_code_t*`, and free it * * @param this The `mds_kbdc_source_code_t*` */ -void mds_kbdc_source_code_free(mds_kbdc_source_code_t* restrict this); +void mds_kbdc_source_code_free(mds_kbdc_source_code_t *restrict this); /** * Create a duplicate of a `mds_kbdc_source_code_t*` @@ -91,7 +89,7 @@ void mds_kbdc_source_code_free(mds_kbdc_source_code_t* restrict this); * @param this The `mds_kbdc_source_code_t*` * @return `this` is returned */ -mds_kbdc_source_code_t* mds_kbdc_source_code_dup(mds_kbdc_source_code_t* restrict this); +mds_kbdc_source_code_t *mds_kbdc_source_code_dup(mds_kbdc_source_code_t *restrict this); /** @@ -106,7 +104,8 @@ mds_kbdc_source_code_t* mds_kbdc_source_code_dup(mds_kbdc_source_code_t* restric * or `size` if the call do not end (that is, the code ends * prematurely), or zero if there is no function call at `offset` */ -size_t get_end_of_call(const char* restrict content, size_t offset, size_t size) __attribute__((pure)); +__attribute__((pure)) +size_t get_end_of_call(const char *restrict content, size_t offset, size_t size); /** * Read lines of a source file @@ -115,7 +114,7 @@ size_t get_end_of_call(const char* restrict content, size_t offset, size_t size) * @param source_code Output parameter for read data * @return Zero on success, -1 on error */ -int read_source_lines(const char* restrict pathname, mds_kbdc_source_code_t* restrict source_code); +int read_source_lines(const char *restrict pathname, mds_kbdc_source_code_t *restrict source_code); /** @@ -124,8 +123,7 @@ int read_source_lines(const char* restrict pathname, mds_kbdc_source_code_t* res * @param string The string * @return The string in machine-readable format, `NULL` on error */ -char* parse_raw_string(const char* restrict string); +char *parse_raw_string(const char *restrict string); #endif - diff --git a/src/mds-kbdc/simplify-tree.c b/src/mds-kbdc/simplify-tree.c index d559e2e..b3f588c 100644 --- a/src/mds-kbdc/simplify-tree.c +++ b/src/mds-kbdc/simplify-tree.c @@ -27,13 +27,13 @@ /** * This process's value for `mds_kbdc_tree_t.processed` */ -#define PROCESS_LEVEL 2 +#define PROCESS_LEVEL 2 /** * Tree type constant shortener */ -#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE +#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE /** @@ -44,9 +44,9 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(NODE, SEVERITY, ...) \ - NEW_ERROR_(result, SEVERITY, 1, (NODE)->loc_line, \ - (NODE)->loc_start, (NODE)->loc_end, 1, __VA_ARGS__) +#define NEW_ERROR(NODE, SEVERITY, ...)\ + NEW_ERROR_(result, SEVERITY, 1, (NODE)->loc_line,\ + (NODE)->loc_start, (NODE)->loc_end, 1, __VA_ARGS__) @@ -58,25 +58,25 @@ * @scope here:mds_kbdc_tree_t** Help variable that must be available for use * @scope argument:mds_kbdc_tree_t* Help variable that must be available for use */ -#define REMOVE_NOTHING(START) \ - do \ - { \ - long processed = tree->processed; \ - tree->processed = PROCESS_LEVEL; \ - for (here = &(tree->START); *here;) \ - if ((*here)->type != C(NOTHING)) \ - here = &((*here)->next); \ - else \ - while (*here && (*here)->type == C(NOTHING)) \ - { \ - argument = (*here)->next, (*here)->next = NULL; \ - if ((processed != PROCESS_LEVEL) && ((*here)->processed != PROCESS_LEVEL)) \ - NEW_ERROR(*here, WARNING, "‘.’ outside alternation has no effect"); \ - mds_kbdc_tree_free(*here); \ - *here = argument; \ - } \ - } \ - while (0) +#define REMOVE_NOTHING(START)\ + do {\ + long int processed = tree->processed;\ + tree->processed = PROCESS_LEVEL;\ + for (here = &(tree->START); *here;) {\ + if ((*here)->type != C(NOTHING)) {\ + here = &((*here)->next);\ + } else {\ + while (*here && (*here)->type == C(NOTHING)) {\ + argument = (*here)->next;\ + (*here)->next = NULL;\ + if (processed != PROCESS_LEVEL && (*here)->processed != PROCESS_LEVEL)\ + NEW_ERROR(*here, WARNING, "‘.’ outside alternation has no effect");\ + mds_kbdc_tree_free(*here);\ + *here = argument;\ + }\ + }\ + }\ + } while (0) @@ -89,38 +89,36 @@ * @scope here:mds_kbdc_tree_t** Pointer to the space where the argument was found * @scope temp:mds_kbdc_tree_t* Help variable that must be available for use */ -#define FLATTEN(argument) \ - do \ - { \ - /* Remember the alternation/subsequence and the argument that follows it. */ \ - mds_kbdc_tree_t* eliminated_argument = argument; \ - temp = argument->next; \ - /* Find the last alternative/element. */ \ - for (argument->next = argument->ordered.inner; argument->next;) \ - argument = argument->next; \ - /* Attach the argument that was after the alternation/subsequence to the */ \ - /* end of the alternation/subsequence, that is, flatten the right side. */ \ - argument->next = temp; \ - /* Flatten the left side. */ \ - *here = eliminated_argument->next; \ - /* Free the memory of the alternation/subsequence. */ \ - eliminated_argument->ordered.inner = NULL; \ - eliminated_argument->next = NULL; \ - mds_kbdc_tree_free(eliminated_argument); \ - } \ - while (0) +#define FLATTEN(argument)\ + do {\ + /* Remember the alternation/subsequence and the argument that follows it. */\ + mds_kbdc_tree_t *eliminated_argument = argument;\ + temp = argument->next;\ + /* Find the last alternative/element. */\ + for (argument->next = argument->ordered.inner; argument->next;)\ + argument = argument->next;\ + /* Attach the argument that was after the alternation/subsequence to the */\ + /* end of the alternation/subsequence, that is, flatten the right side. */\ + argument->next = temp;\ + /* Flatten the left side. */\ + *here = eliminated_argument->next;\ + /* Free the memory of the alternation/subsequence. */\ + eliminated_argument->ordered.inner = NULL;\ + eliminated_argument->next = NULL;\ + mds_kbdc_tree_free(eliminated_argument);\ + } while (0) /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The parameter of `simplify_tree` */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; @@ -130,7 +128,7 @@ static mds_kbdc_parsed_t* restrict result; * @param tree The tree * @return Zero on success, -1 on error */ -static int simplify(mds_kbdc_tree_t* restrict tree); +static int simplify(mds_kbdc_tree_t *restrict tree); /** * Simplify an unordered subsequence-subtree @@ -138,7 +136,7 @@ static int simplify(mds_kbdc_tree_t* restrict tree); * @param tree The unordered subsequence-subtree * @return Zero on success, -1 on error */ -static int simplify_unordered(mds_kbdc_tree_unordered_t* restrict tree); +static int simplify_unordered(mds_kbdc_tree_unordered_t *restrict tree); @@ -150,60 +148,61 @@ static int simplify_unordered(mds_kbdc_tree_unordered_t* restrict tree); * @param argument_index The index of the argument to eliminate * @return Zero on sucess, -1 on error */ -static int eliminate_alternation(mds_kbdc_tree_t* tree, mds_kbdc_tree_t* argument, size_t argument_index) +static int +eliminate_alternation(mds_kbdc_tree_t *tree, mds_kbdc_tree_t *argument, size_t argument_index) { - mds_kbdc_tree_t** here; - mds_kbdc_tree_t* first; - mds_kbdc_tree_t* last; - mds_kbdc_tree_t* new_tree; - mds_kbdc_tree_t* alternative; - mds_kbdc_tree_t* next_statement; - mds_kbdc_tree_t* next_alternative; - mds_kbdc_tree_t* new_argument; - size_t i; - int saved_errno; - - /* Detach next statement, we do not want to duplicate all following statements. */ - next_statement = tree->next, tree->next = NULL; - /* Detach alternation, we replace it in all duplcates, - no need to duplicate all alternatives. */ - alternative = argument->alternation.inner, argument->alternation.inner = NULL; - /* Eliminate. */ - for (first = last = NULL; alternative; alternative = next_alternative) - { - /* Duplicate statement. */ - fail_if (new_tree = mds_kbdc_tree_dup(tree), new_tree == NULL); - /* Join trees. */ - if (last) - last->next = new_tree; - last = new_tree; - first = first ? first : new_tree; - /* Jump to the alternation. */ - here = &(new_tree->macro_call.arguments); /* `new_tree->macro_call.arguments` and - * `new_tree->map.sequence` as the same address. */ - for (new_argument = *here, i = 0; i < argument_index; i++, here = &((*here)->next)) - new_argument = new_argument->next; - /* Detach alternative. */ - next_alternative = alternative->next; - /* Right-join alternative. */ - alternative->next = new_argument->next, new_argument->next = NULL; - mds_kbdc_tree_free(new_argument); - /* Left-join alternative. */ - *here = alternative; - } - /* Replace the statement with the first generated statement without the alternation. */ - mds_kbdc_tree_destroy((mds_kbdc_tree_t*)tree); - memcpy(tree, first, sizeof(mds_kbdc_tree_t)); - if (first == last) last = (mds_kbdc_tree_t*)tree; - free(first); - /* Reattach the statement that followed to the last generated statement. */ - last->next = next_statement; - return 0; - fail: - saved_errno = errno; - argument->alternation.inner = alternative; - tree->next = next_statement; - return errno = saved_errno, -1; + mds_kbdc_tree_t **here; + mds_kbdc_tree_t *first; + mds_kbdc_tree_t *last; + mds_kbdc_tree_t *new_tree; + mds_kbdc_tree_t *alternative; + mds_kbdc_tree_t *next_statement; + mds_kbdc_tree_t *next_alternative; + mds_kbdc_tree_t *new_argument; + size_t i; + int saved_errno; + + /* Detach next statement, we do not want to duplicate all following statements. */ + next_statement = tree->next, tree->next = NULL; + /* Detach alternation, we replace it in all duplcates, + no need to duplicate all alternatives. */ + alternative = argument->alternation.inner, argument->alternation.inner = NULL; + /* Eliminate. */ + for (first = last = NULL; alternative; alternative = next_alternative) { + /* Duplicate statement. */ + fail_if (!(new_tree = mds_kbdc_tree_dup(tree))); + /* Join trees. */ + if (last) + last->next = new_tree; + last = new_tree; + first = first ? first : new_tree; + /* Jump to the alternation. */ + here = &(new_tree->macro_call.arguments); /* `new_tree->macro_call.arguments` and + * `new_tree->map.sequence` as the same address. */ + for (new_argument = *here, i = 0; i < argument_index; i++, here = &((*here)->next)) + new_argument = new_argument->next; + /* Detach alternative. */ + next_alternative = alternative->next; + /* Right-join alternative. */ + alternative->next = new_argument->next, new_argument->next = NULL; + mds_kbdc_tree_free(new_argument); + /* Left-join alternative. */ + *here = alternative; + } + /* Replace the statement with the first generated statement without the alternation. */ + mds_kbdc_tree_destroy((mds_kbdc_tree_t*)tree); + memcpy(tree, first, sizeof(mds_kbdc_tree_t)); + if (first == last) + last = (mds_kbdc_tree_t*)tree; + free(first); + /* Reattach the statement that followed to the last generated statement. */ + last->next = next_statement; + return 0; +fail: + saved_errno = errno; + argument->alternation.inner = alternative; + tree->next = next_statement; + return errno = saved_errno, -1; } @@ -213,118 +212,119 @@ static int eliminate_alternation(mds_kbdc_tree_t* tree, mds_kbdc_tree_t* argumen * @param tree The macro call-subtree * @return Zero on success, -1 on error */ -static int simplify_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) +static int +simplify_macro_call(mds_kbdc_tree_macro_call_t *restrict tree) { - mds_kbdc_tree_t* argument; - mds_kbdc_tree_t* dup_arguments = NULL; - mds_kbdc_tree_t** here; - char* full_macro_name; - size_t argument_index = 0; - int saved_errno; - - /* Simplify arguments. */ - for (argument = tree->arguments; argument; argument = argument->next) - fail_if (simplify(argument)); - - /* Remove ‘.’:s. */ - REMOVE_NOTHING(arguments); - - /* Copy arguments. */ - if (tree->arguments == NULL) - goto no_args; - fail_if (dup_arguments = mds_kbdc_tree_dup(tree->arguments), dup_arguments == NULL); - - /* Eliminate alterations. */ - for (argument = dup_arguments; argument; argument = argument->next, argument_index++) - if (argument->type == C(ALTERNATION)) - fail_if (eliminate_alternation((mds_kbdc_tree_t*)tree, argument, argument_index)); - mds_kbdc_tree_free(dup_arguments), dup_arguments = NULL; - - /* Add argument count suffix. */ - no_args: - for (argument_index = 0, argument = tree->arguments; argument; argument = argument->next) - argument_index++; - fail_if (xasprintf(full_macro_name, "%s/%zu", tree->name, argument_index)); - free(tree->name), tree->name = full_macro_name; - - /* Example of what will happend: - * - * my_macro([1 2] [1 2] [1 2]) ## call 1 - * - * simplify_macro_call on call 1 - * after processing argument 1 - * my_macro(1 [1 2] [1 2]) ## call 1 - * my_macro(2 [1 2] [1 2]) ## call 5 - * after processing argument 2 - * my_macro(1 1 [1 2]) ## call 1 - * my_macro(1 2 [1 2]) ## call 3 - * my_macro(2 [1 2] [1 2]) ## call 5 - * after processing argument 3 - * my_macro(1 1 1) ## call 1 - * my_macro(1 1 2) ## call 2 - * my_macro(1 2 [1 2]) ## call 3 - * my_macro(2 [1 2] [1 2]) ## call 5 - * - * no difference after simplify_macro_call on call 2 - * - * simplify_macro_call on call 3 - * no difference after processing argument 1 - * no difference after processing argument 2 - * after processing argument 3 - * my_macro(1 1 1) ## (call 1) - * my_macro(1 1 2) ## (call 2) - * my_macro(1 2 1) ## call 3 - * my_macro(1 2 1) ## call 4 - * my_macro(2 [1 2] [1 2]) ## call 5 - * - * no difference after simplify_macro_call on call 4 - * - * simplify_macro_call on call 5 - * no difference after processing argument 1 - * after processing argument 2 - * my_macro(1 1 1) ## (call 1) - * my_macro(1 1 2) ## (call 2) - * my_macro(1 2 1) ## (call 3) - * my_macro(1 2 2) ## (call 4) - * my_macro(2 1 [1 2]) ## call 5 - * my_macro(2 2 [1 2]) ## call 7 - * after processing argument 3 - * my_macro(1 1 1) ## (call 1) - * my_macro(1 1 2) ## (call 2) - * my_macro(1 2 1) ## (call 3) - * my_macro(1 2 2) ## (call 4) - * my_macro(2 1 1) ## call 5 - * my_macro(2 1 2) ## call 6 - * my_macro(2 2 [1 2]) ## call 7 - * - * no difference after simplify_macro_call on call 6 - * - * simplify_macro_call on call 7 - * no difference after processing argument 1 - * no difference after processing argument 2 - * after processing argument 3 - * my_macro(1 1 1) ## (call 1) - * my_macro(1 1 2) ## (call 2) - * my_macro(1 2 1) ## (call 3) - * my_macro(1 2 2) ## (call 4) - * my_macro(2 1 1) ## (call 5) - * my_macro(2 1 2) ## (call 6) - * my_macro(2 2 1) ## call 7 - * my_macro(2 2 2) ## call 8 - * - * no difference after simplify_macro_call on call 8 - * - * Nothings (‘.’) are removed before processing the alternations. - * - * It should also be noticed that all macro names are update to - * with the argument count suffix. - */ - - return 0; - fail: - saved_errno = errno; - mds_kbdc_tree_free(dup_arguments); - return errno = saved_errno, -1; + mds_kbdc_tree_t *argument; + mds_kbdc_tree_t *dup_arguments = NULL; + mds_kbdc_tree_t **here; + char *full_macro_name; + size_t argument_index = 0; + int saved_errno; + + /* Simplify arguments. */ + for (argument = tree->arguments; argument; argument = argument->next) + fail_if (simplify(argument)); + + /* Remove ‘.’:s. */ + REMOVE_NOTHING(arguments); + + /* Copy arguments. */ + if (!tree->arguments) + goto no_args; + fail_if (!(dup_arguments = mds_kbdc_tree_dup(tree->arguments))); + + /* Eliminate alterations. */ + for (argument = dup_arguments; argument; argument = argument->next, argument_index++) + if (argument->type == C(ALTERNATION)) + fail_if (eliminate_alternation((mds_kbdc_tree_t*)tree, argument, argument_index)); + mds_kbdc_tree_free(dup_arguments), dup_arguments = NULL; + + /* Add argument count suffix. */ +no_args: + for (argument_index = 0, argument = tree->arguments; argument; argument = argument->next) + argument_index++; + fail_if (xasprintf(full_macro_name, "%s/%zu", tree->name, argument_index)); + free(tree->name), tree->name = full_macro_name; + + /* Example of what will happend: + * + * my_macro([1 2] [1 2] [1 2]) ## call 1 + * + * simplify_macro_call on call 1 + * after processing argument 1 + * my_macro(1 [1 2] [1 2]) ## call 1 + * my_macro(2 [1 2] [1 2]) ## call 5 + * after processing argument 2 + * my_macro(1 1 [1 2]) ## call 1 + * my_macro(1 2 [1 2]) ## call 3 + * my_macro(2 [1 2] [1 2]) ## call 5 + * after processing argument 3 + * my_macro(1 1 1) ## call 1 + * my_macro(1 1 2) ## call 2 + * my_macro(1 2 [1 2]) ## call 3 + * my_macro(2 [1 2] [1 2]) ## call 5 + * + * no difference after simplify_macro_call on call 2 + * + * simplify_macro_call on call 3 + * no difference after processing argument 1 + * no difference after processing argument 2 + * after processing argument 3 + * my_macro(1 1 1) ## (call 1) + * my_macro(1 1 2) ## (call 2) + * my_macro(1 2 1) ## call 3 + * my_macro(1 2 1) ## call 4 + * my_macro(2 [1 2] [1 2]) ## call 5 + * + * no difference after simplify_macro_call on call 4 + * + * simplify_macro_call on call 5 + * no difference after processing argument 1 + * after processing argument 2 + * my_macro(1 1 1) ## (call 1) + * my_macro(1 1 2) ## (call 2) + * my_macro(1 2 1) ## (call 3) + * my_macro(1 2 2) ## (call 4) + * my_macro(2 1 [1 2]) ## call 5 + * my_macro(2 2 [1 2]) ## call 7 + * after processing argument 3 + * my_macro(1 1 1) ## (call 1) + * my_macro(1 1 2) ## (call 2) + * my_macro(1 2 1) ## (call 3) + * my_macro(1 2 2) ## (call 4) + * my_macro(2 1 1) ## call 5 + * my_macro(2 1 2) ## call 6 + * my_macro(2 2 [1 2]) ## call 7 + * + * no difference after simplify_macro_call on call 6 + * + * simplify_macro_call on call 7 + * no difference after processing argument 1 + * no difference after processing argument 2 + * after processing argument 3 + * my_macro(1 1 1) ## (call 1) + * my_macro(1 1 2) ## (call 2) + * my_macro(1 2 1) ## (call 3) + * my_macro(1 2 2) ## (call 4) + * my_macro(2 1 1) ## (call 5) + * my_macro(2 1 2) ## (call 6) + * my_macro(2 2 1) ## call 7 + * my_macro(2 2 2) ## call 8 + * + * no difference after simplify_macro_call on call 8 + * + * Nothings (‘.’) are removed before processing the alternations. + * + * It should also be noticed that all macro names are update to + * with the argument count suffix. + */ + + return 0; +fail: + saved_errno = errno; + mds_kbdc_tree_free(dup_arguments); + return errno = saved_errno, -1; } @@ -334,26 +334,27 @@ static int simplify_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) * @param tree The value statement-tree * @return Zero on success, -1 on error */ -static int check_value_statement_before_simplification(mds_kbdc_tree_map_t* restrict tree) +static int +check_value_statement_before_simplification(mds_kbdc_tree_map_t *restrict tree) { - again: - /* Check for alternation. */ - if ((tree->sequence->type == C(ALTERNATION)) && (tree->processed != PROCESS_LEVEL)) - NEW_ERROR(tree->sequence, WARNING, - "alternated value statement is undefined unless the alternatives are identical"); - - /* Check for unordered. */ - if (tree->sequence->type != C(UNORDERED)) - return 0; - if (tree->processed != PROCESS_LEVEL) - NEW_ERROR(tree->sequence, WARNING, "use of sequence in value statement is discouraged"); - - /* Simplify argument and start over. */ - fail_if (simplify(tree->sequence)); - goto again; - - fail: - return -1; +again: + /* Check for alternation. */ + if (tree->sequence->type == C(ALTERNATION) && tree->processed != PROCESS_LEVEL) + NEW_ERROR(tree->sequence, WARNING, + "alternated value statement is undefined unless the alternatives are identical"); + + /* Check for unordered. */ + if (tree->sequence->type != C(UNORDERED)) + return 0; + if (tree->processed != PROCESS_LEVEL) + NEW_ERROR(tree->sequence, WARNING, "use of sequence in value statement is discouraged"); + + /* Simplify argument and start over. */ + fail_if (simplify(tree->sequence)); + goto again; + +fail: + return -1; } @@ -363,19 +364,20 @@ static int check_value_statement_before_simplification(mds_kbdc_tree_map_t* rest * @param tree The value statement-tree * @return Zero on success, -1 on error */ -static int check_value_statement_after_simplification(mds_kbdc_tree_map_t* restrict tree) +static int +check_value_statement_after_simplification(mds_kbdc_tree_map_t *restrict tree) { - /* Check that there is only one value. */ - if (tree->sequence->next) - NEW_ERROR(tree->sequence->next, ERROR, "more the one value in value statement"); - - /* Check the type of the value */ - if (tree->sequence->type != C(STRING)) - NEW_ERROR(tree->sequence, ERROR, "bad value type"); - - return 0; - fail: - return -1; + /* Check that there is only one value. */ + if (tree->sequence->next) + NEW_ERROR(tree->sequence->next, ERROR, "more the one value in value statement"); + + /* Check the type of the value */ + if (tree->sequence->type != C(STRING)) + NEW_ERROR(tree->sequence, ERROR, "bad value type"); + + return 0; +fail: + return -1; } @@ -385,155 +387,154 @@ static int check_value_statement_after_simplification(mds_kbdc_tree_map_t* restr * @param tree The mapping-subtree * @return Zero on success, -1 on error */ -static int simplify_map(mds_kbdc_tree_map_t* restrict tree) +static int +simplify_map(mds_kbdc_tree_map_t *restrict tree) { - mds_kbdc_tree_t* argument; - mds_kbdc_tree_t** here; - mds_kbdc_tree_t* dup_sequence = NULL; - mds_kbdc_tree_t* temp; - size_t argument_index; - int redo = 0, need_reelimination, saved_errno; - - /* Check for bad things in the result. */ - for (argument = tree->result; argument; argument = argument->next) - if ((argument->type != C(KEYS)) && (argument->type != C(STRING))) - NEW_ERROR(argument, ERROR, "not allowed in mapping output"); - - /* Valid value properties. */ - if (tree->result == NULL) - fail_if (check_value_statement_before_simplification(tree)); - - /* Simplify sequence. */ - for (argument = tree->sequence; argument; argument = argument->next) - fail_if (simplify(argument)); - - /* Test predicted emptyness. */ - for (argument = tree->sequence; argument; argument = argument->next) - if (argument->type != C(NOTHING)) - goto will_not_be_empty; - if (tree->sequence->processed != PROCESS_LEVEL) - { - if (tree->result) - NEW_ERROR(tree->sequence, ERROR, "mapping of null sequence"); - else - NEW_ERROR(tree->sequence, ERROR, "nothing in value statement"); - } - /* The tree parsing process will not allow a mapping statement - * to start with a ‘.’. Thus if we select to highlight it we - * know that it is either an empty alternation, an empty - * unordered subsequence or a nothing inside an alternation. - * If it is already been processed by the simplifier, it is an - * error because it is an empty alternation or empty unordered - * subsequence, and there is not reason to print an additional - * error. If however it is a nothing inside an alternation we - * know that it is the cause of the error, however possibily - * in conjunction with additional such constructs, but those - * are harder to locate. */ - return 0; - will_not_be_empty: - - /* Remove ‘.’:s. */ - REMOVE_NOTHING(sequence); - - /* Because unordered are simplified to alternations of ordered subsequences, which - in turn can contain alternations, possibiled from simplification of nested - unordered sequenceses, we need to reeliminated until there are not alternations. */ - for (need_reelimination = 1; need_reelimination ? (need_reelimination = 0, 1) : 0; redo = 0) - { - /* Copy sequence. */ - fail_if (dup_sequence = mds_kbdc_tree_dup(tree->sequence), dup_sequence == NULL); - - /* Eliminate alterations, remember, unordered subsequences have - been simplified to alternations of ordered subsequences. */ - for (argument_index = 0, argument = dup_sequence; argument; argument = argument->next, argument_index++) - if (argument->type == C(ALTERNATION)) - fail_if (eliminate_alternation((mds_kbdc_tree_t*)tree, argument, argument_index)); - - mds_kbdc_tree_free(dup_sequence), dup_sequence = NULL; - - /* Eliminated ordered subsequences. */ - for (here = &(tree->sequence); (argument = *here); redo ? (redo = 0) : (here = &(argument->next), 0)) - if (argument->type == C(ORDERED)) - { - FLATTEN(argument); - redo = 1; - } - else if (argument->type == C(ALTERNATION)) - need_reelimination = 1; - } - - /* Valid value properties. */ - if (tree->result == NULL) - fail_if (check_value_statement_after_simplification(tree)); - - /* Mapping statements are simplified in a manner similar - * to how macro calls are simplified. However mapping - * statements can also contain unordered subsequences, - * there are translated into alternations of ordered - * subsequences. Thus after the elimination of alternations, - * ordered subsequences are eliminated too. - * - * Example of what will happen, ‘{ }’ represents an - * ordered subsequence: - * - * (1 2) (3 4) : 0 ## mapping 1 - * - * simplify_map on mapping 1 - * after simplification - * [{1 2} {2 1}] [{3 4} {4 3}] ## mapping 1 - * after alternation elimination on argument 1 - * {1 2} [{3 4} {4 3}] ## mapping 1 - * {2 1} [{3 4} {4 3}] ## mapping 3 - * after alternation elimination on argument 2 - * {1 2} {3 4} ## mapping 1 - * {1 2} {4 3} ## mapping 2 - * {2 1} [{3 4} {4 3}] ## mapping 3 - * after ordered subsequence elimination - * 1 2 3 4 ## mapping 1 - * {1 2} {4 3} ## mapping 2 - * {2 1} [{3 4} {4 3}] ## mapping 3 - * - * simplify_map on mapping 2 - * no difference after simplification - * no difference after alternation elimination on argument 1 - * no difference after alternation elimination on argument 2 - * after ordered subsequence elimination - * 1 2 3 4 ## (mapping 1) - * 1 2 4 3 ## mapping 2 - * {2 1} [{3 4} {4 3}] ## mapping 3 - * - * simplify_map on mapping 3 - * no difference after simplification - * no difference after alternation elimination on argument 1 - * after alternation elimination on argument 2 - * 1 2 3 4 ## (mapping 1) - * 1 2 4 3 ## (mapping 2) - * {2 1} {3 4} ## mapping 3 - * {2 1} {4 3} ## mapping 4 - * after ordered subsequence elimination - * 1 2 3 4 ## (mapping 1) - * 1 2 4 3 ## (mapping 2) - * 2 1 3 4 ## mapping 3 - * {2 1} {4 3} ## mapping 4 - * - * simplify_map on mapping 4 - * no difference after simplification - * no difference after alternation elimination on argument 1 - * no difference after alternation elimination on argument 2 - * after ordered subsequence elimination - * 1 2 3 4 ## (mapping 1) - * 1 2 4 3 ## (mapping 2) - * 2 1 3 4 ## (mapping 3) - * 2 1 4 3 ## mapping 4 - * - * Nothings (‘.’) are removed before processing the alternations. - */ - - return 0; - fail: - saved_errno = errno; - mds_kbdc_tree_free(dup_sequence); - return errno = saved_errno, -1; + mds_kbdc_tree_t *argument; + mds_kbdc_tree_t **here; + mds_kbdc_tree_t *dup_sequence = NULL; + mds_kbdc_tree_t *temp; + size_t argument_index; + int redo = 0, need_reelimination, saved_errno; + + /* Check for bad things in the result. */ + for (argument = tree->result; argument; argument = argument->next) + if (argument->type != C(KEYS) && argument->type != C(STRING)) + NEW_ERROR(argument, ERROR, "not allowed in mapping output"); + + /* Valid value properties. */ + if (!tree->result) + fail_if (check_value_statement_before_simplification(tree)); + + /* Simplify sequence. */ + for (argument = tree->sequence; argument; argument = argument->next) + fail_if (simplify(argument)); + + /* Test predicted emptyness. */ + for (argument = tree->sequence; argument; argument = argument->next) + if (argument->type != C(NOTHING)) + goto will_not_be_empty; + if (tree->sequence->processed != PROCESS_LEVEL) { + if (tree->result) + NEW_ERROR(tree->sequence, ERROR, "mapping of null sequence"); + else + NEW_ERROR(tree->sequence, ERROR, "nothing in value statement"); + } + /* The tree parsing process will not allow a mapping statement + * to start with a ‘.’. Thus if we select to highlight it we + * know that it is either an empty alternation, an empty + * unordered subsequence or a nothing inside an alternation. + * If it is already been processed by the simplifier, it is an + * error because it is an empty alternation or empty unordered + * subsequence, and there is not reason to print an additional + * error. If however it is a nothing inside an alternation we + * know that it is the cause of the error, however possibily + * in conjunction with additional such constructs, but those + * are harder to locate. */ + return 0; +will_not_be_empty: + + /* Remove ‘.’:s. */ + REMOVE_NOTHING(sequence); + + /* Because unordered are simplified to alternations of ordered subsequences, which + in turn can contain alternations, possibiled from simplification of nested + unordered sequenceses, we need to reeliminated until there are not alternations. */ + for (need_reelimination = 1; need_reelimination ? (need_reelimination = 0, 1) : 0; redo = 0) { + /* Copy sequence. */ + fail_if (!(dup_sequence = mds_kbdc_tree_dup(tree->sequence))); + + /* Eliminate alterations, remember, unordered subsequences have + been simplified to alternations of ordered subsequences. */ + for (argument_index = 0, argument = dup_sequence; argument; argument = argument->next, argument_index++) + if (argument->type == C(ALTERNATION)) + fail_if (eliminate_alternation((mds_kbdc_tree_t*)tree, argument, argument_index)); + + mds_kbdc_tree_free(dup_sequence), dup_sequence = NULL; + + /* Eliminated ordered subsequences. */ + for (here = &(tree->sequence); (argument = *here); redo ? (redo = 0) : (here = &(argument->next), 0)) { + if (argument->type == C(ORDERED)) { + FLATTEN(argument); + redo = 1; + } else if (argument->type == C(ALTERNATION)) { + need_reelimination = 1; + } + } + } + + /* Valid value properties. */ + if (!tree->result) + fail_if (check_value_statement_after_simplification(tree)); + + /* Mapping statements are simplified in a manner similar + * to how macro calls are simplified. However mapping + * statements can also contain unordered subsequences, + * there are translated into alternations of ordered + * subsequences. Thus after the elimination of alternations, + * ordered subsequences are eliminated too. + * + * Example of what will happen, ‘{ }’ represents an + * ordered subsequence: + * + * (1 2) (3 4) : 0 ## mapping 1 + * + * simplify_map on mapping 1 + * after simplification + * [{1 2} {2 1}] [{3 4} {4 3}] ## mapping 1 + * after alternation elimination on argument 1 + * {1 2} [{3 4} {4 3}] ## mapping 1 + * {2 1} [{3 4} {4 3}] ## mapping 3 + * after alternation elimination on argument 2 + * {1 2} {3 4} ## mapping 1 + * {1 2} {4 3} ## mapping 2 + * {2 1} [{3 4} {4 3}] ## mapping 3 + * after ordered subsequence elimination + * 1 2 3 4 ## mapping 1 + * {1 2} {4 3} ## mapping 2 + * {2 1} [{3 4} {4 3}] ## mapping 3 + * + * simplify_map on mapping 2 + * no difference after simplification + * no difference after alternation elimination on argument 1 + * no difference after alternation elimination on argument 2 + * after ordered subsequence elimination + * 1 2 3 4 ## (mapping 1) + * 1 2 4 3 ## mapping 2 + * {2 1} [{3 4} {4 3}] ## mapping 3 + * + * simplify_map on mapping 3 + * no difference after simplification + * no difference after alternation elimination on argument 1 + * after alternation elimination on argument 2 + * 1 2 3 4 ## (mapping 1) + * 1 2 4 3 ## (mapping 2) + * {2 1} {3 4} ## mapping 3 + * {2 1} {4 3} ## mapping 4 + * after ordered subsequence elimination + * 1 2 3 4 ## (mapping 1) + * 1 2 4 3 ## (mapping 2) + * 2 1 3 4 ## mapping 3 + * {2 1} {4 3} ## mapping 4 + * + * simplify_map on mapping 4 + * no difference after simplification + * no difference after alternation elimination on argument 1 + * no difference after alternation elimination on argument 2 + * after ordered subsequence elimination + * 1 2 3 4 ## (mapping 1) + * 1 2 4 3 ## (mapping 2) + * 2 1 3 4 ## (mapping 3) + * 2 1 4 3 ## mapping 4 + * + * Nothings (‘.’) are removed before processing the alternations. + */ + + return 0; +fail: + saved_errno = errno; + mds_kbdc_tree_free(dup_sequence); + return errno = saved_errno, -1; } @@ -543,69 +544,63 @@ static int simplify_map(mds_kbdc_tree_map_t* restrict tree) * @param tree The alternation-subtree * @return Zero on success, -1 on error */ -static int simplify_alternation(mds_kbdc_tree_alternation_t* restrict tree) +static int +simplify_alternation(mds_kbdc_tree_alternation_t *restrict tree) { - mds_kbdc_tree_t* argument; - mds_kbdc_tree_t* first_nothing = NULL; - mds_kbdc_tree_t* temp; - mds_kbdc_tree_t** here; - int redo = 0; - - /* Test emptyness. */ - if (tree->inner == NULL) - { - NEW_ERROR(tree, ERROR, "empty alternation"); - tree->type = C(NOTHING); - tree->processed = PROCESS_LEVEL; - return 0; - } - - /* Test singletonness. */ - if (tree->inner->next == NULL) - { - temp = tree->inner; - NEW_ERROR(tree, WARNING, "singleton alternation"); - memcpy(tree, temp, sizeof(mds_kbdc_tree_t)); - free(temp); - fail_if (simplify((mds_kbdc_tree_t*)tree)); - return 0; - } - - /* Simplify. */ - for (here = &(tree->inner); (argument = *here); redo ? (redo = 0) : (here = &(argument->next), 0)) - if ((argument->type == C(NOTHING)) && (argument->processed != PROCESS_LEVEL)) - { - /* Test multiple nothings. */ - if (first_nothing == NULL) - first_nothing = argument; - else - { - NEW_ERROR(argument, WARNING, "multiple ‘.’ inside an alternation"); - NEW_ERROR(first_nothing, NOTE, "first ‘.’ was here"); - } - } - else if (argument->type == C(ALTERNATION)) - { - /* Alternation nesting. */ - if (argument->processed != PROCESS_LEVEL) - NEW_ERROR(argument, WARNING, "alternation inside alternation is unnessary"); - fail_if (simplify_alternation(&(argument->alternation))); - if (argument->type == C(ALTERNATION)) - FLATTEN(argument); - redo = 1; - } - else if (argument->type == C(UNORDERED)) - { - /* Nesting unordered subsequence, - simplifies to alternation of ordered subsequence, or simpler. */ - NEW_ERROR(argument, WARNING, "unordered subsequence inside alternation is discouraged"); - fail_if (simplify_unordered(&(argument->unordered))); - redo = 1; - } - - return 0; - fail: - return -1; + mds_kbdc_tree_t *argument; + mds_kbdc_tree_t *first_nothing = NULL; + mds_kbdc_tree_t *temp; + mds_kbdc_tree_t **here; + int redo = 0; + + /* Test emptyness. */ + if (!tree->inner) { + NEW_ERROR(tree, ERROR, "empty alternation"); + tree->type = C(NOTHING); + tree->processed = PROCESS_LEVEL; + return 0; + } + + /* Test singletonness. */ + if (!tree->inner->next) { + temp = tree->inner; + NEW_ERROR(tree, WARNING, "singleton alternation"); + memcpy(tree, temp, sizeof(mds_kbdc_tree_t)); + free(temp); + fail_if (simplify((mds_kbdc_tree_t*)tree)); + return 0; + } + + /* Simplify. */ + for (here = &(tree->inner); (argument = *here); redo ? (redo = 0) : (here = &(argument->next), 0)) { + if (argument->type == C(NOTHING) && argument->processed != PROCESS_LEVEL) { + /* Test multiple nothings. */ + if (!first_nothing) { + first_nothing = argument; + } else{ + NEW_ERROR(argument, WARNING, "multiple ‘.’ inside an alternation"); + NEW_ERROR(first_nothing, NOTE, "first ‘.’ was here"); + } + } else if (argument->type == C(ALTERNATION)) { + /* Alternation nesting. */ + if (argument->processed != PROCESS_LEVEL) + NEW_ERROR(argument, WARNING, "alternation inside alternation is unnessary"); + fail_if (simplify_alternation(&(argument->alternation))); + if (argument->type == C(ALTERNATION)) + FLATTEN(argument); + redo = 1; + } else if (argument->type == C(UNORDERED)) { + /* Nesting unordered subsequence, + simplifies to alternation of ordered subsequence, or simpler. */ + NEW_ERROR(argument, WARNING, "unordered subsequence inside alternation is discouraged"); + fail_if (simplify_unordered(&(argument->unordered))); + redo = 1; + } + } + + return 0; +fail: + return -1; } @@ -616,77 +611,75 @@ static int simplify_alternation(mds_kbdc_tree_alternation_t* restrict tree) * @param elements The subtrees, chained * @return Chain of ordered subsequence, `NULL` on error */ -static mds_kbdc_tree_t* create_permutations(mds_kbdc_tree_t* elements) +static mds_kbdc_tree_t * +create_permutations(mds_kbdc_tree_t *elements) { - mds_kbdc_tree_t* first = NULL; - mds_kbdc_tree_t** here = &first; - mds_kbdc_tree_t** previous_next = &elements; - mds_kbdc_tree_t* argument; - mds_kbdc_tree_t* temp; - mds_kbdc_tree_t* subperms = NULL; - mds_kbdc_tree_t* perm; - mds_kbdc_tree_t ordered; - int saved_errno, no_perms, stage = 0; - - /* Error case. */ - fail_if (elements == NULL); - - /* Base case. */ - if (elements->next == NULL) - { - fail_if ((first = mds_kbdc_tree_create(C(ORDERED))) == NULL); - fail_if ((first->ordered.inner = mds_kbdc_tree_dup(elements)) == NULL); - return first; - } - - stage++; - for (previous_next = &elements; (argument = *previous_next); previous_next = &((*previous_next)->next)) - { - /* Created ordered alternative for a permutation prototype. */ - mds_kbdc_tree_initialise(&ordered, C(ORDERED)); - /* Select the first element. */ - temp = argument->next, argument->next = NULL; - ordered.ordered.inner = mds_kbdc_tree_dup(argument); - argument->next = temp; - fail_if (ordered.ordered.inner == NULL); - /* Create subpermutations. */ - *previous_next = argument->next; - argument->next = NULL; - no_perms = (elements == NULL); - subperms = create_permutations(elements); - argument->next = *previous_next; - *previous_next = argument; - fail_if (no_perms ? 0 : (subperms == NULL)); - /* Join first element with subpermutations. */ - while (subperms) - { - /* Join. */ - fail_if (perm = mds_kbdc_tree_dup(&ordered), perm == NULL); - perm->ordered.inner->next = subperms->ordered.inner; - subperms->ordered.inner = NULL; - /* Add the permutation to the chain. */ - *here = perm; - here = &(perm->next); - /* Select next permutation. */ - temp = subperms; - subperms = subperms->next; - temp->next = NULL; - mds_kbdc_tree_free(temp); + mds_kbdc_tree_t *first = NULL; + mds_kbdc_tree_t **here = &first; + mds_kbdc_tree_t **previous_next = &elements; + mds_kbdc_tree_t *argument; + mds_kbdc_tree_t *temp; + mds_kbdc_tree_t *subperms = NULL; + mds_kbdc_tree_t *perm; + mds_kbdc_tree_t ordered; + int saved_errno, no_perms, stage = 0; + + /* Error case. */ + fail_if (!elements); + + /* Base case. */ + if (!elements->next) { + fail_if (!(first = mds_kbdc_tree_create(C(ORDERED)))); + fail_if (!(first->ordered.inner = mds_kbdc_tree_dup(elements))); + return first; } - /* Destroy prototype. */ - mds_kbdc_tree_destroy(&ordered); - } - - return first; - - fail: - saved_errno = errno; - mds_kbdc_tree_free(first); - mds_kbdc_tree_free(subperms); - if (stage > 0) - mds_kbdc_tree_destroy(&ordered); - errno = saved_errno; - return NULL; + + stage++; + for (previous_next = &elements; (argument = *previous_next); previous_next = &(*previous_next)->next) { + /* Created ordered alternative for a permutation prototype. */ + mds_kbdc_tree_initialise(&ordered, C(ORDERED)); + /* Select the first element. */ + temp = argument->next, argument->next = NULL; + ordered.ordered.inner = mds_kbdc_tree_dup(argument); + argument->next = temp; + fail_if (!ordered.ordered.inner); + /* Create subpermutations. */ + *previous_next = argument->next; + argument->next = NULL; + no_perms = !elements; + subperms = create_permutations(elements); + argument->next = *previous_next; + *previous_next = argument; + fail_if (no_perms && !subperms); + /* Join first element with subpermutations. */ + while (subperms) { + /* Join. */ + fail_if (!(perm = mds_kbdc_tree_dup(&ordered))); + perm->ordered.inner->next = subperms->ordered.inner; + subperms->ordered.inner = NULL; + /* Add the permutation to the chain. */ + *here = perm; + here = &perm->next; + /* Select next permutation. */ + temp = subperms; + subperms = subperms->next; + temp->next = NULL; + mds_kbdc_tree_free(temp); + } + /* Destroy prototype. */ + mds_kbdc_tree_destroy(&ordered); + } + + return first; + +fail: + saved_errno = errno; + mds_kbdc_tree_free(first); + mds_kbdc_tree_free(subperms); + if (stage > 0) + mds_kbdc_tree_destroy(&ordered); + errno = saved_errno; + return NULL; } @@ -696,105 +689,97 @@ static mds_kbdc_tree_t* create_permutations(mds_kbdc_tree_t* elements) * @param tree The unordered subsequence-subtree * @return Zero on success, -1 on error */ -static int simplify_unordered(mds_kbdc_tree_unordered_t* restrict tree) +static int +simplify_unordered(mds_kbdc_tree_unordered_t *restrict tree) { - mds_kbdc_tree_t* arguments; - mds_kbdc_tree_t* argument; - mds_kbdc_tree_t* temp; - mds_kbdc_tree_t** here; - int allow_long = 0; - size_t argument_count; - - /* Test for ‘(( ))’. */ - if (tree->inner && (tree->inner->next == NULL) && (tree->inner->type == C(UNORDERED))) - { - tree->loc_end = tree->inner->loc_end; - temp = tree->inner; - tree->inner = tree->inner->unordered.inner; - temp->unordered.inner = NULL; - mds_kbdc_tree_free(temp); - allow_long = 1; - } - - /* Test emptyness. */ - if (tree->inner == NULL) - { - NEW_ERROR(tree, ERROR, "empty unordered subsequence"); - tree->type = C(NOTHING); - tree->processed = PROCESS_LEVEL; - return 0; - } - - /* Test singletonness. */ - if (tree->inner->next == NULL) - { - temp = tree->inner; - NEW_ERROR(tree, WARNING, "singleton unordered subsequence"); - memcpy(tree, temp, sizeof(mds_kbdc_tree_t)); - free(temp); - fail_if (simplify((mds_kbdc_tree_t*)tree)); - return -1; - } - - /* Remove ‘.’:s. */ - REMOVE_NOTHING(inner); - - /* Check that the sequnced contained anything else. */ - if (tree->inner == NULL) - { - NEW_ERROR(tree, ERROR, "unordered subsequence contained nothing else than ‘.’"); - tree->type = C(NOTHING); - tree->processed = PROCESS_LEVEL; - return 0; - } - - /* Simplify. */ - for (argument = tree->inner, argument_count = 0; argument; argument = argument->next, argument_count++) - if (argument->type == C(ALTERNATION)) - { - fail_if (simplify_alternation(&(argument->alternation))); - argument->processed = PROCESS_LEVEL; - } - else if (argument->type == C(UNORDERED)) - { - NEW_ERROR(argument, WARNING, "unordered subsequence inside unordered subsequence is discouraged"); - fail_if (simplify_unordered(&(argument->unordered))); - argument->processed = PROCESS_LEVEL; - } - - /* Check the size of the subsequence. */ - if ((argument_count > 5) && (allow_long * argv_force == 0)) - { - if (allow_long == 0) - NEW_ERROR(tree->inner, ERROR, - "unordered subsequence longer than 5 elements need double brackets"); - else if (argv_force == 0) - NEW_ERROR(tree->inner, ERROR, - "unordered subsequence of size %zu found, requires ‘--force’ to compile", argument_count); - return 0; - } - - /* Generate permutations. */ - tree->type = C(ALTERNATION); - tree->processed = PROCESS_LEVEL; - arguments = tree->inner; - if (tree->inner = create_permutations(arguments), tree->inner == NULL) - { - if (errno == 0) - { - /* `create_permutations` can return `NULL` without setting `errno` - * if it does not list any permutations. */ - NEW_ERROR_(result, INTERNAL_ERROR, 0, 0, 0, 0, 1, - "Fail to create permutations of an unordered sequence"); - return 0; + mds_kbdc_tree_t *arguments; + mds_kbdc_tree_t *argument; + mds_kbdc_tree_t *temp; + mds_kbdc_tree_t **here; + int allow_long = 0; + size_t argument_count; + + /* Test for ‘(( ))’. */ + if (tree->inner && !tree->inner->next && tree->inner->type == C(UNORDERED)) { + tree->loc_end = tree->inner->loc_end; + temp = tree->inner; + tree->inner = tree->inner->unordered.inner; + temp->unordered.inner = NULL; + mds_kbdc_tree_free(temp); + allow_long = 1; } - fail_if (tree->inner = arguments, 1); - } - mds_kbdc_tree_free(arguments); - - return 0; - fail: - return -1; + + /* Test emptyness. */ + if (!tree->inner) { + NEW_ERROR(tree, ERROR, "empty unordered subsequence"); + tree->type = C(NOTHING); + tree->processed = PROCESS_LEVEL; + return 0; + } + + /* Test singletonness. */ + if (!tree->inner->next) { + temp = tree->inner; + NEW_ERROR(tree, WARNING, "singleton unordered subsequence"); + memcpy(tree, temp, sizeof(mds_kbdc_tree_t)); + free(temp); + fail_if (simplify((mds_kbdc_tree_t*)tree)); + return -1; + } + + /* Remove ‘.’:s. */ + REMOVE_NOTHING(inner); + + /* Check that the sequnced contained anything else. */ + if (!tree->inner) { + NEW_ERROR(tree, ERROR, "unordered subsequence contained nothing else than ‘.’"); + tree->type = C(NOTHING); + tree->processed = PROCESS_LEVEL; + return 0; + } + + /* Simplify. */ + for (argument = tree->inner, argument_count = 0; argument; argument = argument->next, argument_count++) { + if (argument->type == C(ALTERNATION)) { + fail_if (simplify_alternation(&(argument->alternation))); + argument->processed = PROCESS_LEVEL; + } else if (argument->type == C(UNORDERED)) { + NEW_ERROR(argument, WARNING, "unordered subsequence inside unordered subsequence is discouraged"); + fail_if (simplify_unordered(&(argument->unordered))); + argument->processed = PROCESS_LEVEL; + } + } + + /* Check the size of the subsequence. */ + if (argument_count > 5 && (!allow_long || !argv_force)) { + if (!allow_long) + NEW_ERROR(tree->inner, ERROR, + "unordered subsequence longer than 5 elements need double brackets"); + else if (!argv_force) + NEW_ERROR(tree->inner, ERROR, + "unordered subsequence of size %zu found, requires ‘--force’ to compile", argument_count); + return 0; + } + + /* Generate permutations. */ + tree->type = C(ALTERNATION); + tree->processed = PROCESS_LEVEL; + arguments = tree->inner; + if (!(tree->inner = create_permutations(arguments))) { + if (!errno) { + /* `create_permutations` can return `NULL` without setting `errno` + * if it does not list any permutations. */ + NEW_ERROR_(result, INTERNAL_ERROR, 0, 0, 0, 0, 1, + "Fail to create permutations of an unordered sequence"); + return 0; + } + fail_if (tree->inner = arguments, 1); + } + mds_kbdc_tree_free(arguments); + + return 0; +fail: + return -1; } @@ -804,34 +789,34 @@ static int simplify_unordered(mds_kbdc_tree_unordered_t* restrict tree) * @param tree The tree * @return Zero on success, -1 on error */ -static int simplify(mds_kbdc_tree_t* restrict tree) +static int +simplify(mds_kbdc_tree_t *restrict tree) { -#define s(expr) fail_if (simplify(tree->expr)) -#define S(type) fail_if (simplify_##type(&(tree->type))) - again: - if (tree == NULL) - return 0; - - switch (tree->type) - { - case C(INFORMATION): s (information.inner); break; - case C(FUNCTION): s (function.inner); break; - case C(MACRO): s (macro.inner); break; - case C(ASSUMPTION): s (assumption.inner); break; - case C(FOR): s (for_.inner); break; - case C(IF): s (if_.inner); s (if_.otherwise); break; - case C(MAP): S (map); break; - case C(ALTERNATION): S (alternation); break; - case C(UNORDERED): S (unordered); break; - case C(MACRO_CALL): S (macro_call); break; - default: - break; - } - - tree = tree->next; - goto again; +#define s(expr) fail_if (simplify(tree->expr)) +#define S(type) fail_if (simplify_##type(&(tree->type))) +again: + if (!tree) + return 0; + + switch (tree->type) { + case C(INFORMATION): s (information.inner); break; + case C(FUNCTION): s (function.inner); break; + case C(MACRO): s (macro.inner); break; + case C(ASSUMPTION): s (assumption.inner); break; + case C(FOR): s (for_.inner); break; + case C(IF): s (if_.inner); s (if_.otherwise); break; + case C(MAP): S (map); break; + case C(ALTERNATION): S (alternation); break; + case C(UNORDERED): S (unordered); break; + case C(MACRO_CALL): S (macro_call); break; + default: + break; + } + + tree = tree->next; + goto again; fail: - return -1; + return -1; #undef s #undef S } @@ -843,10 +828,11 @@ static int simplify(mds_kbdc_tree_t* restrict tree) * @param result_ `result` from `parse_to_tree`, same sematics, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int simplify_tree(mds_kbdc_parsed_t* restrict result_) +int +simplify_tree(mds_kbdc_parsed_t *restrict result_) { - result = result_; - return simplify(result_->tree); + result = result_; + return simplify(result_->tree); } @@ -856,4 +842,3 @@ int simplify_tree(mds_kbdc_parsed_t* restrict result_) #undef NEW_ERROR #undef C #undef PROCESS_LEVEL - diff --git a/src/mds-kbdc/simplify-tree.h b/src/mds-kbdc/simplify-tree.h index b5e5ce2..e648a46 100644 --- a/src/mds-kbdc/simplify-tree.h +++ b/src/mds-kbdc/simplify-tree.h @@ -28,8 +28,7 @@ * @param result `result` from `parse_to_tree`, same sematics, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int simplify_tree(mds_kbdc_parsed_t* restrict result); +int simplify_tree(mds_kbdc_parsed_t *restrict result); #endif - diff --git a/src/mds-kbdc/string.c b/src/mds-kbdc/string.c index a334611..c0e9852 100644 --- a/src/mds-kbdc/string.c +++ b/src/mds-kbdc/string.c @@ -30,12 +30,13 @@ * @param string The string * @return The length of the string */ -size_t string_length(const char32_t* restrict string) +size_t +string_length(const char32_t *restrict string) { - size_t i = 0; - while (string[i] != -1) - i++; - return i; + size_t i = 0; + while (string[i] != -1) + i++; + return i; } @@ -45,43 +46,41 @@ size_t string_length(const char32_t* restrict string) * @param string The UTF-8 string * @return The string in UTF-32, `NULL` on error */ -char32_t* string_decode(const char* restrict string) +char32_t * +string_decode(const char *restrict string) { - size_t i, j, n, length = 0; - char32_t* rc; - - /* Get the length of the UTF-32 string, excluding termination. */ - for (i = 0; string[i]; i++) - if ((string[i] & 0xC0) != 0x80) - length++; - - /* Allocated UTF-32 string. */ - fail_if (xmalloc(rc, length + 1, char32_t)); - - /* Convert to UTF-32. */ - for (i = j = n = 0; string[i]; i++) - { - char c = string[i]; - if (n) - { - rc[j] <<= 6, rc[j] |= c & 0x3F; - if (--n == 0) - j++; - } - else if ((c & 0xC0) == 0xC0) - { - while (c & 0x80) - n++, c = (char)(c << 1); - rc[j] = c >> n--; + size_t i, j, n, length = 0; + char32_t *rc; + char c; + + /* Get the length of the UTF-32 string, excluding termination. */ + for (i = 0; string[i]; i++) + if ((string[i] & 0xC0) != 0x80) + length++; + + /* Allocated UTF-32 string. */ + fail_if (xmalloc(rc, length + 1, char32_t)); + + /* Convert to UTF-32. */ + for (i = j = n = 0; string[i]; i++) { + c = string[i]; + if (n) { + rc[j] <<= 6, rc[j] |= c & 0x3F; + if (!--n) + j++; + } else if ((c & 0xC0) == 0xC0) { + while (c & 0x80) + n++, c = (char)(c << 1); + rc[j] = c >> n--; + } else { + rc[j++] = c & 255; + } } - else - rc[j++] = c & 255; - } - /* -1-terminate and return. */ - return rc[length] = -1, rc; - fail: - return NULL; + /* -1-terminate and return. */ + return rc[length] = -1, rc; +fail: + return NULL; } @@ -93,42 +92,43 @@ char32_t* string_decode(const char* restrict string) * @param string The UTF-32 string * @return The string in UTF-8, `NULL` on error */ -char* string_encode(const char32_t* restrict string) +char * +string_encode(const char32_t *restrict string) { - size_t i, j, n = string_length(string); - char* restrict rc; - - /* Allocated Modified UTF-8 string. */ - fail_if (xmalloc(rc, 7 * n + 1, char)); - - /* Convert to Modified UTF-8. */ - for (i = j = 0; i < n; i++) - { -#define _c(s) rc[j++] = (char)(((c >> (s)) & 0x3F) | 0x80) -#define _t(s) (0 < c) && ((uint32_t)c < (uint32_t)(1ULL << s)) - char32_t c = string[i]; - if (c == 0) rc[j++] = (char)0xC0, rc[j++] = (char)0x80; - else if (_t( 7)) rc[j++] = (char)c; - else if (_t(11)) rc[j++] = (char)((c >> 6) | 0xC0), _c( 0); - else if (_t(16)) rc[j++] = (char)((c >> 12) | 0xE0), _c( 6), _c( 0); - else if (_t(21)) rc[j++] = (char)((c >> 18) | 0xF0), _c(12), _c( 6), _c( 0); - /* UTF-8 actually ends here, fits 32 planes. */ - else if (_t(26)) rc[j++] = (char)((c >> 24) | 0xF8), _c(18), _c(12), _c( 6), _c(0); - else if (_t(31)) rc[j++] = (char)((c >> 30) | 0xFC), _c(24), _c(18), _c(12), _c(6), _c(0); - /* The orginal UTF-8 specification ended here, fits 31 bits. - * However, we added another byte so we can fit 32 bits - * (actually we ca now fit 36 bits.) - * However, we only needed this in `string_decode` which would - * not require any changed, but we added it here for symmetry. */ - else rc[j++] = (char)0xFE, _c(30), _c(24), _c(18), _c(12), _c(6), _c(0); + size_t i, j, n = string_length(string); + char *restrict rc; + char32_t c; + + /* Allocated Modified UTF-8 string. */ + fail_if (xmalloc(rc, 7 * n + 1, char)); + + /* Convert to Modified UTF-8. */ + for (i = j = 0; i < n; i++) { +#define _c(s) rc[j++] = (char)(((c >> (s)) & 0x3F) | 0x80) +#define _t(s) (0 < c) && ((uint32_t)c < (uint32_t)(1ULL << (s))) + c = string[i]; + if (!c) rc[j++] = (char)0xC0, rc[j++] = (char)0x80; + else if (_t( 7)) rc[j++] = (char)c; + else if (_t(11)) rc[j++] = (char)((c >> 6) | 0xC0), _c( 0); + else if (_t(16)) rc[j++] = (char)((c >> 12) | 0xE0), _c( 6), _c( 0); + else if (_t(21)) rc[j++] = (char)((c >> 18) | 0xF0), _c(12), _c( 6), _c( 0); + /* UTF-8 actually ends here, fits 32 planes. */ + else if (_t(26)) rc[j++] = (char)((c >> 24) | 0xF8), _c(18), _c(12), _c( 6), _c(0); + else if (_t(31)) rc[j++] = (char)((c >> 30) | 0xFC), _c(24), _c(18), _c(12), _c(6), _c(0); + /* The orginal UTF-8 specification ended here, fits 31 bits. + * However, we added another byte so we can fit 32 bits + * (actually we ca now fit 36 bits.) + * However, we only needed this in `string_decode` which would + * not require any changed, but we added it here for symmetry. */ + else rc[j++] = (char)0xFE, _c(30), _c(24), _c(18), _c(12), _c(6), _c(0); #undef _t #undef _c - } - - /* NUL-terminate and return. */ - return rc[j] = '\0', rc; - fail: - return NULL; + } + + /* NUL-terminate and return. */ + return rc[j] = '\0', rc; +fail: + return NULL; } @@ -138,16 +138,16 @@ char* string_encode(const char32_t* restrict string) * @param string The string * @return A duplicate of the string, `NULL` on error or if `string` is `NULL` */ -char32_t* string_dup(const char32_t* restrict string) +char32_t * +string_dup(const char32_t *restrict string) { - size_t n; - char32_t* rc; - if (string == NULL) - return NULL; - n = string_length(string) + 1; - fail_if (xmemdup(rc, string, n, char32_t)); - return rc; - fail: - return NULL; + size_t n; + char32_t *rc; + if (!string) + return NULL; + n = string_length(string) + 1; + fail_if (xmemdup(rc, string, n, char32_t)); + return rc; +fail: + return NULL; } - diff --git a/src/mds-kbdc/string.h b/src/mds-kbdc/string.h index a58eb91..81155ed 100644 --- a/src/mds-kbdc/string.h +++ b/src/mds-kbdc/string.h @@ -35,7 +35,8 @@ typedef int32_t char32_t; * @param string The string * @return The length of the string */ -size_t string_length(const char32_t* restrict string) __attribute__((pure, nonnull)); +__attribute__((pure, nonnull)) +size_t string_length(const char32_t *restrict string); /** * Convert a NUL-terminated UTF-8 string to a -1-terminated UTF-32 string @@ -43,7 +44,8 @@ size_t string_length(const char32_t* restrict string) __attribute__((pure, nonnu * @param string The UTF-8 string * @return The string in UTF-32, `NULL` on error */ -char32_t* string_decode(const char* restrict string) __attribute__((nonnull)); +__attribute__((nonnull)) +char32_t *string_decode(const char *restrict string); /** * Convert a -1-terminated UTF-32 string to a NUL-terminated Modified UTF-8 string @@ -51,7 +53,8 @@ char32_t* string_decode(const char* restrict string) __attribute__((nonnull)); * @param string The UTF-32 string * @return The string in UTF-8, `NULL` on error */ -char* string_encode(const char32_t* restrict string) __attribute__((nonnull)); +__attribute__((nonnull)) +char *string_encode(const char32_t *restrict string); /** * Create duplicate of a string @@ -59,9 +62,8 @@ char* string_encode(const char32_t* restrict string) __attribute__((nonnull)); * @param string The string * @return A duplicate of the string, `NULL` on error or if `string` is `NULL` */ -char32_t* string_dup(const char32_t* restrict string); +char32_t *string_dup(const char32_t *restrict string); #endif - diff --git a/src/mds-kbdc/tree.c b/src/mds-kbdc/tree.c index 289ccac..33db89e 100644 --- a/src/mds-kbdc/tree.c +++ b/src/mds-kbdc/tree.c @@ -36,7 +36,7 @@ typedef struct mds_kbdc_tree_information_data mds_kbdc_tree_information_data_t; /** * Tree type constant shortener */ -#define C(t) MDS_KBDC_TREE_TYPE_##t +#define C(t) MDS_KBDC_TREE_TYPE_##t /** @@ -45,10 +45,11 @@ typedef struct mds_kbdc_tree_information_data mds_kbdc_tree_information_data_t; * @param this The memory slot for the tree node * @param type The type of the node */ -void mds_kbdc_tree_initialise(mds_kbdc_tree_t* restrict this, int type) +void +mds_kbdc_tree_initialise(mds_kbdc_tree_t *restrict this, int type) { - memset(this, 0, sizeof(mds_kbdc_tree_t)); - this->type = type; + memset(this, 0, sizeof(mds_kbdc_tree_t)); + this->type = type; } @@ -58,14 +59,15 @@ void mds_kbdc_tree_initialise(mds_kbdc_tree_t* restrict this, int type) * @param type The type of the node * @return The tree node, `NULL` on error */ -mds_kbdc_tree_t* mds_kbdc_tree_create(int type) +mds_kbdc_tree_t * +mds_kbdc_tree_create(int type) { - mds_kbdc_tree_t* this; - fail_if (xmalloc(this, 1, mds_kbdc_tree_t)); - mds_kbdc_tree_initialise(this, type); - return this; - fail: - return NULL; + mds_kbdc_tree_t *this; + fail_if (xmalloc(this, 1, mds_kbdc_tree_t)); + mds_kbdc_tree_initialise(this, type); + return this; +fail: + return NULL; } @@ -75,110 +77,109 @@ mds_kbdc_tree_t* mds_kbdc_tree_create(int type) * @param this The tree node * @param recursive Whether subtree should be destroyed and freed */ -static void mds_kbdc_tree_destroy_(mds_kbdc_tree_t* restrict this, int recursive) +static void mds_kbdc_tree_destroy_(mds_kbdc_tree_t *restrict this, int recursive) { -#define V(type, var) (((type)this)->var) -#define xfree(t, v) (free(V(t, v)), V(t, v) = NULL) -#define xdestroy(t, v) (recursive ? (mds_kbdc_tree_destroy_(V(t, v), 1), xfree(t, v)) : (V(t, v) = NULL)) - - mds_kbdc_tree_t* prev = NULL; - mds_kbdc_tree_t* first = this; - - again: - if (this == NULL) - return; - - switch (this->type) - { - case C(INFORMATION): - case C(ASSUMPTION): - case C(ALTERNATION): - case C(UNORDERED): - case C(ORDERED): - xdestroy(mds_kbdc_tree_nesting_t*, inner); - break; - - case C(INFORMATION_LANGUAGE): - case C(INFORMATION_COUNTRY): - case C(INFORMATION_VARIANT): - xfree(mds_kbdc_tree_information_data_t*, data); - break; - - case C(FUNCTION): - case C(MACRO): - xfree(mds_kbdc_tree_callable_t*, name); - xdestroy(mds_kbdc_tree_callable_t*, inner); - break; - - case C(INCLUDE): - xfree(mds_kbdc_tree_include_t*, filename); - xdestroy(mds_kbdc_tree_include_t*, inner); - mds_kbdc_source_code_free(this->include.source_code); - break; - - case C(ASSUMPTION_HAVE): - xdestroy(mds_kbdc_tree_assumption_have_t*, data); - break; - - case C(ASSUMPTION_HAVE_CHARS): - xfree(mds_kbdc_tree_assumption_have_chars_t*, chars); - break; - - case C(ASSUMPTION_HAVE_RANGE): - xfree(mds_kbdc_tree_assumption_have_range_t*, first); - xfree(mds_kbdc_tree_assumption_have_range_t*, last); - break; - - case C(FOR): - xfree(mds_kbdc_tree_for_t*, first); - xfree(mds_kbdc_tree_for_t*, last); - xfree(mds_kbdc_tree_for_t*, variable); - xdestroy(mds_kbdc_tree_for_t*, inner); - break; - - case C(IF): - xfree(mds_kbdc_tree_if_t*, condition); - xdestroy(mds_kbdc_tree_if_t*, inner); - xdestroy(mds_kbdc_tree_if_t*, otherwise); - break; - - case C(LET): - xfree(mds_kbdc_tree_let_t*, variable); - xdestroy(mds_kbdc_tree_let_t*, value); - break; - - case C(MAP): - xdestroy(mds_kbdc_tree_map_t*, sequence); - xdestroy(mds_kbdc_tree_map_t*, result); - break; - - case C(ARRAY): - xdestroy(mds_kbdc_tree_array_t*, elements); - break; - - case C(KEYS): - case C(STRING): - case C(COMPILED_KEYS): - case C(COMPILED_STRING): - xfree(mds_kbdc_tree_keys_t*, keys); - /* We are abusing the similaries of the structures. */ - break; - - case C(MACRO_CALL): - xfree(mds_kbdc_tree_macro_call_t*, name); - xdestroy(mds_kbdc_tree_macro_call_t*, arguments); - break; - - default: - break; - } - - prev = this; - this = this->next; - if (prev != first) - free(prev); - goto again; - +#define V(type, var) (((type)this)->var) +#define xfree(t, v) (free(V(t, v)), V(t, v) = NULL) +#define xdestroy(t, v) (recursive ? (mds_kbdc_tree_destroy_(V(t, v), 1), xfree(t, v)) : (V(t, v) = NULL)) + + mds_kbdc_tree_t *prev = NULL; + mds_kbdc_tree_t *first = this; + +again: + if (!this) + return; + + switch (this->type) { + case C(INFORMATION): + case C(ASSUMPTION): + case C(ALTERNATION): + case C(UNORDERED): + case C(ORDERED): + xdestroy(mds_kbdc_tree_nesting_t *, inner); + break; + + case C(INFORMATION_LANGUAGE): + case C(INFORMATION_COUNTRY): + case C(INFORMATION_VARIANT): + xfree(mds_kbdc_tree_information_data_t *, data); + break; + + case C(FUNCTION): + case C(MACRO): + xfree(mds_kbdc_tree_callable_t *, name); + xdestroy(mds_kbdc_tree_callable_t *, inner); + break; + + case C(INCLUDE): + xfree(mds_kbdc_tree_include_t *, filename); + xdestroy(mds_kbdc_tree_include_t *, inner); + mds_kbdc_source_code_free(this->include.source_code); + break; + + case C(ASSUMPTION_HAVE): + xdestroy(mds_kbdc_tree_assumption_have_t *, data); + break; + + case C(ASSUMPTION_HAVE_CHARS): + xfree(mds_kbdc_tree_assumption_have_chars_t *, chars); + break; + + case C(ASSUMPTION_HAVE_RANGE): + xfree(mds_kbdc_tree_assumption_have_range_t *, first); + xfree(mds_kbdc_tree_assumption_have_range_t *, last); + break; + + case C(FOR): + xfree(mds_kbdc_tree_for_t *, first); + xfree(mds_kbdc_tree_for_t *, last); + xfree(mds_kbdc_tree_for_t *, variable); + xdestroy(mds_kbdc_tree_for_t *, inner); + break; + + case C(IF): + xfree(mds_kbdc_tree_if_t *, condition); + xdestroy(mds_kbdc_tree_if_t *, inner); + xdestroy(mds_kbdc_tree_if_t *, otherwise); + break; + + case C(LET): + xfree(mds_kbdc_tree_let_t *, variable); + xdestroy(mds_kbdc_tree_let_t *, value); + break; + + case C(MAP): + xdestroy(mds_kbdc_tree_map_t *, sequence); + xdestroy(mds_kbdc_tree_map_t *, result); + break; + + case C(ARRAY): + xdestroy(mds_kbdc_tree_array_t *, elements); + break; + + case C(KEYS): + case C(STRING): + case C(COMPILED_KEYS): + case C(COMPILED_STRING): + xfree(mds_kbdc_tree_keys_t *, keys); + /* We are abusing the similaries of the structures. */ + break; + + case C(MACRO_CALL): + xfree(mds_kbdc_tree_macro_call_t *, name); + xdestroy(mds_kbdc_tree_macro_call_t *, arguments); + break; + + default: + break; + } + + prev = this; + this = this->next; + if (prev != first) + free(prev); + goto again; + #undef xdestroy #undef xfree #undef V @@ -192,9 +193,10 @@ static void mds_kbdc_tree_destroy_(mds_kbdc_tree_t* restrict this, int recursive * * @param this The tree node */ -void mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t* restrict this) +void +mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t *restrict this) { - mds_kbdc_tree_destroy_(this, 0); + mds_kbdc_tree_destroy_(this, 0); } @@ -206,10 +208,11 @@ void mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t* restrict this) * * @param this The tree node */ -void mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t* restrict this) +void +mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t *restrict this) { - mds_kbdc_tree_destroy_nonrecursive(this); - free(this); + mds_kbdc_tree_destroy_nonrecursive(this); + free(this); } @@ -220,9 +223,10 @@ void mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t* restrict this) * * @param this The tree node */ -void mds_kbdc_tree_destroy(mds_kbdc_tree_t* restrict this) +void +mds_kbdc_tree_destroy(mds_kbdc_tree_t *restrict this) { - mds_kbdc_tree_destroy_(this, 1); + mds_kbdc_tree_destroy_(this, 1); } @@ -233,10 +237,11 @@ void mds_kbdc_tree_destroy(mds_kbdc_tree_t* restrict this) * * @param this The tree node */ -void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) +void +mds_kbdc_tree_free(mds_kbdc_tree_t *restrict this) { - mds_kbdc_tree_destroy(this); - free(this); + mds_kbdc_tree_destroy(this); + free(this); } @@ -246,7 +251,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) * * @param member:identifer The member in the tree to duplicate */ -#define T(member) fail_if (t->member && (n->member = mds_kbdc_tree_dup(t->member), n->member == NULL)) +#define T(member) fail_if (t->member && !(n->member = mds_kbdc_tree_dup(t->member))) /** @@ -254,7 +259,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) * * @param member:identifer The member in the tree to duplicate */ -#define S(member) fail_if (t->member && xstrdup(n->member, t->member)) +#define S(member) fail_if (t->member && xstrdup(n->member, t->member)) /** @@ -262,7 +267,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) * * @param member:identifer The member in the tree to duplicate */ -#define Z(member) fail_if (t->member && (n->member = string_dup(t->member), n->member == NULL)) +#define Z(member) fail_if (t->member && !(n->member = string_dup(t->member))) /** @@ -270,7 +275,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) * * @param member:identifer The member in the tree to copied */ -#define R(member) fail_if (t->member && (n->member = mds_kbdc_source_code_dup(t->member), n->member == NULL)) +#define R(member) fail_if (t->member && !(n->member = mds_kbdc_source_code_dup(t->member))) @@ -280,62 +285,109 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) * @param this The tree node * @return A duplicate of `this`, `NULL` on error */ -mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) +mds_kbdc_tree_t * +mds_kbdc_tree_dup(const mds_kbdc_tree_t *restrict this) { -#define t this -#define n (*node) - mds_kbdc_tree_t* rc = NULL; - mds_kbdc_tree_t** node = &rc; - int saved_errno; - - again: - if (t == NULL) return rc; - fail_if (xcalloc(n, 1, mds_kbdc_tree_t)); +#define t this +#define n (*node) + mds_kbdc_tree_t *rc = NULL; + mds_kbdc_tree_t **node = &rc; + int saved_errno; + +again: + if (!t) + return rc; + fail_if (xcalloc(n, 1, mds_kbdc_tree_t)); + + n->type = t->type; + n->loc_line = t->loc_line; + n->loc_start = t->loc_start; + n->loc_end = t->loc_end; + n->processed = t->processed; + + switch (this->type) { + case C(INFORMATION): + case C(ASSUMPTION): + case C(ALTERNATION): + case C(UNORDERED): + case C(ORDERED): + T(ordered.inner); + break; + case C(FUNCTION): + case C(MACRO): + S(macro.name); + T(macro.inner); + break; + case C(ASSUMPTION_HAVE): + T(have.data); + break; + case C(ARRAY): + T(array.elements); + break; + case C(LET): + S(let.variable); + T(let.value); + break; + case C(MACRO_CALL): + S(macro_call.name); + T(macro_call.arguments); + break; + case C(INFORMATION_LANGUAGE): + case C(INFORMATION_COUNTRY): + case C(INFORMATION_VARIANT): + S(variant.data); + break; + case C(INCLUDE): + S(include.filename); + T(include.inner); + R(include.source_code); + break; + case C(ASSUMPTION_HAVE_CHARS): + S(have_chars.chars); + break; + case C(KEYS): + S(keys.keys); + break; + case C(STRING): + S(string.string); + break; + case C(COMPILED_KEYS): + Z(compiled_keys.keys); + break; + case C(COMPILED_STRING): + Z(compiled_string.string); + break; + case C(ASSUMPTION_HAVE_RANGE): + S(have_range.first); + S(have_range.last); + break; + case C(FOR): + S(for_.first); + S(for_.last); + S(for_.variable); + T(for_.inner); + break; + case C(IF): + S(if_.condition); + T(if_.inner); + T(if_.otherwise); + break; + case C(MAP): + T(map.sequence); + T(map.result); + break; + default: + break; + } + + t = t->next; + node = &(n->next); + goto again; - n->type = t->type; - n->loc_line = t->loc_line; - n->loc_start = t->loc_start; - n->loc_end = t->loc_end; - n->processed = t->processed; - - switch (this->type) - { - case C(INFORMATION): - case C(ASSUMPTION): - case C(ALTERNATION): - case C(UNORDERED): - case C(ORDERED): T(ordered.inner); break; - case C(FUNCTION): - case C(MACRO): S(macro.name); T(macro.inner); break; - case C(ASSUMPTION_HAVE): T(have.data); break; - case C(ARRAY): T(array.elements); break; - case C(LET): S(let.variable); T(let.value); break; - case C(MACRO_CALL): S(macro_call.name); T(macro_call.arguments); break; - case C(INFORMATION_LANGUAGE): - case C(INFORMATION_COUNTRY): - case C(INFORMATION_VARIANT): S(variant.data); break; - case C(INCLUDE): S(include.filename); T(include.inner); R(include.source_code); break; - case C(ASSUMPTION_HAVE_CHARS): S(have_chars.chars); break; - case C(KEYS): S(keys.keys); break; - case C(STRING): S(string.string); break; - case C(COMPILED_KEYS): Z(compiled_keys.keys); break; - case C(COMPILED_STRING): Z(compiled_string.string); break; - case C(ASSUMPTION_HAVE_RANGE): S(have_range.first); S(have_range.last); break; - case C(FOR): S(for_.first); S(for_.last); S(for_.variable); T(for_.inner); break; - case C(IF): S(if_.condition); T(if_.inner); T(if_.otherwise); break; - case C(MAP): T(map.sequence); T(map.result); break; - default: - break; - } - - t = t->next; - node = &(n->next); - goto again; - - fail: - saved_errno = errno; - mds_kbdc_tree_free(rc); - return errno = saved_errno, NULL; +fail: + saved_errno = errno; + mds_kbdc_tree_free(rc); + return errno = saved_errno, NULL; #undef n #undef t } @@ -355,12 +407,12 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * @param LOWERCASE:identifer The name of subtype * @param NOTATION:const char* The notation for the subtype */ -#define NODE(LOWERCASE, NOTATION) \ - const mds_kbdc_tree_##LOWERCASE##_t* node; \ - node = (const mds_kbdc_tree_##LOWERCASE##_t*)this; \ - fprintf(output, "%*.s(\033[01m%s\033[00m", indent, "", NOTATION); \ - fprintf(output, " \033[36m(@ %zu %zu-%zu)\033[00m", \ - node->loc_line + 1, node->loc_start, node->loc_end) +#define NODE(LOWERCASE, NOTATION)\ + const mds_kbdc_tree_##LOWERCASE##_t *node;\ + node = (const mds_kbdc_tree_##LOWERCASE##_t *)this;\ + fprintf(output, "%*.s(\033[01m%s\033[00m", indent, "", NOTATION);\ + fprintf(output, " \033[36m(@ %zu %zu-%zu)\033[00m",\ + node->loc_line + 1, node->loc_start, node->loc_end) /** @@ -368,22 +420,23 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * * @param MEMBER:identifier The tree structure's member */ -#define BRANCH(MEMBER) \ - if (node->MEMBER) \ - { \ - fprintf(output, "\n%*.s(.%s\n", indent + 2, "", #MEMBER); \ - mds_kbdc_tree_print_indented(node->MEMBER, output, indent + 4); \ - fprintf(output, "%*.s)", indent + 2, ""); \ - } \ - else \ - fprintf(output, "\n%*.s(.%s \033[35mnil\033[00m)", indent + 2, "", #MEMBER) +#define BRANCH(MEMBER)\ + do {\ + if (node->MEMBER) {\ + fprintf(output, "\n%*.s(.%s\n", indent + 2, "", #MEMBER);\ + mds_kbdc_tree_print_indented(node->MEMBER, output, indent + 4);\ + fprintf(output, "%*.s)", indent + 2, "");\ + } else {\ + fprintf(output, "\n%*.s(.%s \033[35mnil\033[00m)", indent + 2, "", #MEMBER);\ + }\ + } while (0) /** * End a tree which has at least one member that is a subtree */ -#define COMPLEX \ - fprintf(output, "\n%*.s)\n", indent, "") +#define COMPLEX\ + fprintf(output, "\n%*.s)\n", indent, "") /** @@ -391,11 +444,13 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * * @param MEMBER:identifier The tree structure's member */ -#define STRING(MEMBER) \ - if (node->MEMBER) \ - fprintf(output, " ‘\033[32m%s\033[00m’", node->MEMBER); \ - else \ - fprintf(output, " \033[35mnil\033[00m") +#define STRING(MEMBER)\ + do {\ + if (node->MEMBER)\ + fprintf(output, " ‘\033[32m%s\033[00m’", node->MEMBER);\ + else\ + fprintf(output, " \033[35mnil\033[00m");\ + } while (0) /** @@ -404,9 +459,11 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * * @param MEMBER:identifier The tree structure's member */ -#define SIMPLE(MEMBER) \ - STRING(MEMBER); \ - fprintf(output, ")\n") +#define SIMPLE(MEMBER)\ + do {\ + STRING(MEMBER);\ + fprintf(output, ")\n");\ + } while (0) /** @@ -417,12 +474,12 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * @param NOTATION:const char* See `NODE` * @param MEMBER:identifier See `STRING` */ -#define SIMPLEX(LOWERCASE, NOTATION, MEMBER) \ - { \ - NODE(LOWERCASE, NOTATION); \ - SIMPLE(MEMBER); \ - } \ - break +#define SIMPLEX(LOWERCASE, NOTATION, MEMBER)\ + {\ + NODE(LOWERCASE, NOTATION);\ + SIMPLE(MEMBER);\ + }\ + break /** @@ -434,13 +491,13 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * @param FIRST:identifier See `STRING`, the first member * @param LAST:identifier See `STRING`, the second member */ -#define DUPLEX(LOWERCASE, NOTATION, FIRST, LAST) \ - { \ - NODE(LOWERCASE, NOTATION); \ - STRING(FIRST); \ - SIMPLE(LAST); \ - } \ - break +#define DUPLEX(LOWERCASE, NOTATION, FIRST, LAST)\ + {\ + NODE(LOWERCASE, NOTATION);\ + STRING(FIRST);\ + SIMPLE(LAST);\ + }\ + break /** @@ -451,13 +508,13 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * @param NOTATION:const char* See `NODE` * @param MEMBER:identifier See `BRANCH` */ -#define NESTING(LOWERCASE, NOTATION, MEMBER) \ - { \ - NODE(LOWERCASE, NOTATION); \ - BRANCH(MEMBER); \ - COMPLEX; \ - } \ - break +#define NESTING(LOWERCASE, NOTATION, MEMBER)\ + {\ + NODE(LOWERCASE, NOTATION);\ + BRANCH(MEMBER);\ + COMPLEX;\ + }\ + break /** @@ -470,14 +527,14 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * @param NAMER:identifier See `STRING` * @param MEMBER:identifier See `BRANCH` */ -#define NAMED_NESTING(LOWERCASE, NOTATION, NAMER, MEMBER) \ - { \ - NODE(LOWERCASE, NOTATION); \ - STRING(NAMER); \ - BRANCH(MEMBER); \ - COMPLEX; \ - } \ - break +#define NAMED_NESTING(LOWERCASE, NOTATION, NAMER, MEMBER)\ + {\ + NODE(LOWERCASE, NOTATION);\ + STRING(NAMER);\ + BRANCH(MEMBER);\ + COMPLEX;\ + }\ + break /** @@ -485,12 +542,12 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * * @param NOTATION:const char* See `NODE` */ -#define NOTHING(NOTATION) \ - fprintf(output, "%*.s(\033[01m%s\033[00m", indent, "", NOTATION); \ - fprintf(output, " \033[36m(@ %zu %zu-%zu)\033[00m", \ - this->loc_line + 1, this->loc_start, this->loc_end); \ - fprintf(output, ")\n"); \ - break +#define NOTHING(NOTATION)\ + fprintf(output, "%*.s(\033[01m%s\033[00m", indent, "", NOTATION);\ + fprintf(output, " \033[36m(@ %zu %zu-%zu)\033[00m",\ + this->loc_line + 1, this->loc_start, this->loc_end);\ + fprintf(output, ")\n");\ + break @@ -501,100 +558,100 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * @param output The output file * @param indent The indent */ -static void mds_kbdc_tree_print_indented(const mds_kbdc_tree_t* restrict this, FILE* output, int indent) +static void +mds_kbdc_tree_print_indented(const mds_kbdc_tree_t *restrict this, FILE *output, int indent) { - again: - if (this == NULL) - return; - - switch (this->type) - { - /* These have their break built into their macro. */ - case C(INFORMATION): NESTING(information, "information", inner); - case C(INFORMATION_LANGUAGE): SIMPLEX(information_language, "language", data); - case C(INFORMATION_COUNTRY): SIMPLEX(information_country, "country", data); - case C(INFORMATION_VARIANT): SIMPLEX(information_variant, "variant", data); - case C(INCLUDE): NAMED_NESTING(include, "include", filename, inner); - case C(FUNCTION): NAMED_NESTING(function, "function", name, inner); - case C(MACRO): NAMED_NESTING(macro, "macro", name, inner); - case C(ASSUMPTION): NESTING(assumption, "assumption", inner); - case C(ASSUMPTION_HAVE): NESTING(assumption_have, "have", data); - case C(ASSUMPTION_HAVE_CHARS): SIMPLEX(assumption_have_chars, "have_chars", chars); - case C(ASSUMPTION_HAVE_RANGE): DUPLEX(assumption_have_range, "have_range", first, last); - case C(LET): NAMED_NESTING(let, "let", variable, value); - case C(ARRAY): NESTING(array, "array", elements); - case C(KEYS): SIMPLEX(keys, "keys", keys); - case C(STRING): SIMPLEX(string, "string", string); - case C(NOTHING): NOTHING("nothing"); - case C(ALTERNATION): NESTING(alternation, "alternation", inner); - case C(UNORDERED): NESTING(unordered, "unordered", inner); - case C(ORDERED): NESTING(ordered, "ordered", inner); - case C(MACRO_CALL): NAMED_NESTING(macro_call, "macro_call", name, arguments); - case C(RETURN): NOTHING("return"); - case C(BREAK): NOTHING("break"); - case C(CONTINUE): NOTHING("continue"); - - case C(COMPILED_KEYS): - { - NODE(compiled_keys, "compiled_keys"); - if (node->keys) - fprintf(output, " ‘\033[32m%s\033[00m’", string_encode(node->keys)); - else - fprintf(output, " \033[35mnil\033[00m"); - fprintf(output, ")\n"); - } - break; - - case C(COMPILED_STRING): - { - NODE(compiled_string, "compiled_string"); - if (node->string) - fprintf(output, " ‘\033[32m%s\033[00m’", string_encode(node->string)); - else - fprintf(output, " \033[35mnil\033[00m"); - fprintf(output, ")\n"); - } - break; - - case C(FOR): - { - NODE(for, "for"); - STRING(first); - STRING(last); - fprintf(output, " (.variable"); - STRING(variable); - fprintf(output, ")"); - BRANCH(inner); - COMPLEX; - } - break; - - case C(IF): - { - NODE(if, "if"); - STRING(condition); - BRANCH(inner); - BRANCH(otherwise); - COMPLEX; - } - break; - - case C(MAP): - { - NODE(map, "map"); - BRANCH(sequence); - BRANCH(result); - COMPLEX; - } - break; - - default: - abort(); - break; - } - - this = this->next; - goto again; +again: + if (!this) + return; + + switch (this->type) { + /* These have their break built into their macro. */ + case C(INFORMATION): NESTING(information, "information", inner); + case C(INFORMATION_LANGUAGE): SIMPLEX(information_language, "language", data); + case C(INFORMATION_COUNTRY): SIMPLEX(information_country, "country", data); + case C(INFORMATION_VARIANT): SIMPLEX(information_variant, "variant", data); + case C(INCLUDE): NAMED_NESTING(include, "include", filename, inner); + case C(FUNCTION): NAMED_NESTING(function, "function", name, inner); + case C(MACRO): NAMED_NESTING(macro, "macro", name, inner); + case C(ASSUMPTION): NESTING(assumption, "assumption", inner); + case C(ASSUMPTION_HAVE): NESTING(assumption_have, "have", data); + case C(ASSUMPTION_HAVE_CHARS): SIMPLEX(assumption_have_chars, "have_chars", chars); + case C(ASSUMPTION_HAVE_RANGE): DUPLEX(assumption_have_range, "have_range", first, last); + case C(LET): NAMED_NESTING(let, "let", variable, value); + case C(ARRAY): NESTING(array, "array", elements); + case C(KEYS): SIMPLEX(keys, "keys", keys); + case C(STRING): SIMPLEX(string, "string", string); + case C(NOTHING): NOTHING("nothing"); + case C(ALTERNATION): NESTING(alternation, "alternation", inner); + case C(UNORDERED): NESTING(unordered, "unordered", inner); + case C(ORDERED): NESTING(ordered, "ordered", inner); + case C(MACRO_CALL): NAMED_NESTING(macro_call, "macro_call", name, arguments); + case C(RETURN): NOTHING("return"); + case C(BREAK): NOTHING("break"); + case C(CONTINUE): NOTHING("continue"); + + case C(COMPILED_KEYS): + { + NODE(compiled_keys, "compiled_keys"); + if (node->keys) + fprintf(output, " ‘\033[32m%s\033[00m’", string_encode(node->keys)); + else + fprintf(output, " \033[35mnil\033[00m"); + fprintf(output, ")\n"); + } + break; + + case C(COMPILED_STRING): + { + NODE(compiled_string, "compiled_string"); + if (node->string) + fprintf(output, " ‘\033[32m%s\033[00m’", string_encode(node->string)); + else + fprintf(output, " \033[35mnil\033[00m"); + fprintf(output, ")\n"); + } + break; + + case C(FOR): + { + NODE(for, "for"); + STRING(first); + STRING(last); + fprintf(output, " (.variable"); + STRING(variable); + fprintf(output, ")"); + BRANCH(inner); + COMPLEX; + } + break; + + case C(IF): + { + NODE(if, "if"); + STRING(condition); + BRANCH(inner); + BRANCH(otherwise); + COMPLEX; + } + break; + + case C(MAP): + { + NODE(map, "map"); + BRANCH(sequence); + BRANCH(result); + COMPLEX; + } + break; + + default: + abort(); + break; + } + + this = this->next; + goto again; } @@ -604,9 +661,10 @@ static void mds_kbdc_tree_print_indented(const mds_kbdc_tree_t* restrict this, F * @param this The tree node * @param output The output file */ -void mds_kbdc_tree_print(const mds_kbdc_tree_t* restrict this, FILE* output) +void +mds_kbdc_tree_print(const mds_kbdc_tree_t *restrict this, FILE *output) { - mds_kbdc_tree_print_indented(this, output, 0); + mds_kbdc_tree_print_indented(this, output, 0); } @@ -622,4 +680,3 @@ void mds_kbdc_tree_print(const mds_kbdc_tree_t* restrict this, FILE* output) #undef NODE #undef C - diff --git a/src/mds-kbdc/tree.h b/src/mds-kbdc/tree.h index e9d28f4..392c85b 100644 --- a/src/mds-kbdc/tree.h +++ b/src/mds-kbdc/tree.h @@ -32,142 +32,142 @@ /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_information_t` */ -#define MDS_KBDC_TREE_TYPE_INFORMATION 0 +#define MDS_KBDC_TREE_TYPE_INFORMATION 0 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_information_language_t` */ -#define MDS_KBDC_TREE_TYPE_INFORMATION_LANGUAGE 1 +#define MDS_KBDC_TREE_TYPE_INFORMATION_LANGUAGE 1 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_information_country_t` */ -#define MDS_KBDC_TREE_TYPE_INFORMATION_COUNTRY 2 +#define MDS_KBDC_TREE_TYPE_INFORMATION_COUNTRY 2 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_information_variant_t` */ -#define MDS_KBDC_TREE_TYPE_INFORMATION_VARIANT 3 +#define MDS_KBDC_TREE_TYPE_INFORMATION_VARIANT 3 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_include_t` */ -#define MDS_KBDC_TREE_TYPE_INCLUDE 4 +#define MDS_KBDC_TREE_TYPE_INCLUDE 4 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_function_t` */ -#define MDS_KBDC_TREE_TYPE_FUNCTION 5 +#define MDS_KBDC_TREE_TYPE_FUNCTION 5 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_macro_t` */ -#define MDS_KBDC_TREE_TYPE_MACRO 6 +#define MDS_KBDC_TREE_TYPE_MACRO 6 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_assumption` */ -#define MDS_KBDC_TREE_TYPE_ASSUMPTION 7 +#define MDS_KBDC_TREE_TYPE_ASSUMPTION 7 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_assumption_have_t` */ -#define MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE 8 +#define MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE 8 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_assumption_have_chars_t` */ -#define MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_CHARS 9 +#define MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_CHARS 9 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_assumption_have_range_t` */ -#define MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_RANGE 10 +#define MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_RANGE 10 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_for_t` */ -#define MDS_KBDC_TREE_TYPE_FOR 11 +#define MDS_KBDC_TREE_TYPE_FOR 11 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_if_t` */ -#define MDS_KBDC_TREE_TYPE_IF 12 +#define MDS_KBDC_TREE_TYPE_IF 12 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_let_t` */ -#define MDS_KBDC_TREE_TYPE_LET 13 +#define MDS_KBDC_TREE_TYPE_LET 13 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_map_t` */ -#define MDS_KBDC_TREE_TYPE_MAP 14 +#define MDS_KBDC_TREE_TYPE_MAP 14 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_array_t` */ -#define MDS_KBDC_TREE_TYPE_ARRAY 15 +#define MDS_KBDC_TREE_TYPE_ARRAY 15 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_keys_t` */ -#define MDS_KBDC_TREE_TYPE_KEYS 16 +#define MDS_KBDC_TREE_TYPE_KEYS 16 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_string_t` */ -#define MDS_KBDC_TREE_TYPE_STRING 17 +#define MDS_KBDC_TREE_TYPE_STRING 17 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_compiled_keys_t` */ -#define MDS_KBDC_TREE_TYPE_COMPILED_KEYS 18 +#define MDS_KBDC_TREE_TYPE_COMPILED_KEYS 18 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_compiled_string_t` */ -#define MDS_KBDC_TREE_TYPE_COMPILED_STRING 19 +#define MDS_KBDC_TREE_TYPE_COMPILED_STRING 19 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_nothing_t` */ -#define MDS_KBDC_TREE_TYPE_NOTHING 20 +#define MDS_KBDC_TREE_TYPE_NOTHING 20 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_alternation_t` */ -#define MDS_KBDC_TREE_TYPE_ALTERNATION 21 +#define MDS_KBDC_TREE_TYPE_ALTERNATION 21 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_unordered_t` */ -#define MDS_KBDC_TREE_TYPE_UNORDERED 22 +#define MDS_KBDC_TREE_TYPE_UNORDERED 22 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_ordered_t` */ -#define MDS_KBDC_TREE_TYPE_ORDERED 23 +#define MDS_KBDC_TREE_TYPE_ORDERED 23 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_macro_call_t` */ -#define MDS_KBDC_TREE_TYPE_MACRO_CALL 24 +#define MDS_KBDC_TREE_TYPE_MACRO_CALL 24 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_return_t` */ -#define MDS_KBDC_TREE_TYPE_RETURN 25 +#define MDS_KBDC_TREE_TYPE_RETURN 25 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_break_t` */ -#define MDS_KBDC_TREE_TYPE_BREAK 26 +#define MDS_KBDC_TREE_TYPE_BREAK 26 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_continue_t` */ -#define MDS_KBDC_TREE_TYPE_CONTINUE 27 +#define MDS_KBDC_TREE_TYPE_CONTINUE 27 @@ -196,13 +196,13 @@ typedef union mds_kbdc_tree mds_kbdc_tree_t; * - size_t loc_end; -- The last byte in the source code where this is found, exclusive * - long processed; -- The lasted step where the statement has already been processed once */ -#define MDS_KBDC_TREE_COMMON \ - int type; \ - mds_kbdc_tree_t* next; \ - size_t loc_line; \ - size_t loc_start; \ - size_t loc_end; \ - long processed +#define MDS_KBDC_TREE_COMMON\ + int type;\ + mds_kbdc_tree_t *next;\ + size_t loc_line;\ + size_t loc_start;\ + size_t loc_end;\ + long processed /** * This macro is used in this header file, and is then @@ -211,7 +211,7 @@ typedef union mds_kbdc_tree mds_kbdc_tree_t; * @param S:size_t The size of the data structure excluding this padding and * the members defined by the macro `MDS_KBDC_TREE_COMMON` */ -#define MDS_KBDC_TREE_PADDING_(S) char _padding[(5 * sizeof(void*) - (S)) / sizeof(char)] +#define MDS_KBDC_TREE_PADDING_(S) char _padding[(5 * sizeof(void*) - (S)) / sizeof(char)] /** * This macro is used in this header file, and is then @@ -221,7 +221,7 @@ typedef union mds_kbdc_tree mds_kbdc_tree_t; * structure excluding this padding and the members defined * by the macro `MDS_KBDC_TREE_COMMON` */ -#define MDS_KBDC_TREE_PADDING(N) MDS_KBDC_TREE_PADDING_((N) * sizeof(void*)) +#define MDS_KBDC_TREE_PADDING(N) MDS_KBDC_TREE_PADDING_((N) * sizeof(void*)) @@ -232,17 +232,16 @@ typedef union mds_kbdc_tree mds_kbdc_tree_t; * the common members, a pointer to the first * node on next level in the tree */ -struct mds_kbdc_tree_nesting -{ - MDS_KBDC_TREE_COMMON; - - /** - * The first child node, `.inner.next` - * is used to access the second child node. - */ - mds_kbdc_tree_t* inner; - - MDS_KBDC_TREE_PADDING(1); +struct mds_kbdc_tree_nesting { + MDS_KBDC_TREE_COMMON; + + /** + * The first child node, `.inner.next` + * is used to access the second child node. + */ + mds_kbdc_tree_t *inner; + + MDS_KBDC_TREE_PADDING(1); }; @@ -258,16 +257,15 @@ typedef struct mds_kbdc_tree_nesting mds_kbdc_tree_information_t; * for the tree structurs for the information * entries: the children of `mds_kbdc_tree_information_t` */ -struct mds_kbdc_tree_information_data -{ - MDS_KBDC_TREE_COMMON; - - /** - * The value of the information entry - */ - char* data; - - MDS_KBDC_TREE_PADDING(1); +struct mds_kbdc_tree_information_data { + MDS_KBDC_TREE_COMMON; + + /** + * The value of the information entry + */ + char *data; + + MDS_KBDC_TREE_PADDING(1); }; @@ -290,27 +288,25 @@ typedef struct mds_kbdc_tree_information_data mds_kbdc_tree_information_variant_ /** * Leaf structure for inclusion of a file */ -typedef struct mds_kbdc_tree_include -{ - MDS_KBDC_TREE_COMMON; - - /** - * The included layout code tree - */ - mds_kbdc_tree_t* inner; - - /** - * The filename of the file to include - */ - char* filename; - - /** - * The source code of the file included by this statement - */ - mds_kbdc_source_code_t* source_code; - - MDS_KBDC_TREE_PADDING(3); - +typedef struct mds_kbdc_tree_include { + MDS_KBDC_TREE_COMMON; + + /** + * The included layout code tree + */ + mds_kbdc_tree_t *inner; + + /** + * The filename of the file to include + */ + char *filename; + + /** + * The source code of the file included by this statement + */ + mds_kbdc_source_code_t* source_code; + + MDS_KBDC_TREE_PADDING(3); } mds_kbdc_tree_include_t; @@ -320,28 +316,27 @@ typedef struct mds_kbdc_tree_include * for tree structurs that define a callable * element */ -struct mds_kbdc_tree_callable -{ - MDS_KBDC_TREE_COMMON; - - /** - * The first child node, `.inner.next` - * is used to access the second child node - */ - mds_kbdc_tree_t* inner; - - /* It is important that `.inner` is first because - * it is first in `struct mds_kbdc_tree_nesting` - * too which means that `.inner` has to same - * offset everyever (except in `mds_kbdc_tree_if_t`). - */ - - /** - * The name of the callable - */ - char* name; - - MDS_KBDC_TREE_PADDING(2); +struct mds_kbdc_tree_callable { + MDS_KBDC_TREE_COMMON; + + /** + * The first child node, `.inner.next` + * is used to access the second child node + */ + mds_kbdc_tree_t *inner; + + /* It is important that `.inner` is first because + * it is first in `struct mds_kbdc_tree_nesting` + * too which means that `.inner` has to same + * offset everyever (except in `mds_kbdc_tree_if_t`). + */ + + /** + * The name of the callable + */ + char *name; + + MDS_KBDC_TREE_PADDING(2); }; @@ -366,17 +361,15 @@ typedef struct mds_kbdc_tree_nesting mds_kbdc_tree_assumption_t; * Tree structure for making the assumption * that there is a mapping to a key or string */ -typedef struct mds_kbdc_tree_assumption_have -{ - MDS_KBDC_TREE_COMMON; - - /** - * The key or string - */ - mds_kbdc_tree_t* data; - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_assumption_have { + MDS_KBDC_TREE_COMMON; + + /** + * The key or string + */ + mds_kbdc_tree_t *data; + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_assumption_have_t; @@ -384,17 +377,15 @@ typedef struct mds_kbdc_tree_assumption_have * Leaf structure for making the assumption * that there are mappings to a set of characters */ -typedef struct mds_kbdc_tree_assumption_have_chars -{ - MDS_KBDC_TREE_COMMON; - - /** - * The characters - */ - char* chars; - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_assumption_have_chars { + MDS_KBDC_TREE_COMMON; + + /** + * The characters + */ + char *chars; + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_assumption_have_chars_t; @@ -402,91 +393,85 @@ typedef struct mds_kbdc_tree_assumption_have_chars * Leaf structure for making the assumption * that there are mappings to a range of characters */ -typedef struct mds_kbdc_tree_assumption_have_range -{ - MDS_KBDC_TREE_COMMON; - - /** - * The first character, inclusive - */ - char* first; - - /** - * The last character, inclusive - */ - char* last; - - MDS_KBDC_TREE_PADDING(2); - +typedef struct mds_kbdc_tree_assumption_have_range { + MDS_KBDC_TREE_COMMON; + + /** + * The first character, inclusive + */ + char *first; + + /** + * The last character, inclusive + */ + char *last; + + MDS_KBDC_TREE_PADDING(2); } mds_kbdc_tree_assumption_have_range_t; /** * Tree structure for a "for"-loop */ -typedef struct mds_kbdc_tree_for -{ - MDS_KBDC_TREE_COMMON; - - /** - * The first child node, `.inner.next` is - * used to access the second child node. - * This is what should be done inside the loop. - */ - mds_kbdc_tree_t* inner; - - /* It is important that `.inner` is first because - * it is first in `struct mds_kbdc_tree_nesting` - * too which means that `.inner` has to same - * offset everyever (except in `mds_kbdc_tree_if_t`). - */ - - /** - * The first value to variable should take, inclusive - */ - char* first; - - /** - * The last value the variable should take, inclusive - */ - char* last; - - /** - * The variable - */ - char* variable; - - MDS_KBDC_TREE_PADDING(4); - +typedef struct mds_kbdc_tree_for { + MDS_KBDC_TREE_COMMON; + + /** + * The first child node, `.inner.next` is + * used to access the second child node. + * This is what should be done inside the loop. + */ + mds_kbdc_tree_t *inner; + + /* It is important that `.inner` is first because + * it is first in `struct mds_kbdc_tree_nesting` + * too which means that `.inner` has to same + * offset everyever (except in `mds_kbdc_tree_if_t`). + */ + + /** + * The first value to variable should take, inclusive + */ + char *first; + + /** + * The last value the variable should take, inclusive + */ + char *last; + + /** + * The variable + */ + char *variable; + + MDS_KBDC_TREE_PADDING(4); } mds_kbdc_tree_for_t; /** * Tree structure for a "if"-statement */ -typedef struct mds_kbdc_tree_if -{ - MDS_KBDC_TREE_COMMON; - - /** - * The condition - */ - char* condition; - - /** - * This is what should be done inside - * if the condition is satisfied - */ - mds_kbdc_tree_t* inner; - - /** - * This is what should be done inside - * if the condition is not satisfied - */ - mds_kbdc_tree_t* otherwise; - - MDS_KBDC_TREE_PADDING(3); - +typedef struct mds_kbdc_tree_if { + MDS_KBDC_TREE_COMMON; + + /** + * The condition + */ + char *condition; + + /** + * This is what should be done inside + * if the condition is satisfied + */ + mds_kbdc_tree_t *inner; + + /** + * This is what should be done inside + * if the condition is not satisfied + */ + mds_kbdc_tree_t *otherwise; + + MDS_KBDC_TREE_PADDING(3); } mds_kbdc_tree_if_t; @@ -494,22 +479,20 @@ typedef struct mds_kbdc_tree_if * Tree structure for assigning a value to a variable, * possibly declaring the variable in the process */ -typedef struct mds_kbdc_tree_let -{ - MDS_KBDC_TREE_COMMON; - - /** - * The variable - */ - char* variable; - - /** - * The value to assign to the variable - */ - mds_kbdc_tree_t* value; - - MDS_KBDC_TREE_PADDING(2); - +typedef struct mds_kbdc_tree_let { + MDS_KBDC_TREE_COMMON; + + /** + * The variable + */ + char *variable; + + /** + * The value to assign to the variable + */ + mds_kbdc_tree_t *value; + + MDS_KBDC_TREE_PADDING(2); } mds_kbdc_tree_let_t; @@ -522,127 +505,115 @@ typedef struct mds_kbdc_tree_let * in such case `sequence` should not be `NULL` but * `sequence.next` and `result` should be `NULL` */ -typedef struct mds_kbdc_tree_map -{ - MDS_KBDC_TREE_COMMON; - - /** - * The input sequence - */ - mds_kbdc_tree_t* sequence; - - /** - * The output sequence - */ - mds_kbdc_tree_t* result; - - /* - * These are ordered so that `mds_kbdc_tree_t.macro_call.arguments` - * and `mds_kbdc_tree_t.map.sequence` have the same address. - */ - - MDS_KBDC_TREE_PADDING(2); - +typedef struct mds_kbdc_tree_map { + MDS_KBDC_TREE_COMMON; + + /** + * The input sequence + */ + mds_kbdc_tree_t *sequence; + + /** + * The output sequence + */ + mds_kbdc_tree_t *result; + + /* + * These are ordered so that `mds_kbdc_tree_t.macro_call.arguments` + * and `mds_kbdc_tree_t.map.sequence` have the same address. + */ + + MDS_KBDC_TREE_PADDING(2); } mds_kbdc_tree_map_t; /** * Tree structure for an array of values */ -typedef struct mds_kbdc_tree_array -{ - MDS_KBDC_TREE_COMMON; - - /** - * The first value, `.elements.next` - * is used to access the second value. - */ - mds_kbdc_tree_t* elements; - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_array { + MDS_KBDC_TREE_COMMON; + + /** + * The first value, `.elements.next` + * is used to access the second value. + */ + mds_kbdc_tree_t *elements; + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_array_t; /** * Leaf structure for a key-combination */ -typedef struct mds_kbdc_tree_keys -{ - MDS_KBDC_TREE_COMMON; - - /** - * The key-combination - */ - char* keys; - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_keys { + MDS_KBDC_TREE_COMMON; + + /** + * The key-combination + */ + char *keys; + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_keys_t; /** * Leaf structure for a string */ -typedef struct mds_kbdc_tree_string -{ - MDS_KBDC_TREE_COMMON; - - /** - * The string - */ - char* string; - - /* - * `evaluate_element` in "compile-layout.c" utilises - * that `mds_kbdc_tree_string.string` has the same - * offset as `mds_kbdc_tree_keys.keys`. - */ - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_string { + MDS_KBDC_TREE_COMMON; + + /** + * The string + */ + char *string; + + /* + * `evaluate_element` in "compile-layout.c" utilises + * that `mds_kbdc_tree_string.string` has the same + * offset as `mds_kbdc_tree_keys.keys`. + */ + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_string_t; /** * Leaf structure for a compiled key-combination */ -typedef struct mds_kbdc_tree_compiled_keys -{ - MDS_KBDC_TREE_COMMON; - - /** - * The key-combination - * - * Strictly terminated by -1 - */ - char32_t* keys; - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_compiled_keys { + MDS_KBDC_TREE_COMMON; + + /** + * The key-combination + * + * Strictly terminated by -1 + */ + char32_t *keys; + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_compiled_keys_t; /** * Leaf structure for a compiled string */ -typedef struct mds_kbdc_tree_compiled_string -{ - MDS_KBDC_TREE_COMMON; - - /** - * The string - */ - char32_t* string; - - /* - * `evaluate_element` in "compile-layout.c" utilises - * that `mds_kbdc_tree_string.compiled_string` has the - * same offset as `mds_kbdc_tree_keys.compiled_keys`. - */ - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_compiled_string { + MDS_KBDC_TREE_COMMON; + + /** + * The string + */ + char32_t *string; + + /* + * `evaluate_element` in "compile-layout.c" utilises + * that `mds_kbdc_tree_string.compiled_string` has the + * same offset as `mds_kbdc_tree_keys.compiled_keys`. + */ + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_compiled_string_t; @@ -652,11 +623,9 @@ typedef struct mds_kbdc_tree_compiled_string * Other leaf structures without any content may `typedef` * this structure */ -typedef struct mds_kbdc_tree_nothing -{ - MDS_KBDC_TREE_COMMON; - MDS_KBDC_TREE_PADDING(0); - +typedef struct mds_kbdc_tree_nothing { + MDS_KBDC_TREE_COMMON; + MDS_KBDC_TREE_PADDING(0); } mds_kbdc_tree_nothing_t; @@ -682,29 +651,27 @@ typedef struct mds_kbdc_tree_nesting mds_kbdc_tree_ordered_t; /** * Tree structure for a macro call */ -typedef struct mds_kbdc_tree_macro_call -{ - MDS_KBDC_TREE_COMMON; - - /** - * The first input argument for the - * macro call, the second is accessed - * using `.arguments.next` - */ - mds_kbdc_tree_t* arguments; - - /** - * The name of the macro - */ - char* name; - - /* - * These are ordered so that `mds_kbdc_tree_t.macro_call.arguments` - * and `mds_kbdc_tree_t.map.sequence` have the same address. - */ - - MDS_KBDC_TREE_PADDING(2); - +typedef struct mds_kbdc_tree_macro_call { + MDS_KBDC_TREE_COMMON; + + /** + * The first input argument for the + * macro call, the second is accessed + * using `.arguments.next` + */ + mds_kbdc_tree_t *arguments; + + /** + * The name of the macro + */ + char *name; + + /* + * These are ordered so that `mds_kbdc_tree_t.macro_call.arguments` + * and `mds_kbdc_tree_t.map.sequence` have the same address. + */ + + MDS_KBDC_TREE_PADDING(2); } mds_kbdc_tree_macro_call_t; @@ -728,45 +695,47 @@ typedef struct mds_kbdc_tree_nothing mds_kbdc_tree_continue_t; /** * Keyboard layout syntax tree */ -union mds_kbdc_tree -{ +union mds_kbdc_tree { +#if defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpedantic" /* unnamed struct */ - struct - { - MDS_KBDC_TREE_COMMON; - MDS_KBDC_TREE_PADDING(0); - }; +#endif + struct { + MDS_KBDC_TREE_COMMON; + MDS_KBDC_TREE_PADDING(0); + }; +#if defined(__GNUC__) # pragma GCC diagnostic pop - - mds_kbdc_tree_information_t information; - mds_kbdc_tree_information_language_t language; - mds_kbdc_tree_information_country_t country; - mds_kbdc_tree_information_variant_t variant; - mds_kbdc_tree_include_t include; - mds_kbdc_tree_function_t function; - mds_kbdc_tree_macro_t macro; - mds_kbdc_tree_assumption_t assumption; - mds_kbdc_tree_assumption_have_t have; - mds_kbdc_tree_assumption_have_chars_t have_chars; - mds_kbdc_tree_assumption_have_range_t have_range; - mds_kbdc_tree_for_t for_; - mds_kbdc_tree_if_t if_; - mds_kbdc_tree_let_t let; - mds_kbdc_tree_map_t map; - mds_kbdc_tree_array_t array; - mds_kbdc_tree_keys_t keys; - mds_kbdc_tree_string_t string; - mds_kbdc_tree_compiled_keys_t compiled_keys; - mds_kbdc_tree_compiled_string_t compiled_string; - mds_kbdc_tree_nothing_t nothing; - mds_kbdc_tree_alternation_t alternation; - mds_kbdc_tree_unordered_t unordered; - mds_kbdc_tree_ordered_t ordered; - mds_kbdc_tree_macro_call_t macro_call; - mds_kbdc_tree_return_t return_; - mds_kbdc_tree_break_t break_; - mds_kbdc_tree_continue_t continue_; +#endif + + mds_kbdc_tree_information_t information; + mds_kbdc_tree_information_language_t language; + mds_kbdc_tree_information_country_t country; + mds_kbdc_tree_information_variant_t variant; + mds_kbdc_tree_include_t include; + mds_kbdc_tree_function_t function; + mds_kbdc_tree_macro_t macro; + mds_kbdc_tree_assumption_t assumption; + mds_kbdc_tree_assumption_have_t have; + mds_kbdc_tree_assumption_have_chars_t have_chars; + mds_kbdc_tree_assumption_have_range_t have_range; + mds_kbdc_tree_for_t for_; + mds_kbdc_tree_if_t if_; + mds_kbdc_tree_let_t let; + mds_kbdc_tree_map_t map; + mds_kbdc_tree_array_t array; + mds_kbdc_tree_keys_t keys; + mds_kbdc_tree_string_t string; + mds_kbdc_tree_compiled_keys_t compiled_keys; + mds_kbdc_tree_compiled_string_t compiled_string; + mds_kbdc_tree_nothing_t nothing; + mds_kbdc_tree_alternation_t alternation; + mds_kbdc_tree_unordered_t unordered; + mds_kbdc_tree_ordered_t ordered; + mds_kbdc_tree_macro_call_t macro_call; + mds_kbdc_tree_return_t return_; + mds_kbdc_tree_break_t break_; + mds_kbdc_tree_continue_t continue_; }; @@ -777,7 +746,7 @@ union mds_kbdc_tree * @param this The memory slot for the tree node * @param type The type of the node */ -void mds_kbdc_tree_initialise(mds_kbdc_tree_t* restrict this, int type); +void mds_kbdc_tree_initialise(mds_kbdc_tree_t *restrict this, int type); /** * Create a tree node @@ -785,7 +754,7 @@ void mds_kbdc_tree_initialise(mds_kbdc_tree_t* restrict this, int type); * @param type The type of the node * @return The tree node, `NULL` on error */ -mds_kbdc_tree_t* mds_kbdc_tree_create(int type); +mds_kbdc_tree_t *mds_kbdc_tree_create(int type); /** * Release all resources stored in a tree node, @@ -794,7 +763,7 @@ mds_kbdc_tree_t* mds_kbdc_tree_create(int type); * * @param this The tree node */ -void mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t* restrict this); +void mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t *restrict this); /** * Release all resources stored in a tree node, @@ -804,7 +773,7 @@ void mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t* restrict this); * * @param this The tree node */ -void mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t* restrict this); +void mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t *restrict this); /** * Release all resources stored in a tree node @@ -813,7 +782,7 @@ void mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t* restrict this); * * @param this The tree node */ -void mds_kbdc_tree_destroy(mds_kbdc_tree_t* restrict this); +void mds_kbdc_tree_destroy(mds_kbdc_tree_t *restrict this); /** * Release all resources stored in a tree node @@ -822,7 +791,7 @@ void mds_kbdc_tree_destroy(mds_kbdc_tree_t* restrict this); * * @param this The tree node */ -void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this); +void mds_kbdc_tree_free(mds_kbdc_tree_t *restrict this); /** @@ -832,7 +801,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this); * @param this The tree node * @return A duplicate of `this`, `NULL` on error */ -mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this); +mds_kbdc_tree_t *mds_kbdc_tree_dup(const mds_kbdc_tree_t *restrict this); /** @@ -841,7 +810,7 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this); * @param this The tree node * @param output The output file */ -void mds_kbdc_tree_print(const mds_kbdc_tree_t* restrict this, FILE* output); +void mds_kbdc_tree_print(const mds_kbdc_tree_t *restrict this, FILE *output); @@ -850,4 +819,3 @@ void mds_kbdc_tree_print(const mds_kbdc_tree_t* restrict this, FILE* output); #undef MDS_KBDC_TREE_COMMON #endif - diff --git a/src/mds-kbdc/validate-tree.c b/src/mds-kbdc/validate-tree.c index 632b9a8..80ef7d5 100644 --- a/src/mds-kbdc/validate-tree.c +++ b/src/mds-kbdc/validate-tree.c @@ -28,12 +28,12 @@ /** * Tree type constant shortener */ -#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE +#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE /** * Check the value of `innermost_visit` */ -#define VISITING(TYPE) (innermost_visit == MDS_KBDC_TREE_TYPE_##TYPE) +#define VISITING(TYPE) (innermost_visit == MDS_KBDC_TREE_TYPE_##TYPE) /** * Add an error with “included from here”-notes to the error list @@ -44,20 +44,20 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(NODE, PTR, SEVERITY, ...) \ - NEW_ERROR_WITH_INCLUDES(NODE, PTR, SEVERITY, __VA_ARGS__) +#define NEW_ERROR(NODE, PTR, SEVERITY, ...)\ + NEW_ERROR_WITH_INCLUDES(NODE, PTR, SEVERITY, __VA_ARGS__) /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The parameter of `validate_tree` */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; /** * The number visited for-statements @@ -67,22 +67,22 @@ static size_t fors = 0; /** * The function definition that is currently being visited */ -static mds_kbdc_tree_function_t* function = NULL; +static mds_kbdc_tree_function_t *function = NULL; /** * The macro definition that is currently being visited */ -static mds_kbdc_tree_macro_t* macro = NULL; +static mds_kbdc_tree_macro_t *macro = NULL; /** * The information clause that is currently being visited */ -static mds_kbdc_tree_information_t* information = NULL; +static mds_kbdc_tree_information_t *information = NULL; /** * The assumption clause that is currently being visited */ -static mds_kbdc_tree_assumption_t* assumption = NULL; +static mds_kbdc_tree_assumption_t *assumption = NULL; /** * The value `includes_ptr` had when `function`, @@ -105,7 +105,7 @@ static int innermost_visit = -1; * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_subtree(mds_kbdc_tree_t* restrict tree); +static int validate_subtree(mds_kbdc_tree_t *restrict tree); @@ -115,17 +115,18 @@ static int validate_subtree(mds_kbdc_tree_t* restrict tree); * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_include(mds_kbdc_tree_include_t* restrict tree) +static int +validate_include(mds_kbdc_tree_include_t *restrict tree) { - void* data; - int r; - fail_if (mds_kbdc_include_stack_push(tree, &data)); - r = validate_subtree(tree->inner); - mds_kbdc_include_stack_pop(data); - fail_if (r); - return 0; - fail: - return -1; + void *data; + int r; + fail_if (mds_kbdc_include_stack_push(tree, &data)); + r = validate_subtree(tree->inner); + mds_kbdc_include_stack_pop(data); + fail_if (r); + return 0; +fail: + return -1; } @@ -135,34 +136,30 @@ static int validate_include(mds_kbdc_tree_include_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_function(mds_kbdc_tree_function_t* restrict tree) +static int +validate_function(mds_kbdc_tree_function_t *restrict tree) { - int r; - if (VISITING(FUNCTION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "nested function definition"); - NEW_ERROR(function, def_includes_ptr, NOTE, "outer function defined here"); - return 0; - } - else if (VISITING(MACRO)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "function definition inside macro definition"); - NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); - return 0; - } - else if (VISITING(INFORMATION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "function definition inside information clause"); - NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); - return 0; - } - innermost_visit = tree->type; - function = tree; - def_includes_ptr = includes_ptr; - r = validate_subtree(tree->inner); - return function = NULL, r; - fail: - return -1; + int r; + if (VISITING(FUNCTION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "nested function definition"); + NEW_ERROR(function, def_includes_ptr, NOTE, "outer function defined here"); + return 0; + } else if (VISITING(MACRO)) { + NEW_ERROR(tree, includes_ptr, ERROR, "function definition inside macro definition"); + NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); + return 0; + } else if (VISITING(INFORMATION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "function definition inside information clause"); + NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); + return 0; + } + innermost_visit = tree->type; + function = tree; + def_includes_ptr = includes_ptr; + r = validate_subtree(tree->inner); + return function = NULL, r; +fail: + return -1; } @@ -172,34 +169,30 @@ static int validate_function(mds_kbdc_tree_function_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_macro(mds_kbdc_tree_macro_t* restrict tree) +static int +validate_macro(mds_kbdc_tree_macro_t *restrict tree) { - int r; - if (VISITING(FUNCTION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "macro definition inside function definition"); - NEW_ERROR(function, def_includes_ptr, NOTE, "outer function definition defined here"); - return 0; - } - else if (VISITING(MACRO)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "nested macro definition"); - NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); - return 0; - } - else if (VISITING(INFORMATION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "macro definition inside information clause"); - NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); - return 0; - } - innermost_visit = tree->type; - macro = tree; - def_includes_ptr = includes_ptr; - r = validate_subtree(tree->inner); - return macro = NULL, r; - fail: - return -1; + int r; + if (VISITING(FUNCTION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "macro definition inside function definition"); + NEW_ERROR(function, def_includes_ptr, NOTE, "outer function definition defined here"); + return 0; + } else if (VISITING(MACRO)) { + NEW_ERROR(tree, includes_ptr, ERROR, "nested macro definition"); + NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); + return 0; + } else if (VISITING(INFORMATION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "macro definition inside information clause"); + NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); + return 0; + } + innermost_visit = tree->type; + macro = tree; + def_includes_ptr = includes_ptr; + r = validate_subtree(tree->inner); + return macro = NULL, r; +fail: + return -1; } @@ -209,40 +202,34 @@ static int validate_macro(mds_kbdc_tree_macro_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_information(mds_kbdc_tree_information_t* restrict tree) +static int +validate_information(mds_kbdc_tree_information_t *restrict tree) { - int r; - if (VISITING(FUNCTION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "information clause inside function definition"); - NEW_ERROR(function, def_includes_ptr, NOTE, "outer function definition defined here"); - return 0; - } - else if (VISITING(MACRO)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "information clause inside macro definition"); - NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); - return 0; - } - else if (VISITING(INFORMATION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "nested information clause"); - NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); - return 0; - } - else if (VISITING(ASSUMPTION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "information clause inside assumption clause"); - NEW_ERROR(assumption, def_includes_ptr, NOTE, "outer assumption clause defined here"); - return 0; - } - innermost_visit = tree->type; - information = tree; - def_includes_ptr = includes_ptr; - r = validate_subtree(tree->inner); - return information = NULL, r; - fail: - return -1; + int r; + if (VISITING(FUNCTION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "information clause inside function definition"); + NEW_ERROR(function, def_includes_ptr, NOTE, "outer function definition defined here"); + return 0; + } else if (VISITING(MACRO)) { + NEW_ERROR(tree, includes_ptr, ERROR, "information clause inside macro definition"); + NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); + return 0; + } else if (VISITING(INFORMATION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "nested information clause"); + NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); + return 0; + } else if (VISITING(ASSUMPTION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "information clause inside assumption clause"); + NEW_ERROR(assumption, def_includes_ptr, NOTE, "outer assumption clause defined here"); + return 0; + } + innermost_visit = tree->type; + information = tree; + def_includes_ptr = includes_ptr; + r = validate_subtree(tree->inner); + return information = NULL, r; +fail: + return -1; } @@ -252,40 +239,34 @@ static int validate_information(mds_kbdc_tree_information_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_assumption(mds_kbdc_tree_assumption_t* restrict tree) +static int +validate_assumption(mds_kbdc_tree_assumption_t *restrict tree) { - int r; - if (VISITING(FUNCTION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "assumption clause inside function definition"); - NEW_ERROR(function, def_includes_ptr, NOTE, "outer function definition defined here"); - return 0; - } - else if (VISITING(MACRO)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "assumption clause inside macro definition"); - NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); - return 0; - } - else if (VISITING(INFORMATION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "assumption clause inside information clause"); - NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); - return 0; - } - else if (VISITING(ASSUMPTION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "nested assumption clause"); - NEW_ERROR(assumption, def_includes_ptr, NOTE, "outer assumption clause defined here"); - return 0; - } - innermost_visit = tree->type; - assumption = tree; - def_includes_ptr = includes_ptr; - r = validate_subtree(tree->inner); - return assumption = NULL, r; - fail: - return -1; + int r; + if (VISITING(FUNCTION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "assumption clause inside function definition"); + NEW_ERROR(function, def_includes_ptr, NOTE, "outer function definition defined here"); + return 0; + } else if (VISITING(MACRO)) { + NEW_ERROR(tree, includes_ptr, ERROR, "assumption clause inside macro definition"); + NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); + return 0; + } else if (VISITING(INFORMATION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "assumption clause inside information clause"); + NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); + return 0; + } else if (VISITING(ASSUMPTION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "nested assumption clause"); + NEW_ERROR(assumption, def_includes_ptr, NOTE, "outer assumption clause defined here"); + return 0; + } + innermost_visit = tree->type; + assumption = tree; + def_includes_ptr = includes_ptr; + r = validate_subtree(tree->inner); + return assumption = NULL, r; +fail: + return -1; } @@ -295,25 +276,26 @@ static int validate_assumption(mds_kbdc_tree_assumption_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_map(mds_kbdc_tree_map_t* restrict tree) +static int +validate_map(mds_kbdc_tree_map_t *restrict tree) { - int is_value = tree->result == NULL; - if (is_value); - /* We do not want value-statments outside function - * definitions, however, we do want \set/3 to be usable, - * from anywhere, even indirectly, therefore we cannot, - * at this process level, determine whether a - * value-statement is used correctly or not. - */ - else if (VISITING(INFORMATION)) - NEW_ERROR(tree, includes_ptr, ERROR, "mapping-statement inside information clause"); - else if (VISITING(ASSUMPTION)) - NEW_ERROR(tree, includes_ptr, ERROR, "mapping-statement inside assumption clause"); - else if (VISITING(FUNCTION)) - NEW_ERROR(tree, includes_ptr, ERROR, "mapping-statement inside function definition"); - return 0; + int is_value = tree->result == NULL; + if (is_value) + /* We do not want value-statments outside function + * definitions, however, we do want \set/3 to be usable, + * from anywhere, even indirectly, therefore we cannot, + * at this process level, determine whether a + * value-statement is used correctly or not. + */; + else if (VISITING(INFORMATION)) + NEW_ERROR(tree, includes_ptr, ERROR, "mapping-statement inside information clause"); + else if (VISITING(ASSUMPTION)) + NEW_ERROR(tree, includes_ptr, ERROR, "mapping-statement inside assumption clause"); + else if (VISITING(FUNCTION)) + NEW_ERROR(tree, includes_ptr, ERROR, "mapping-statement inside function definition"); + return 0; fail: - return -1; + return -1; } @@ -323,17 +305,18 @@ static int validate_map(mds_kbdc_tree_map_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) +static int +validate_macro_call(mds_kbdc_tree_macro_call_t *restrict tree) { - if (VISITING(INFORMATION)) - NEW_ERROR(tree, includes_ptr, ERROR, "macro call inside information clause"); - else if (VISITING(ASSUMPTION)) - NEW_ERROR(tree, includes_ptr, ERROR, "macro call inside assumption clause"); - else if (VISITING(FUNCTION)) - NEW_ERROR(tree, includes_ptr, ERROR, "macro call inside function definition"); - return 0; - fail: - return -1; + if (VISITING(INFORMATION)) + NEW_ERROR(tree, includes_ptr, ERROR, "macro call inside information clause"); + else if (VISITING(ASSUMPTION)) + NEW_ERROR(tree, includes_ptr, ERROR, "macro call inside assumption clause"); + else if (VISITING(FUNCTION)) + NEW_ERROR(tree, includes_ptr, ERROR, "macro call inside function definition"); + return 0; +fail: + return -1; } @@ -343,14 +326,15 @@ static int validate_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_for(mds_kbdc_tree_for_t* restrict tree) +static int +validate_for(mds_kbdc_tree_for_t *restrict tree) { - int r; - fors++, r = validate_subtree(tree->inner), fors--; - fail_if (r); - return 0; - fail: - return -1; + int r; + fors++, r = validate_subtree(tree->inner), fors--; + fail_if (r); + return 0; +fail: + return -1; } @@ -360,12 +344,13 @@ static int validate_for(mds_kbdc_tree_for_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_if(mds_kbdc_tree_if_t* restrict tree) +static int +validate_if(mds_kbdc_tree_if_t *restrict tree) { - fail_if ((validate_subtree(tree->inner) || validate_subtree(tree->otherwise))); - return 0; - fail: - return -1; + fail_if ((validate_subtree(tree->inner) || validate_subtree(tree->otherwise))); + return 0; +fail: + return -1; } @@ -375,13 +360,14 @@ static int validate_if(mds_kbdc_tree_if_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_return(mds_kbdc_tree_return_t* restrict tree) +static int +validate_return(mds_kbdc_tree_return_t *restrict tree) { - if ((function == NULL) && (macro == NULL)) - NEW_ERROR(tree, includes_ptr, ERROR, "‘return’ outside function and macro definition"); - return 0; - fail: - return -1; + if (!function && !macro) + NEW_ERROR(tree, includes_ptr, ERROR, "‘return’ outside function and macro definition"); + return 0; +fail: + return -1; } @@ -391,13 +377,14 @@ static int validate_return(mds_kbdc_tree_return_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_break(mds_kbdc_tree_break_t* restrict tree) +static int +validate_break(mds_kbdc_tree_break_t *restrict tree) { - if (fors == 0) - NEW_ERROR(tree, includes_ptr, ERROR, "‘break’ outside ‘for’"); - return 0; - fail: - return -1; + if (!fors) + NEW_ERROR(tree, includes_ptr, ERROR, "‘break’ outside ‘for’"); + return 0; +fail: + return -1; } @@ -407,13 +394,14 @@ static int validate_break(mds_kbdc_tree_break_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_continue(mds_kbdc_tree_continue_t* restrict tree) +static int +validate_continue(mds_kbdc_tree_continue_t *restrict tree) { - if (fors == 0) - NEW_ERROR(tree, includes_ptr, ERROR, "‘continue’ outside ‘for’"); - return 0; - fail: - return -1; + if (!fors) + NEW_ERROR(tree, includes_ptr, ERROR, "‘continue’ outside ‘for’"); + return 0; +fail: + return -1; } @@ -423,13 +411,14 @@ static int validate_continue(mds_kbdc_tree_continue_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_assumption_data(mds_kbdc_tree_t* restrict tree) +static int +validate_assumption_data(mds_kbdc_tree_t *restrict tree) { - if (assumption == NULL) - NEW_ERROR(tree, includes_ptr, ERROR, "assumption outside assumption clause"); - return 0; - fail: - return -1; + if (!assumption) + NEW_ERROR(tree, includes_ptr, ERROR, "assumption outside assumption clause"); + return 0; +fail: + return -1; } @@ -439,13 +428,14 @@ static int validate_assumption_data(mds_kbdc_tree_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_information_data(mds_kbdc_tree_t* restrict tree) +static int +validate_information_data(mds_kbdc_tree_t *restrict tree) { - if (information == NULL) - NEW_ERROR(tree, includes_ptr, ERROR, "information outside information clause"); - return 0; - fail: - return -1; + if (!information) + NEW_ERROR(tree, includes_ptr, ERROR, "information outside information clause"); + return 0; +fail: + return -1; } @@ -455,48 +445,48 @@ static int validate_information_data(mds_kbdc_tree_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_subtree(mds_kbdc_tree_t* restrict tree) +static int +validate_subtree(mds_kbdc_tree_t *restrict tree) { -#define v(type) fail_if (validate_##type(&(tree->type))) -#define V(type) fail_if (validate_##type(&(tree->type##_))) - int old_innermost_visit = innermost_visit; - again: - if (tree == NULL) - return 0; - - switch (tree->type) - { - case C(INFORMATION): v(information); break; - case C(INCLUDE): v(include); break; - case C(FUNCTION): v(function); break; - case C(MACRO): v(macro); break; - case C(ASSUMPTION): v(assumption); break; - case C(FOR): V(for); break; - case C(IF): V(if); break; - case C(MAP): v(map); break; - case C(MACRO_CALL): v(macro_call); break; - case C(RETURN): V(return); break; - case C(BREAK): V(break); break; - case C(CONTINUE): V(continue); break; - case C(INFORMATION_LANGUAGE): - case C(INFORMATION_COUNTRY): - case C(INFORMATION_VARIANT): - fail_if (validate_information_data(tree)); - break; - case C(ASSUMPTION_HAVE): - case C(ASSUMPTION_HAVE_CHARS): - case C(ASSUMPTION_HAVE_RANGE): - fail_if (validate_assumption_data(tree)); - break; - default: - break; - } - - innermost_visit = old_innermost_visit; - tree = tree->next; - goto again; - fail: - return innermost_visit = old_innermost_visit, -1; +#define v(type) fail_if (validate_##type(&(tree->type))) +#define V(type) fail_if (validate_##type(&(tree->type##_))) + int old_innermost_visit = innermost_visit; +again: + if (!tree) + return 0; + + switch (tree->type) { + case C(INFORMATION): v(information); break; + case C(INCLUDE): v(include); break; + case C(FUNCTION): v(function); break; + case C(MACRO): v(macro); break; + case C(ASSUMPTION): v(assumption); break; + case C(FOR): V(for); break; + case C(IF): V(if); break; + case C(MAP): v(map); break; + case C(MACRO_CALL): v(macro_call); break; + case C(RETURN): V(return); break; + case C(BREAK): V(break); break; + case C(CONTINUE): V(continue); break; + case C(INFORMATION_LANGUAGE): + case C(INFORMATION_COUNTRY): + case C(INFORMATION_VARIANT): + fail_if (validate_information_data(tree)); + break; + case C(ASSUMPTION_HAVE): + case C(ASSUMPTION_HAVE_CHARS): + case C(ASSUMPTION_HAVE_RANGE): + fail_if (validate_assumption_data(tree)); + break; + default: + break; + } + + innermost_visit = old_innermost_visit; + tree = tree->next; + goto again; +fail: + return innermost_visit = old_innermost_visit, -1; #undef V #undef v } @@ -508,17 +498,18 @@ static int validate_subtree(mds_kbdc_tree_t* restrict tree) * @param result_ `result` from `process_includes`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int validate_tree(mds_kbdc_parsed_t* restrict result_) +int +validate_tree(mds_kbdc_parsed_t *restrict result_) { - int r; - mds_kbdc_include_stack_begin(result = result_); - r = validate_subtree(result_->tree); - fors = 0; - mds_kbdc_include_stack_end(); - fail_if (r); - return 0; - fail: - return -1; + int r; + mds_kbdc_include_stack_begin(result = result_); + r = validate_subtree(result_->tree); + fors = 0; + mds_kbdc_include_stack_end(); + fail_if (r); + return 0; +fail: + return -1; } @@ -526,4 +517,3 @@ int validate_tree(mds_kbdc_parsed_t* restrict result_) #undef NEW_ERROR #undef VISITING #undef C - diff --git a/src/mds-kbdc/validate-tree.h b/src/mds-kbdc/validate-tree.h index e32b2f2..5ca9277 100644 --- a/src/mds-kbdc/validate-tree.h +++ b/src/mds-kbdc/validate-tree.h @@ -28,8 +28,7 @@ * @param result `result` from `process_includes`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int validate_tree(mds_kbdc_parsed_t* restrict result); +int validate_tree(mds_kbdc_parsed_t *restrict result); #endif - diff --git a/src/mds-kbdc/variables.c b/src/mds-kbdc/variables.c index 3b2e128..15a1cb6 100644 --- a/src/mds-kbdc/variables.c +++ b/src/mds-kbdc/variables.c @@ -27,32 +27,30 @@ /** * The state of a variable */ -typedef struct variable -{ - /** - * The current value of the variable - */ - mds_kbdc_tree_t* value; - - /** - * The previous version of variable, - * before it was shadowed - */ - struct variable* restrict previous; - - /** - * The original scope in which the current - * shadow of the variable was created - */ - size_t scope; - - /** - * The latest scope the in which the - * variable has been used in a for-loop, - * `~0' if never, or below `scope` - */ - size_t used_in_for; - +typedef struct variable { + /** + * The current value of the variable + */ + mds_kbdc_tree_t *value; + + /** + * The previous version of variable, + * before it was shadowed + */ + struct variable *restrict previous; + + /** + * The original scope in which the current + * shadow of the variable was created + */ + size_t scope; + + /** + * The latest scope the in which the + * variable has been used in a for-loop, + * `~0' if never, or below `scope` + */ + size_t used_in_for; } variable_t; @@ -60,7 +58,7 @@ typedef struct variable /** * Map (by index) of defined variables */ -static variable_t** restrict variables = NULL; +static variable_t **restrict variables = NULL; /** * The size of `variables` @@ -79,20 +77,21 @@ static size_t current_scope = 0; /** * Destroy the variable storage */ -void variables_terminate(void) +void +variables_terminate(void) { - size_t i; - variable_t* old; - for (i = 0; i < variable_count; i++) - while (variables[i]) - { - old = variables[i]; - variables[i] = variables[i]->previous; - mds_kbdc_tree_free(old->value); - free(old); - } - free(variables), variables = NULL; - variable_count = current_scope = 0; + size_t i; + variable_t *old; + for (i = 0; i < variable_count; i++) { + while (variables[i]) { + old = variables[i]; + variables[i] = variables[i]->previous; + mds_kbdc_tree_free(old->value); + free(old); + } + } + free(variables), variables = NULL; + variable_count = current_scope = 0; } @@ -100,9 +99,10 @@ void variables_terminate(void) * Push the variable-stack, making it * possible to shadow all variables */ -void variables_stack_push(void) +void +variables_stack_push(void) { - current_scope++; + current_scope++; } @@ -112,19 +112,20 @@ void variables_stack_push(void) * since it was last called (without a * corresponding call to this function) */ -void variables_stack_pop(void) +void +variables_stack_pop(void) { - size_t i; - variable_t* old; - for (i = 0; i < variable_count; i++) - if (variables[i] && (variables[i]->scope == current_scope)) - { - old = variables[i]; - variables[i] = variables[i]->previous; - mds_kbdc_tree_free(old->value); - free(old); - } - current_scope--; + size_t i; + variable_t *old; + for (i = 0; i < variable_count; i++) { + if (variables[i] && variables[i]->scope == current_scope) { + old = variables[i]; + variables[i] = variables[i]->previous; + mds_kbdc_tree_free(old->value); + free(old); + } + } + current_scope--; } @@ -135,11 +136,12 @@ void variables_stack_pop(void) * @param variable The variable index * @return Whether a let will override the variable */ -int variables_let_will_override(size_t variable) +int +variables_let_will_override(size_t variable) { - if (variable >= variable_count) return 0; - if (variables[variable] == NULL) return 0; - return variables[variable]->scope == current_scope; + if (variable >= variable_count) return 0; + if (!variables[variable]) return 0; + return variables[variable]->scope == current_scope; } @@ -150,42 +152,39 @@ int variables_let_will_override(size_t variable) * @param value The variable's new value * @return Zero on success, -1 on error */ -int variables_let(size_t variable, mds_kbdc_tree_t* restrict value) +int +variables_let(size_t variable, mds_kbdc_tree_t *restrict value) { - variable_t** new; - variable_t* previous; - - /* Grow the table if necessary to fit the variable. */ - if (variable >= variable_count) - { - new = variables; - fail_if (xrealloc(new, variable + 1, variable_t*)); - variables = new; - memset(variables + variable_count, 0, (variable + 1 - variable_count) * sizeof(variable_t*)); - variable_count = variable + 1; - } + variable_t **new; + variable_t *previous; + + /* Grow the table if necessary to fit the variable. */ + if (variable >= variable_count) { + new = variables; + fail_if (xrealloc(new, variable + 1, variable_t*)); + variables = new; + memset(variables + variable_count, 0, (variable + 1 - variable_count) * sizeof(variable_t*)); + variable_count = variable + 1; + } + + if (variables_let_will_override(variable)) { + /* Override. */ + mds_kbdc_tree_free(variables[variable]->value); + variables[variable]->value = value; + } else { + /* Shadow or define. */ + previous = variables[variable]; + if (xmalloc(variables[variable], 1, variable_t)) + fail_if (variables[variable] = previous, 1); + variables[variable]->value = value; + variables[variable]->previous = previous; + variables[variable]->scope = current_scope; + variables[variable]->used_in_for = (size_t)(~0LL); + } - if (variables_let_will_override(variable)) - { - /* Override. */ - mds_kbdc_tree_free(variables[variable]->value); - variables[variable]->value = value; - } - else - { - /* Shadow or define. */ - previous = variables[variable]; - if (xmalloc(variables[variable], 1, variable_t)) - fail_if (variables[variable] = previous, 1); - variables[variable]->value = value; - variables[variable]->previous = previous; - variables[variable]->scope = current_scope; - variables[variable]->used_in_for = (size_t)(~0LL); - } - - return 0; - fail: - return -1; + return 0; +fail: + return -1; } @@ -198,11 +197,12 @@ int variables_let(size_t variable, mds_kbdc_tree_t* restrict value) * @param variable The variable index * @return The variable's value, `NULL` if not defined */ -mds_kbdc_tree_t* variables_get(size_t variable) +mds_kbdc_tree_t * +variables_get(size_t variable) { - if (variable >= variable_count) return NULL; - if (variables[variable] == NULL) return NULL; - return variables[variable]->value; + if (variable >= variable_count) return NULL; + if (!variables[variable]) return NULL; + return variables[variable]->value; } @@ -212,31 +212,32 @@ mds_kbdc_tree_t* variables_get(size_t variable) * @param variable The variable index, must already be defined * @return Zero on success, -1 on error */ -int variables_was_used_in_for(size_t variable) +int +variables_was_used_in_for(size_t variable) { - variable_t* previous; - - /* Already marked. */ - if (variables[variable]->used_in_for == current_scope) - return 0; - - /* Not marked. */ - if (variables[variable]->used_in_for == (size_t)(~0LL)) - return variables[variable]->used_in_for = current_scope, 0; - - /* Marked for another scope. */ - previous = variables[variable]; - if (xmalloc(variables[variable], 1, variable_t)) - fail_if (variables[variable] = previous, 1); - variables[variable]->value = mds_kbdc_tree_dup(previous->value); - fail_if (variables[variable]->value == NULL); - variables[variable]->previous = previous; - variables[variable]->scope = current_scope; - variables[variable]->used_in_for = current_scope; - - return 0; - fail: - return -1; + variable_t *previous; + + /* Already marked. */ + if (variables[variable]->used_in_for == current_scope) + return 0; + + /* Not marked. */ + if (variables[variable]->used_in_for == (size_t)(~0LL)) + return variables[variable]->used_in_for = current_scope, 0; + + /* Marked for another scope. */ + previous = variables[variable]; + if (xmalloc(variables[variable], 1, variable_t)) + fail_if (variables[variable] = previous, 1); + variables[variable]->value = mds_kbdc_tree_dup(previous->value); + fail_if (variables[variable]->value == NULL); + variables[variable]->previous = previous; + variables[variable]->scope = current_scope; + variables[variable]->used_in_for = current_scope; + + return 0; +fail: + return -1; } @@ -246,8 +247,8 @@ int variables_was_used_in_for(size_t variable) * @param variable The variable index, must already be defined * @return Whether `variables_was_used_in_for` has been unused on the variable */ -int variables_has_been_used_in_for(size_t variable) +int +variables_has_been_used_in_for(size_t variable) { - return variables[variable]->used_in_for == current_scope; + return variables[variable]->used_in_for == current_scope; } - diff --git a/src/mds-kbdc/variables.h b/src/mds-kbdc/variables.h index 485961b..a175ab7 100644 --- a/src/mds-kbdc/variables.h +++ b/src/mds-kbdc/variables.h @@ -52,7 +52,8 @@ void variables_stack_pop(void); * @param variable The variable index * @return Whether a let will override the variable */ -int variables_let_will_override(size_t variable) __attribute__((pure)); +__attribute__((pure)) +int variables_let_will_override(size_t variable); /** * Assign a value to a variable, and define or shadow it in the process @@ -61,7 +62,7 @@ int variables_let_will_override(size_t variable) __attribute__((pure)); * @param value The variable's new value * @return Zero on success, -1 on error */ -int variables_let(size_t variable, mds_kbdc_tree_t* restrict value); +int variables_let(size_t variable, mds_kbdc_tree_t *restrict value); /** * Get the value currently assigned to a variable @@ -72,7 +73,8 @@ int variables_let(size_t variable, mds_kbdc_tree_t* restrict value); * @param variable The variable index * @return The variable's value, `NULL` if not defined */ -mds_kbdc_tree_t* variables_get(size_t variable) __attribute__((pure)); +__attribute__((pure)) +mds_kbdc_tree_t *variables_get(size_t variable); /** * Mark a variable as having been unsed in a for-loop in the current scope @@ -88,8 +90,8 @@ int variables_was_used_in_for(size_t variable); * @param variable The variable index, must already be defined * @return Whether `variables_was_used_in_for` has been unused on the variable */ -int variables_has_been_used_in_for(size_t variable) __attribute__((pure)); +__attribute__((pure)) +int variables_has_been_used_in_for(size_t variable); #endif - |