aboutsummaryrefslogtreecommitdiffstats
path: root/src/mds-kbdc
diff options
context:
space:
mode:
authorMattias Andrée <maandree@operamail.com>2014-11-19 05:49:13 +0100
committerMattias Andrée <maandree@operamail.com>2014-11-19 05:49:13 +0100
commitc1ef801d10daf57a4a7fe5b4a2f412160a896c46 (patch)
tree705a0414aa78152f56f208fb9784ee1c4393af99 /src/mds-kbdc
parenttypo (diff)
downloadmds-c1ef801d10daf57a4a7fe5b4a2f412160a896c46.tar.gz
mds-c1ef801d10daf57a4a7fe5b4a2f412160a896c46.tar.bz2
mds-c1ef801d10daf57a4a7fe5b4a2f412160a896c46.tar.xz
preparation for tree simplification
Signed-off-by: Mattias Andrée <maandree@operamail.com>
Diffstat (limited to 'src/mds-kbdc')
-rw-r--r--src/mds-kbdc/simplify-tree.c77
-rw-r--r--src/mds-kbdc/simplify-tree.h37
-rw-r--r--src/mds-kbdc/tree.c201
-rw-r--r--src/mds-kbdc/tree.h10
4 files changed, 279 insertions, 46 deletions
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 <http://www.gnu.org/licenses/>.
+ */
+#include "simplify-tree.h"
+
+#include <libmdsserver/macros.h>
+
+
+/**
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#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 <stdlib.h>
#include <string.h>
+#include <errno.h>
+#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;
@@ -221,6 +225,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
@@ -714,6 +714,16 @@ 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
*
* @param this The tree node