diff options
Diffstat (limited to 'src/mds-kbdc')
-rw-r--r-- | src/mds-kbdc/compile-layout.c | 81 | ||||
-rw-r--r-- | src/mds-kbdc/include-stack.c | 98 | ||||
-rw-r--r-- | src/mds-kbdc/include-stack.h | 46 |
3 files changed, 199 insertions, 26 deletions
diff --git a/src/mds-kbdc/compile-layout.c b/src/mds-kbdc/compile-layout.c index 62eb925..d6df226 100644 --- a/src/mds-kbdc/compile-layout.c +++ b/src/mds-kbdc/compile-layout.c @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "compile-layout.h" +/* TODO add call stack */ #include "include-stack.h" #include "string.h" @@ -40,13 +41,12 @@ * Add an error with “included from here”-notes to the error list * * @param NODE:const mds_kbdc_tree_t* The node the triggered the error - * @param PTR:size_t The number of “included from here”-notes * @param SEVERITY:identifier * in `MDS_KBDC_PARSE_ERROR_*` to indicate severity * @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, SEVERITY, ...) \ + NEW_ERROR_WITH_INCLUDES(NODE, includes_ptr, SEVERITY, __VA_ARGS__) /** * Beginning of failure clause @@ -150,12 +150,24 @@ static int pop_stack(void) return 0; /* TODO */ } +static int get_macro_lax(const char* restrict macro_name, + const mds_kbdc_tree_macro_t** restrict macro, + mds_kbdc_include_stack_t** restrict macro_include_stack) +{ + (void) macro_name; + (void) macro; + (void) macro_include_stack; + return 0; /* TODO */ +} + static int get_macro(const mds_kbdc_tree_macro_call_t* restrict macro_call, - const mds_kbdc_tree_macro_t** restrict macro) + const mds_kbdc_tree_macro_t** restrict macro, + mds_kbdc_include_stack_t** restrict macro_include_stack) { - NEW_ERROR(macro_call, includes_ptr, ERROR, "macro ‘%s’ as not been defined yet", macro_call->name); + NEW_ERROR(macro_call, ERROR, "macro ‘%s’ as not been defined yet", macro_call->name); /* return set `*macro = NULL` if `(*macro)->processed == PROCESS_LEVEL` */ (void) macro; + (void) macro_include_stack; return 0; /* TODO */ pfail: return -1; @@ -265,7 +277,7 @@ static int compile_variant(mds_kbdc_tree_information_variant_t* restrict tree) if (result->variant) { if (multiple_variants == 0) - NEW_ERROR(tree, includes_ptr, ERROR, "only one ‘variant’ is allowed"); + NEW_ERROR(tree, ERROR, "only one ‘variant’ is allowed"); multiple_variants = 1; return 0; } @@ -400,13 +412,13 @@ static int compile_have_range(mds_kbdc_tree_assumption_have_range_t* restrict tr if ((first[0] < 0) || (first[1] >= 0)) { - NEW_ERROR(tree, includes_ptr, ERROR, "iteration boundary must be a single character string"); + 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); } if ((last[0] < 0) || (last[1] >= 0)) { - NEW_ERROR(tree, includes_ptr, ERROR, "iteration boundary must be a single character string"); + 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); } @@ -454,7 +466,8 @@ static int compile_have_range(mds_kbdc_tree_assumption_have_range_t* restrict tr static int check_marco_calls(const mds_kbdc_tree_t* restrict tree) { #define t(...) if (rc |= r = (__VA_ARGS__), r < 0) return r - const mds_kbdc_tree_macro_t* macro; + const mds_kbdc_tree_macro_t* _macro; + mds_kbdc_include_stack_t* _macro_include_stack; void* data; int r, rc = 0; again: @@ -478,7 +491,7 @@ static int check_marco_calls(const mds_kbdc_tree_t* restrict tree) break; case C(MACRO_CALL): - t (get_macro(&(tree->macro_call), ¯o)); + t (get_macro(&(tree->macro_call), &_macro, &_macro_include_stack)); break; default: @@ -487,7 +500,8 @@ static int check_marco_calls(const mds_kbdc_tree_t* restrict tree) tree = tree->next; goto again; - (void) macro; + (void) _macro; + (void) _macro_include_stack; #undef t } @@ -633,25 +647,25 @@ static int check_name_suffix(struct mds_kbdc_tree_callable* restrict tree) if (name == NULL) { - NEW_ERROR(tree, includes_ptr, ERROR, "name-suffix is missing"); + NEW_ERROR(tree, ERROR, "name-suffix is missing"); goto name_error; } if (*++name == '\0') { - NEW_ERROR(tree, includes_ptr, ERROR, "empty name-suffix"); + NEW_ERROR(tree, ERROR, "empty name-suffix"); goto name_error; } if (!strcmp(name, "0")) return 0; if (*name == '\0') { - NEW_ERROR(tree, includes_ptr, ERROR, "leading zero in name-suffix"); + NEW_ERROR(tree, ERROR, "leading zero in name-suffix"); goto name_error; } for (; *name; name++) if ((*name < '0') || ('0' < *name)) { - NEW_ERROR(tree, includes_ptr, ERROR, "name-suffix may only contain digits"); + NEW_ERROR(tree, ERROR, "name-suffix may only contain digits"); goto name_error; } @@ -704,11 +718,24 @@ static int compile_function(mds_kbdc_tree_function_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 - int r; + const 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; t (check_name_suffix((struct mds_kbdc_tree_callable*)tree)); - /* TODO check for redefinition */ + t (get_macro_lax(tree->name, ¯o, ¯o_include_stack)); + if (macro) + { + NEW_ERROR(tree, ERROR, "macro ‘%s’ is already defined", tree->name); + fail_if ((our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL)); + 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; + } t (check_marco_calls(tree->inner)); t (check_function_calls(tree->inner)); @@ -716,8 +743,9 @@ static int compile_macro(mds_kbdc_tree_macro_t* restrict tree) /* TODO add definition */ return 0; - pfail: - return -1; + FAIL_BEGIN; + mds_kbdc_include_stack_free(our_include_stack); + FAIL_END; #undef t } @@ -756,13 +784,13 @@ static int compile_for(mds_kbdc_tree_for_t* restrict tree) if ((first[0] < 0) || (first[1] >= 0)) { - NEW_ERROR(tree, includes_ptr, ERROR, "iteration boundary must be a single character string"); + 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); } if ((last[0] < 0) || (last[1] >= 0)) { - NEW_ERROR(tree, includes_ptr, ERROR, "iteration boundary must be a single character string"); + 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); } @@ -983,7 +1011,9 @@ static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) { mds_kbdc_tree_t* arg = NULL; mds_kbdc_tree_t* arg_; - const mds_kbdc_tree_macro_t* macro = NULL; + const 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; int bad, saved_errno; @@ -992,14 +1022,18 @@ static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) if (bad) return 0; - fail_if (get_macro(tree, ¯o)); + fail_if (get_macro(tree, ¯o, ¯o_include_stack)); if (macro == NULL) goto done; fail_if (push_stack()); for (arg_ = arg; arg_; arg_ = arg_->next) fail_if (let(variable, NULL, arg_, NULL, 0, 0)); + fail_if ((our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL)); + fail_if (mds_kbdc_include_stack_restore(macro_include_stack)); fail_if (compile_subtree(macro->inner)); + fail_if (mds_kbdc_include_stack_restore(our_include_stack)); + mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL; fail_if (pop_stack()); done: @@ -1008,6 +1042,7 @@ static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) return 0; FAIL_BEGIN; mds_kbdc_tree_free(arg); + mds_kbdc_include_stack_free(our_include_stack); FAIL_END; } diff --git a/src/mds-kbdc/include-stack.c b/src/mds-kbdc/include-stack.c index 401bde5..dd2bc98 100644 --- a/src/mds-kbdc/include-stack.c +++ b/src/mds-kbdc/include-stack.c @@ -20,6 +20,7 @@ #include <alloca.h> #include <stdlib.h> #include <errno.h> +#include <string.h> @@ -58,6 +59,11 @@ static size_t includes_size = 0; */ size_t includes_ptr = 0; +/** + * The latest saved include-stack + */ +static mds_kbdc_include_stack_t* latest_save = NULL; + /** @@ -93,6 +99,7 @@ int mds_kbdc_include_stack_dump(size_t ptr) */ void mds_kbdc_include_stack_begin(mds_kbdc_parsed_t* restrict result_) { + latest_save = NULL; result = result_; original_pathname = result_->pathname; original_source_code = result_->source_code; @@ -108,6 +115,7 @@ void mds_kbdc_include_stack_begin(mds_kbdc_parsed_t* restrict result_) void mds_kbdc_include_stack_end(void) { int saved_errno = errno; + latest_save = NULL; result->pathname = original_pathname; result->source_code = original_source_code; free(includes), includes = NULL; @@ -133,15 +141,16 @@ int mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t* restrict tree, vo if (includes_ptr == includes_size) fail_if (xxrealloc(old, includes, includes_size += 4, mds_kbdc_tree_include_t*)); - fail_if (xmalloc(*data, 2, void*)); - - includes[includes_ptr++] = tree; + 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; pfail: @@ -163,8 +172,91 @@ 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; } + +/** + * Save the current include-stack + * + * @return The include-stack, `NULL` on error + */ +mds_kbdc_include_stack_t* mds_kbdc_include_stack_save(void) +{ + int saved_errno; + + if (latest_save) + { + latest_save->duplicates++; + return latest_save; + } + + latest_save = malloc(sizeof(mds_kbdc_include_stack_t)); + if (latest_save == NULL) + return NULL; + + latest_save->stack = NULL; + latest_save->ptr = includes_ptr; + latest_save->duplicates = 0; + + if (latest_save->ptr == 0) + return latest_save; + + fail_if (xmalloc(latest_save->stack, latest_save->ptr, const mds_kbdc_tree_include_t*)); + memcpy(latest_save->stack, includes, latest_save->ptr * sizeof(const mds_kbdc_tree_include_t*)); + + return latest_save; + pfail: + saved_errno = errno; + free(latest_save->stack); + latest_save = NULL; + errno = saved_errno; + return NULL; +} + + +/** + * Restore a previous include-stack + * + * @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) +{ + const mds_kbdc_tree_include_t** new; + + latest_save = stack; + + if (stack->ptr > includes_size) + { + new = realloc(includes, stack->ptr * sizeof(const mds_kbdc_tree_include_t*)); + if (new == NULL) + return -1; + includes = new; + includes_size = stack->ptr; + } + + memcpy(includes, stack->stack, stack->ptr * sizeof(const mds_kbdc_tree_include_t*)); + includes_ptr = stack->ptr; + return 0; +} + + +/** + * 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) +{ + if ((stack == NULL) || (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 6758589..49a6248 100644 --- a/src/mds-kbdc/include-stack.h +++ b/src/mds-kbdc/include-stack.h @@ -63,6 +63,30 @@ /** + * 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; + +} mds_kbdc_include_stack_t; + + + +/** * The number elements stored by `mds_kbdc_include_stack_push` * but not removed by `mds_kbdc_include_stack_pop` */ @@ -113,6 +137,28 @@ int mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t* restrict tree, vo */ void mds_kbdc_include_stack_pop(void* data); +/** + * Save the current include-stack + * + * @return The include-stack, `NULL` on error + */ +mds_kbdc_include_stack_t* mds_kbdc_include_stack_save(void); + +/** + * Restore a previous include-stack + * + * @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); + +/** + * 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); + #endif |