summaryrefslogtreecommitdiffabout
path: root/src
authorSergey Poznyakoff <gray@gnu.org.ua>2011-05-07 10:14:12 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2011-05-07 10:14:12 (GMT)
commitd0371e1111cb083b3916a6ced2ed515a69ca71cc (patch) (side-by-side diff)
tree31cabf0e3dd328c0bb8b2acabc4fc0ee8c844461 /src
parent366e821d28a007a0ca49b9deb97c6c9cea97f2b9 (diff)
downloadgrecs-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') (more/less context) (ignore whitespace changes)
-rw-r--r--src/format.c5
-rw-r--r--src/grecs.h3
-rw-r--r--src/tree.c80
3 files changed, 71 insertions, 17 deletions
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:
@@ -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)
{
- 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;

Return to:

Send suggestions and report system problems to the System administrator.