diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-05-07 13:14:12 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-05-07 13:14:12 +0300 |
commit | d0371e1111cb083b3916a6ced2ed515a69ca71cc (patch) | |
tree | 31cabf0e3dd328c0bb8b2acabc4fc0ee8c844461 /src | |
parent | 366e821d28a007a0ca49b9deb97c6c9cea97f2b9 (diff) | |
download | grecs-d0371e1111cb083b3916a6ced2ed515a69ca71cc.tar.gz grecs-d0371e1111cb083b3916a6ced2ed515a69ca71cc.tar.bz2 |
Implement table-driven statement aggregation.
* src/grecs.h (grecs_tree_reduce): Change signature.
(nodeproc_closure)<flags>: 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.
Diffstat (limited to 'src')
-rw-r--r-- | src/format.c | 3 | ||||
-rw-r--r-- | src/grecs.h | 3 | ||||
-rw-r--r-- | src/tree.c | 72 |
3 files changed, 66 insertions, 12 deletions
diff --git a/src/format.c b/src/format.c index f12b465..9b6b6af 100644 --- a/src/format.c +++ b/src/format.c @@ -146,7 +146,8 @@ grecs_format_simple_statement(struct grecs_keyword *kwp, unsigned level, 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 *, @@ -216,6 +216,8 @@ freeproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) int grecs_tree_free(struct grecs_node *node) { + if (!node) + return 0; /* FIXME: Check if that's a node_type_root */ if (node->type != grecs_node_root) { errno = EINVAL; @@ -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: @@ -917,18 +920,63 @@ value_to_list(struct grecs_value *val) } 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) { + 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); - grecs_list_add(dst->v.value->v.list, src->v.value->v.list); + /* 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,6 +1033,7 @@ reduceproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) if (op == grecs_tree_recurse_post) { if (clos->sections) + clos->cursect = (struct grecs_keyword *) grecs_list_pop(clos->sections); } else { struct grecs_keyword *kwp = NULL; @@ -992,7 +1041,8 @@ reduceproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) 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; |