aboutsummaryrefslogtreecommitdiff
path: root/src/tree.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-05-06 11:58:47 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2011-05-06 13:00:06 +0300
commit52c12573a505bf29a0301a1c9553e88c3270713e (patch)
tree642047e5b3de469199b68a76064f756990a3b249 /src/tree.c
parent8465fa7066d3c922b738346335f801cf9ea2243f (diff)
downloadgrecs-52c12573a505bf29a0301a1c9553e88c3270713e.tar.gz
grecs-52c12573a505bf29a0301a1c9553e88c3270713e.tar.bz2
Rewrite list support to keep doubly-linked lists. Implement tree reduction.
* src/format.c (grecs_format_node) (grecs_format_node_path): Handle grecs_node_root. * src/grecs-gram.y (input production): Create root node. * src/grecs.h (grecs_list_entry)<prev>: New member. (grecs_node_root): New node type. (grecs_node_eq): New proto. (grecs_list_add,grecs_tree_reduce): New protos. * src/list.c: Rewrite as a doubly-linked list. * src/tree.c (grecs_node_bind): Bugfix. (grecs_node_unlink): New function. (_tree_recurse): Allow for removal of the current node. (grecs_node_eq): New function. (grecs_tree_reduce): New function. (grecs_tree_process): Descend into the first subnode at once. * src/lookup.c (node_finder): Handle grecs_node_root. * tests/reduce00.at: New testcase. * tests/reduce01.at: New testcase. * tests/reduce02.at: New testcase. * tests/testsuite.at (GRECS_TEST): New macro. Include reduce0[0-2].at. * tests/gcffmt.c: New option -reduce. * tests/gcfpeek.c: Likewise. * tests/gcfset.c: Likewise.
Diffstat (limited to 'src/tree.c')
-rw-r--r--src/tree.c174
1 files changed, 172 insertions, 2 deletions
diff --git a/src/tree.c b/src/tree.c
index 1a2bba5..6b3d555 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -57,7 +57,7 @@ grecs_node_bind(struct grecs_node *master, struct grecs_node *node, int dn)
} else {
if (!master->next) {
master->next = node;
- node->prev = NULL;
+ node->prev = master;
} else {
for (np = master->next; np->next; np = np->next)
;
@@ -67,6 +67,21 @@ grecs_node_bind(struct grecs_node *master, struct grecs_node *node, int dn)
node->up = master->up;
}
}
+
+int
+grecs_node_unlink(struct grecs_node *node)
+{
+ if (node->prev)
+ node->prev->next = node->next;
+ else if (node->up)
+ node->up->down = node->next;
+ else
+ return 1;
+ if (node->next)
+ node->next->prev = node->prev;
+ return 0;
+}
+
static enum grecs_tree_recurse_res
@@ -83,7 +98,8 @@ _tree_recurse(struct grecs_node *node, grecs_tree_recursor_t recfun,
break; \
}
- for (; node; node = node->next) {
+ while (node) {
+ struct grecs_node *next = node->next;
if (node->type == grecs_node_stmt) {
res = recfun(grecs_tree_recurse_set, node, data);
CKRES();
@@ -104,6 +120,7 @@ _tree_recurse(struct grecs_node *node, grecs_tree_recursor_t recfun,
break;
}
}
+ node = next;
}
return grecs_tree_recurse_ok;
#undef CKRES
@@ -771,8 +788,161 @@ grecs_tree_process(struct grecs_node *node, struct grecs_keyword *kwd)
config_keywords.kwd = kwd;
clos.cursect = &config_keywords;
clos.sections = grecs_list_create();
+ if (node->type == grecs_node_root)
+ node = node->down;
rc = grecs_tree_recurse(node, nodeproc, &clos);
grecs_list_free(clos.sections);
return rc;
}
+
+int
+grecs_node_eq(struct grecs_node *a, struct grecs_node *b)
+{
+ if (a->type != b->type)
+ return 1;
+ if (a->type == grecs_node_root)
+ return 0;
+ if (strcmp(a->ident, b->ident))
+ return 1;
+ if (a->type == grecs_node_block &&
+ !grecs_value_eq(&a->value, &b->value))
+ return 1;
+ return 0;
+}
+
+static void
+value_to_list(struct grecs_value *val)
+{
+ struct grecs_list *list;
+ int i;
+
+ if (val->type != GRECS_TYPE_LIST)
+ return;
+ list = _grecs_simple_list_create(0);/* FIXME: this relies on
+ grecs_value_dup registering its
+ return in string_list */
+ switch (val->type) {
+ case GRECS_TYPE_STRING:
+ grecs_list_append(list, grecs_value_dup(val));
+ break;
+
+ case GRECS_TYPE_ARRAY:
+ for (i = 0; i < val->v.arg.c; i++)
+ grecs_list_append(list,
+ grecs_value_dup(&val->v.arg.v[i]));
+ }
+ val->type = GRECS_TYPE_LIST;
+ val->v.list = list;
+}
+
+static void
+node_aggregate_stmt(struct grecs_node *dst, struct grecs_node *src, int type)
+{
+ value_to_list(&dst->value);
+ value_to_list(&src->value);
+ grecs_list_add(dst->value.v.list, src->value.v.list);
+}
+
+static void
+node_merge_stmt(struct grecs_node *to_node, struct grecs_node *from_node,
+ struct grecs_keyword *kwp)
+{
+ if (kwp && GRECS_IS_LIST(kwp->type) && (kwp->type & GRECS_AGGR))
+ node_aggregate_stmt(to_node, from_node, kwp->type);
+ else {
+ /*FIXME: grecs_value_free(from_node->value) */
+ from_node->value.type = GRECS_TYPE_STRING;
+ from_node->value.v.string = NULL;
+ }
+}
+
+static void
+node_merge_block(struct grecs_node *to_node, struct grecs_node *from_node,
+ struct grecs_keyword *kwp)
+{
+ struct grecs_node *sp;
+
+ if (!from_node->down)
+ return;
+ for (sp = from_node->down; ; sp = sp->next) {
+ sp->up = to_node;
+ if (!sp->next)
+ break;
+ }
+ sp->next = to_node->down;
+ to_node->down = from_node->down;
+ from_node->down = NULL;
+}
+
+static void
+node_reduce(struct grecs_node *node, struct grecs_keyword *kwp)
+{
+ struct grecs_node *p;
+
+ for (p = node->next; p; p = p->next)
+ if (grecs_node_eq(p, node) == 0)
+ break;
+ if (p) {
+ switch (node->type) {
+ case grecs_node_root:
+ return;
+ case grecs_node_stmt:
+ node_merge_stmt(p, node, kwp);
+ break;
+ case grecs_node_block:
+ node_merge_block(p, node, kwp);
+ break;
+ }
+ grecs_node_unlink(node);
+ grecs_node_free(node);
+ }
+}
+
+static enum grecs_tree_recurse_res
+reduceproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data)
+{
+ struct nodeproc_closure *clos = data;
+
+ if (op == grecs_tree_recurse_post) {
+ if (clos->sections)
+ grecs_list_pop(clos->sections);
+ } else {
+ struct grecs_keyword *kwp = NULL;
+ if (clos->cursect) {
+ kwp = find_keyword(clos->cursect, node->ident);
+ if (!kwp) {
+ grecs_error(&node->locus, 0,
+ _("Unknown keyword"));
+ return grecs_tree_recurse_skip;
+ }
+ if (op == grecs_tree_recurse_pre) {
+ grecs_list_push(clos->sections, clos->cursect);
+ clos->cursect = kwp;
+ }
+ }
+ node_reduce(node, kwp);
+ }
+ return grecs_tree_recurse_ok;
+}
+
+int
+grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd)
+{
+ int rc;
+ struct nodeproc_closure clos;
+ struct grecs_keyword config_keywords;
+
+ config_keywords.kwd = kwd;
+ if (kwd) {
+ clos.cursect = &config_keywords;
+ clos.sections = grecs_list_create();
+ } else {
+ clos.cursect = NULL;
+ clos.sections = NULL;
+ }
+ rc = grecs_tree_recurse(node->down, reduceproc, &clos);
+ grecs_list_free(clos.sections);
+ return rc;
+}
+

Return to:

Send suggestions and report system problems to the System administrator.