From c1ef801d10daf57a4a7fe5b4a2f412160a896c46 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Wed, 19 Nov 2014 05:49:13 +0100 Subject: preparation for tree simplification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/mds-kbdc/simplify-tree.c | 77 +++++++++++++++++ src/mds-kbdc/simplify-tree.h | 37 ++++++++ src/mds-kbdc/tree.c | 201 +++++++++++++++++++++++++++++++++---------- src/mds-kbdc/tree.h | 10 +++ 4 files changed, 279 insertions(+), 46 deletions(-) create mode 100644 src/mds-kbdc/simplify-tree.c create mode 100644 src/mds-kbdc/simplify-tree.h (limited to 'src/mds-kbdc') diff --git a/src/mds-kbdc/simplify-tree.c b/src/mds-kbdc/simplify-tree.c new file mode 100644 index 0000000..8a20caa --- /dev/null +++ b/src/mds-kbdc/simplify-tree.c @@ -0,0 +1,77 @@ +/** + * mds — A micro-display server + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "simplify-tree.h" + +#include + + +/** + * Add an error the to error list + * + * @param ERROR_IS_IN_FILE:int Whether the error is in the layout code + * @param SEVERITY:identifier * in `MDS_KBDC_PARSE_ERROR_*` to indicate severity + * @param ...:const char*, ... Error description format string and arguments + */ +#define NEW_ERROR(ERROR_IS_IN_FILE, SEVERITY, ...) \ + do \ + { \ + if (errors_ptr + 1 >= errors_size) \ + { \ + errors_size = errors_size ? (errors_size << 1) : 2; \ + fail_if (xxrealloc(old_errors, *errors, errors_size, mds_kbdc_parse_error_t*)); \ + } \ + fail_if (xcalloc(error, 1, mds_kbdc_parse_error_t)); \ + (*errors)[errors_ptr + 0] = error; \ + (*errors)[errors_ptr + 1] = NULL; \ + errors_ptr++; \ + error->line = line_i; \ + error->severity = MDS_KBDC_PARSE_ERROR_##SEVERITY; \ + error->error_is_in_file = ERROR_IS_IN_FILE; \ + error->start = (size_t)(line - LINE); \ + error->end = (size_t)(end - LINE); \ + fail_if ((error->pathname = strdup(pathname)) == NULL); \ + if (ERROR_IS_IN_FILE) \ + fail_if ((error->code = strdup(source_code.real_lines[line_i])) == NULL); \ + fail_if (xasprintf(error->description, __VA_ARGS__)); \ + } \ + while (0) + + + +/** + * Simplify a tree and generate related warnings in the process + * + * @param tree The tree, it may be modified + * @param errors `NULL`-terminated list of found error, `NULL` if no errors were found or if -1 is returned + * @return -1 if an error occursed that cannot be stored in `*errors`, zero otherwise + */ +int simplify_tree(mds_kbdc_tree_t** restrict tree, mds_kbdc_parse_error_t*** restrict errors) +{ + mds_kbdc_parse_error_t* error; + mds_kbdc_parse_error_t** old_errors = NULL; + size_t errors_size = 0; + size_t errors_ptr = 0; + + *errors = NULL; + + return 0; +} + + +#undef NEW_ERROR + diff --git a/src/mds-kbdc/simplify-tree.h b/src/mds-kbdc/simplify-tree.h new file mode 100644 index 0000000..5009fb6 --- /dev/null +++ b/src/mds-kbdc/simplify-tree.h @@ -0,0 +1,37 @@ +/** + * mds — A micro-display server + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef MDS_MDS_KBDC_SIMPLIFY_TREE_H +#define MDS_MDS_KBDC_SIMPLIFY_TREE_H + + +#include "tree.h" +#include "parse-error.h" + + +/** + * Simplify a tree and generate related warnings in the process + * + * @param tree The tree, it may be modified + * @param errors `NULL`-terminated list of found error, `NULL` if no errors were found or if -1 is returned + * @return -1 if an error occursed that cannot be stored in `*errors`, zero otherwise + */ +int simplify_tree(mds_kbdc_tree_t** restrict tree, mds_kbdc_parse_error_t*** restrict errors); + + +#endif + diff --git a/src/mds-kbdc/tree.c b/src/mds-kbdc/tree.c index b460d04..b11bb6c 100644 --- a/src/mds-kbdc/tree.c +++ b/src/mds-kbdc/tree.c @@ -19,9 +19,13 @@ #include #include +#include +#define C(t) MDS_KBDC_TREE_TYPE_##t + + /** * Initialise a tree node * @@ -72,78 +76,78 @@ static void mds_kbdc_tree_destroy_(mds_kbdc_tree_t* restrict this, int recursive switch (this->type) { - case MDS_KBDC_TREE_TYPE_INFORMATION: - case MDS_KBDC_TREE_TYPE_ASSUMPTION: - case MDS_KBDC_TREE_TYPE_ALTERNATION: - case MDS_KBDC_TREE_TYPE_UNORDERED: + case C(INFORMATION): + case C(ASSUMPTION): + case C(ALTERNATION): + case C(UNORDERED): xdestroy(struct mds_kbdc_tree_nesting*, inner); break; - case MDS_KBDC_TREE_TYPE_INFORMATION_LANGUAGE: - case MDS_KBDC_TREE_TYPE_INFORMATION_COUNTRY: - case MDS_KBDC_TREE_TYPE_INFORMATION_VARIANT: + case C(INFORMATION_LANGUAGE): + case C(INFORMATION_COUNTRY): + case C(INFORMATION_VARIANT): xfree(struct mds_kbdc_tree_information_data*, data); break; - case MDS_KBDC_TREE_TYPE_FUNCTION: - case MDS_KBDC_TREE_TYPE_MACRO: + case C(FUNCTION): + case C(MACRO): xfree(struct mds_kbdc_tree_callable*, name); xdestroy(struct mds_kbdc_tree_callable*, inner); break; - case MDS_KBDC_TREE_TYPE_INCLUDE: + case C(INCLUDE): xfree(mds_kbdc_tree_include_t*, filename); break; - case MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE: + case C(ASSUMPTION_HAVE): xdestroy(mds_kbdc_tree_assumption_have_t*, data); break; - case MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_CHARS: + case C(ASSUMPTION_HAVE_CHARS): xfree(mds_kbdc_tree_assumption_have_chars_t*, chars); break; - case MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_RANGE: + 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 MDS_KBDC_TREE_TYPE_FOR: + 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 MDS_KBDC_TREE_TYPE_IF: + 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 MDS_KBDC_TREE_TYPE_LET: + case C(LET): xfree(mds_kbdc_tree_let_t*, variable); xdestroy(mds_kbdc_tree_let_t*, value); break; - case MDS_KBDC_TREE_TYPE_MAP: + case C(MAP): xdestroy(mds_kbdc_tree_map_t*, sequence); xdestroy(mds_kbdc_tree_map_t*, result); break; - case MDS_KBDC_TREE_TYPE_ARRAY: + case C(ARRAY): xdestroy(mds_kbdc_tree_array_t*, elements); break; - case MDS_KBDC_TREE_TYPE_KEYS: + case C(KEYS): xfree(mds_kbdc_tree_keys_t*, keys); break; - case MDS_KBDC_TREE_TYPE_STRING: + case C(STRING): xfree(mds_kbdc_tree_string_t*, string); break; - case MDS_KBDC_TREE_TYPE_MACRO_CALL: + case C(MACRO_CALL): xfree(mds_kbdc_tree_macro_call_t*, name); xdestroy(mds_kbdc_tree_macro_call_t*, arguments); break; @@ -220,6 +224,108 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) +/** + * Duplicate a subtree and goto `fail` on failure + * + * @param member:identifer The member in the tree to duplicate + */ +#define T(member) \ + if (n->member = mds_kbdc_tree_dup(t->member), n->member == NULL) goto fail + + +/** + * Duplicate a string and goto `fail` on failure + * + * @param member:identifer The member in the tree to duplicate + */ +#define S(member) \ + if (n->member = strdup(t->member), n->member == NULL) goto fail + + +/** + * Cast the trees to a specialised subtype + * + * @param LOWERCASE:identifer The name of subtype + */ +#define NODE(LOWERCASE) \ + mds_kbdc_tree_##LOWERCASE##_t* n = (mds_kbdc_tree_##LOWERCASE##_t*)node; \ + mds_kbdc_tree_##LOWERCASE##_t* t = (mds_kbdc_tree_##LOWERCASE##_t*)this + + +/** + * Create a duplicate of a tree node and its children + * + * @param this The tree node + * @return A duplicate of `this`, `NULL` on error + */ +mds_kbdc_tree_t* mds_kbdc_tree_dup(mds_kbdc_tree_t* restrict this) +{ + typedef struct mds_kbdc_tree_nesting mds_kbdc_tree_nesting_t; + typedef struct mds_kbdc_tree_callable mds_kbdc_tree_callable_t; + typedef struct mds_kbdc_tree_information_data mds_kbdc_tree_information_data_t; + mds_kbdc_tree_t* node = calloc(1, sizeof(mds_kbdc_tree_t)); + int saved_errno; + + if (node == NULL) + return NULL; + + node->type = this->type; + node->loc_line = this->loc_line; + node->loc_start = this->loc_start; + node->loc_end = this->loc_end; + node->next = mds_kbdc_tree_dup(this->next); + if (node->next == NULL) goto fail; + + switch (this->type) + { + case C(INFORMATION): + case C(ASSUMPTION): + case C(ALTERNATION): + case C(UNORDERED): { NODE(nesting); T(inner); } break; + case C(FUNCTION): + case C(MACRO): { NODE(callable); S(name);T(inner); } break; + case C(ASSUMPTION_HAVE): { NODE(assumption_have); T(data); } break; + case C(ARRAY): { NODE(array); T(elements); } break; + case C(LET): { NODE(let); S(variable);T(value); } break; + case C(MACRO_CALL): { NODE(macro_call); S(name);T(arguments); } break; + case C(INFORMATION_LANGUAGE): + case C(INFORMATION_COUNTRY): + case C(INFORMATION_VARIANT): { NODE(information_data); S(data); } break; + case C(INCLUDE): { NODE(include); S(filename); } break; + case C(ASSUMPTION_HAVE_CHARS): { NODE(assumption_have_chars); S(chars); } break; + case C(KEYS): { NODE(keys); S(keys); } break; + case C(STRING): { NODE(string); S(string); } break; + case C(ASSUMPTION_HAVE_RANGE): { NODE(assumption_have_range); S(first);S(last); } break; + case C(FOR): { NODE(for); S(first);S(last);S(variable);T(inner); } break; + case C(IF): { NODE(if); S(condition);T(inner);T(otherwise); } break; + case C(MAP): { NODE(map); T(sequence);T(result); } break; + + case C(NOTHING): + case C(RETURN): + case C(BREAK): + case C(CONTINUE): + break; + + default: + abort(); + break; + } + + return node; + fail: + saved_errno = errno; + mds_kbdc_tree_free(node); + errno = saved_errno; + return NULL; +} + + +#undef NODE +#undef S +#undef T + + + /** * Convert the tree to a specialised subtype and * prints its type and code location @@ -365,6 +471,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) break + /** * Print a tree into a file * @@ -381,30 +488,30 @@ static void mds_kbdc_tree_print_indented(mds_kbdc_tree_t* restrict this, FILE* o switch (this->type) { /* These have their break built into their macro. */ - case MDS_KBDC_TREE_TYPE_INFORMATION: NESTING(information, "information", inner); - case MDS_KBDC_TREE_TYPE_INFORMATION_LANGUAGE: SIMPLEX(information_language, "language", data); - case MDS_KBDC_TREE_TYPE_INFORMATION_COUNTRY: SIMPLEX(information_country, "country", data); - case MDS_KBDC_TREE_TYPE_INFORMATION_VARIANT: SIMPLEX(information_variant, "variant", data); - case MDS_KBDC_TREE_TYPE_INCLUDE: SIMPLEX(include, "include", filename); - case MDS_KBDC_TREE_TYPE_FUNCTION: NAMED_NESTING(function, "function", name, inner); - case MDS_KBDC_TREE_TYPE_MACRO: NAMED_NESTING(macro, "macro", name, inner); - case MDS_KBDC_TREE_TYPE_ASSUMPTION: NESTING(assumption, "assumption", inner); - case MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE: NESTING(assumption_have, "have", data); - case MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_CHARS: SIMPLEX(assumption_have_chars, "have_chars", chars); - case MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_RANGE: DUPLEX(assumption_have_range, "have_range", first, last); - case MDS_KBDC_TREE_TYPE_LET: NAMED_NESTING(let, "let", variable, value); - case MDS_KBDC_TREE_TYPE_ARRAY: NESTING(array, "array", elements); - case MDS_KBDC_TREE_TYPE_KEYS: SIMPLEX(keys, "keys", keys); - case MDS_KBDC_TREE_TYPE_STRING: SIMPLEX(string, "string", string); - case MDS_KBDC_TREE_TYPE_NOTHING: NOTHING("nothing"); - case MDS_KBDC_TREE_TYPE_ALTERNATION: NESTING(alternation, "alternation", inner); - case MDS_KBDC_TREE_TYPE_UNORDERED: NESTING(unordered, "unordered", inner); - case MDS_KBDC_TREE_TYPE_MACRO_CALL: NAMED_NESTING(macro_call, "macro_call", name, arguments); - case MDS_KBDC_TREE_TYPE_RETURN: NOTHING("return"); - case MDS_KBDC_TREE_TYPE_BREAK: NOTHING("break"); - case MDS_KBDC_TREE_TYPE_CONTINUE: NOTHING("continue"); + 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): SIMPLEX(include, "include", filename); + 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(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 MDS_KBDC_TREE_TYPE_FOR: + case C(FOR): { NODE(for, "for"); STRING(first); @@ -417,7 +524,7 @@ static void mds_kbdc_tree_print_indented(mds_kbdc_tree_t* restrict this, FILE* o } break; - case MDS_KBDC_TREE_TYPE_IF: + case C(IF): { NODE(if, "if"); STRING(condition); @@ -427,7 +534,7 @@ static void mds_kbdc_tree_print_indented(mds_kbdc_tree_t* restrict this, FILE* o } break; - case MDS_KBDC_TREE_TYPE_MAP: + case C(MAP): { NODE(map, "map"); BRANCH(sequence); @@ -469,3 +576,5 @@ void mds_kbdc_tree_print(mds_kbdc_tree_t* restrict this, FILE* output) #undef BRANCH #undef NODE +#undef C + diff --git a/src/mds-kbdc/tree.h b/src/mds-kbdc/tree.h index f3ad7f2..c36cec4 100644 --- a/src/mds-kbdc/tree.h +++ b/src/mds-kbdc/tree.h @@ -713,6 +713,16 @@ void mds_kbdc_tree_destroy(mds_kbdc_tree_t* restrict this); void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this); +/** + * Create a duplicate of a tree node and + * its children + * + * @param this The tree node + * @return A duplicate of `this`, `NULL` on error + */ +mds_kbdc_tree_t* mds_kbdc_tree_dup(mds_kbdc_tree_t* restrict this); + + /** * Print a tree into a file * -- cgit v1.2.3-70-g09d2