From d0371e1111cb083b3916a6ced2ed515a69ca71cc Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sat, 7 May 2011 13:14:12 +0300 Subject: Implement table-driven statement aggregation. * src/grecs.h (grecs_tree_reduce): Change signature. (nodeproc_closure): New member. (value_to_list): Bugfixes. (value_to_array,array_add): New functions. (node_aggregate_stmt): Rewrite. (node_merge_stmt): Take additional argument. (grecs_tree_reduce): Take additional argument. All uses changed. * src/tree.c (grecs_tree_free): Don't coredump on NULL arg. * src/format.c (grecs_format_simple_statement): Bugfix. * tests/reduce03.at: New testcase. * tests/Makefile.am: Add reduce03.at * tests/testsuite.at: Add reduce03.at * tests/gcffmt.c: Single grecs_format_node call is enough to print the entire tree. * tests/gcfset.c (logging_kwtab): Mark "facility" as GRECS_AGGR to disable aggregation. (usage): Update. (main): New options: -print, -locus, -sort, -noset. Pass GRECS_AGGR to grecs_tree_reduce. --- src/format.c | 5 ++-- src/grecs.h | 3 ++- src/tree.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 71 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/format.c b/src/format.c index f12b465..9b6b6af 100644 --- a/src/format.c +++ b/src/format.c @@ -143,10 +143,11 @@ grecs_format_simple_statement(struct grecs_keyword *kwp, unsigned level, if (GRECS_IS_LIST(kwp->type)) fprintf(stream, "list of %s", gettext(grecs_data_type_string( - GRECS_TYPE (kwp->type)))); + GRECS_TYPE(kwp->type)))); else fprintf(stream, "%s", - gettext(grecs_data_type_string(kwp->type))); + gettext(grecs_data_type_string( + GRECS_TYPE(kwp->type)))); fprintf(stream, ">;\n"); } } diff --git a/src/grecs.h b/src/grecs.h index f32fc1f..628f9f2 100644 --- a/src/grecs.h +++ b/src/grecs.h @@ -338,7 +338,8 @@ int grecs_tree_process(struct grecs_node *node, struct grecs_keyword *kwd); int grecs_value_eq(struct grecs_value *a, struct grecs_value *b); struct grecs_node *grecs_find_node(struct grecs_node *node, const char *path); struct grecs_node *grecs_node_from_path(const char *path, const char *value); -int grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd); +int grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd, + int flags); void grecs_tree_sort(struct grecs_node *node, int (*compare)(struct grecs_node const *, diff --git a/src/tree.c b/src/tree.c index 955fc52..06f15f0 100644 --- a/src/tree.c +++ b/src/tree.c @@ -216,7 +216,9 @@ freeproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) int grecs_tree_free(struct grecs_node *node) { - /* FIXME: Check if that's a node_type_root */ + if (!node) + return 0; + /* FIXME: Check if that's a node_type_root */ if (node->type != grecs_node_root) { errno = EINVAL; return 1; @@ -760,6 +762,7 @@ grecs_process_ident(struct grecs_keyword *kwp, grecs_value_t *value, struct nodeproc_closure { struct grecs_keyword *cursect; struct grecs_list *sections; + int flags; }; #define CURRENT_BASE(clos) \ ((char*)((clos)->cursect ? (clos)->cursect->callback_data : NULL)) @@ -900,12 +903,12 @@ value_to_list(struct grecs_value *val) struct grecs_list *list; int i; - if (val->type != GRECS_TYPE_LIST) + if (val->type == GRECS_TYPE_LIST) return; list = grecs_value_list_create(); switch (val->type) { case GRECS_TYPE_STRING: - grecs_list_append(list, val); + grecs_list_append(list, grecs_value_ptr_from_static(val)); break; case GRECS_TYPE_ARRAY: @@ -916,19 +919,64 @@ value_to_list(struct grecs_value *val) val->v.list = list; } +static void +value_to_array(struct grecs_value *val) +{ + if (val->type == GRECS_TYPE_ARRAY) + return; + else { + struct grecs_value **vp; + vp = grecs_calloc(1, sizeof(*vp)); + vp[0] = grecs_value_ptr_from_static(val); + val->type = GRECS_TYPE_ARRAY; + val->v.arg.c = 1; + val->v.arg.v = vp; + } +} + +static void +array_add(struct grecs_value *vx, struct grecs_value *vy) +{ + size_t i; + + vx->v.arg.v = grecs_realloc(vx->v.arg.v, + (vx->v.arg.c + vy->v.arg.c) * + sizeof(vx->v.arg.v[0])); + for (i = 0; i < vy->v.arg.c; i++) + vx->v.arg.v[i + vy->v.arg.c] = vy->v.arg.v[i]; + grecs_free(vy->v.arg.v); + vy->v.arg.v = NULL; + vy->v.arg.c = 0; +} + static void node_aggregate_stmt(struct grecs_node *dst, struct grecs_node *src, int type) { - value_to_list(dst->v.value); - value_to_list(src->v.value); - grecs_list_add(dst->v.value->v.list, src->v.value->v.list); + if (GRECS_IS_LIST(type)) { + struct grecs_list *t; + /* Coerce both arguments to lists */ + value_to_list(dst->v.value); + value_to_list(src->v.value); + /* Aggregate two lists in order */ + grecs_list_add(src->v.value->v.list, dst->v.value->v.list); + /* Swap them */ + t = dst->v.value->v.list; + dst->v.value->v.list = src->v.value->v.list; + src->v.value->v.list = t; + } else { + value_to_array(dst->v.value); + value_to_array(src->v.value); + array_add(dst->v.value, src->v.value); + } } static void node_merge_stmt(struct grecs_node *to_node, struct grecs_node *from_node, - struct grecs_keyword *kwp) + struct grecs_keyword *kwp, int flags) { - if (kwp && GRECS_IS_LIST(kwp->type) && (kwp->type & GRECS_AGGR)) + if (kwp && + (flags & GRECS_AGGR) ^ (kwp->type & GRECS_AGGR) && + (GRECS_IS_LIST(kwp->type) || kwp->callback)) node_aggregate_stmt(to_node, from_node, kwp->type); else { grecs_value_free(from_node->v.value); @@ -955,7 +1003,7 @@ node_merge_block(struct grecs_node *to_node, struct grecs_node *from_node, } static void -node_reduce(struct grecs_node *node, struct grecs_keyword *kwp) +node_reduce(struct grecs_node *node, struct grecs_keyword *kwp, int flags) { struct grecs_node *p; @@ -967,7 +1015,7 @@ node_reduce(struct grecs_node *node, struct grecs_keyword *kwp) case grecs_node_root: return; case grecs_node_stmt: - node_merge_stmt(p, node, kwp); + node_merge_stmt(p, node, kwp, flags); break; case grecs_node_block: node_merge_block(p, node, kwp); @@ -985,14 +1033,16 @@ reduceproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) if (op == grecs_tree_recurse_post) { if (clos->sections) - grecs_list_pop(clos->sections); + clos->cursect = (struct grecs_keyword *) + 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")); + _("%s: unknown keyword"), + node->ident); return grecs_tree_recurse_skip; } if (op == grecs_tree_recurse_pre) { @@ -1000,13 +1050,14 @@ reduceproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) clos->cursect = kwp; } } - node_reduce(node, kwp); + node_reduce(node, kwp, clos->flags); } return grecs_tree_recurse_ok; } int -grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd) +grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd, + int flags) { int rc; struct nodeproc_closure clos; @@ -1020,6 +1071,7 @@ grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd) clos.cursect = NULL; clos.sections = NULL; } + clos.flags = flags; rc = grecs_tree_recurse(node->down, reduceproc, &clos); grecs_list_free(clos.sections); return rc; -- cgit v1.2.1