for $segname (keys %segments) {
$segment= $segments{$segname};
$movfeats= $segment->{MovFeats};
- o("static MovFeat movfeats_${segname}[];\n");
+ o("static MovFeat movfeats_$segname","[];\n");
o("static Segment segment_$segname= {");
o(" \"$segname\",");
o(" ",scalar(@$movfeats),", movfeats_$segname");
o(" };\n");
- o("static MovFeat movfeats_${segname}[]= {");
+ o("static MovFeat movfeats_$segname","[]= {");
$delim= "";
for $movfeat (@$movfeats) {
o("$delim\n");
if ($reverse) { o("/*reverse*/ "); }
$sss =~ m,^(\w*)/(([A-Za-z]*)(\d*))$, or die;
($segname, $movfeatpos, $movfeat, $movpos) = ($1,$2,$3,$4);
- o("&movfeats_${segname}[",
+ o("&movfeats_${segname}","[",
$segments{$segname}{MovFeatMap}{$movfeat},
"], ",
(length $movfeat ? $movpos : 0),
o("\n }\n};\n");
}
o("\n");
- o("Node *nodes_head= ",(@nodes ? '&'.pr(Node,$nodes[0]) : 0),";\n");
- o("Node *nodes_tail= ",(@nodes ? '&'.pr(Node,$nodes[$#nodes]) : 0),";\n");
+ o("NodeList all_nodes= { ",
+ (@nodes ? '&'.pr(Node,$nodes[0]) : 0), ", ",
+ (@nodes ? '&'.pr(Node,$nodes[$#nodes]) : 0),
+ " };\n");
}
o("/*autogenerated - do not edit*/\n\n");
/**/
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "dlist.h"
+#include "graph-data.h"
+
+/*---------- output processing ----------*/
+
+static void voutputstuff(int trace, const char *fmt, va_list al) {
+ static struct OutputBuf {
+ int used, allocd;
+ char *buf;
+ } bufs[2];
+
+ struct OutputBuf *b;
+ char *s, *p, *newline;
+ int r, l;
+
+ b= &bufs[trace];
+ r= vasprintf(&s,fmt,al); if (r<0) { perror("vasprintf"); exit(16); }
+ p= s;
+
+ for (;;) {
+ newline= strchr(p,'\n');
+ if (newline) { *newline= 0; }
+ l= strlen(p);
+ if (l+b->used > b->allocd) {
+ b->allocd= l+b->used;
+ b->buf= realloc(b->buf, b->allocd);
+ if (!b->buf) { perror("realloc voutputstuff"); exit(16); }
+ }
+ memcpy(b->buf+b->used, p, l);
+ b->used += l;
+
+ if (!newline) break;
+
+ if (trace) { fputs("# ",stdout); }
+ fwrite(b->buf, 1,b->used, stdout);
+ putc('\n',stdout);
+ if (ferror(stdout) || fflush(stdout)) {
+ perror("stdout voutputstuff"); exit(12);
+ }
+ b->used= 0;
+ p= newline+1;
+ }
+
+ free(s);
+}
+
+#define OF(fn,tr) \
+ static void v##fn(const char *fmt, va_list al) { \
+ voutputstuff(tr,fmt,al); \
+ } \
+ static void fn(const char *fmt, ...) { \
+ va_list al; \
+ va_start(al,fmt); \
+ v##fn(fmt,al); \
+ va_end(al); \
+ }
+OF(output,0)
+OF(trace,1)
+
+/*---------- general graph-manipulation and printing stuff ----------*/
+
+static void trace_node(Node *node) {
+ trace("n%p",node);
+}
+
+static void trace_edgeend(EdgeEnd *edge) {
+ trace("n%p%c",edge->node->node,"OI"[edge->node->side]);
+}
+
+static EdgeEnd *edgeend_otherend(EdgeEnd *thisend) {
+ return &thisend->edge->ends[!thisend->end];
+}
+
+static int count_edges(const NodeSide *node) {
+ int count;
+ const EdgeEnd *edge;
+
+ for (count=0, edge=node->head;
+ edge;
+ count++, edge=edge->next);
+ return count;
+}
+
+static void edgeend_disconnect(EdgeEnd *toremove) {
+ LIST_UNLINK(*toremove->node, toremove);
+}
+
+static void edgeend_replumb(EdgeEnd *tomove, NodeSide *newtarget) {
+ edgeend_disconnect(tomove);
+ LIST_LINK_TAIL(*newtarget, tomove);
+ tomove->node= newtarget;
+}
+
+static void edge_delete(Edge *edge) {
+ edgeend_disconnect(&edge->ends[0]);
+ edgeend_disconnect(&edge->ends[1]);
+}
+
+static void node_surely_orphaned(Node *node) {
+ assert(!node->sides[0].head);
+ assert(!node->sides[1].head);
+ LIST_UNLINK(all_nodes, node);
+}
+
+/*---------- operations ----------*/
+
static void extendsplits(void) {
+ int pass, rightside, n;
+ Node *node;
+ EdgeEnd *leftedge, *rightedge;
+
/*
* Whenever we have a node which has one or more moveable feature
* subsegments, part of the same moveable feature, on one side, and
for (;;) {
pass++;
- for (node=nodes_head; node; node=node->next) {
+ for (node=all_nodes.head; node; node=node->next) {
for (rightside=0; rightside<2; rightside++) {
trace("extendsplit pass %d node ",pass); trace_node(node);
trace("/%d ",rightside);
goto no_extend_this;
}
leftedge= node->sides[!rightside].head;
- if (leftedge->edge->movfeatpos) {
+ if (leftedge->edge->subseg->movfeat) {
trace("no: lhs moveable\n");
goto no_extend_this;
}
for (rightedge= node->sides[rightside].head;
rightedge;
rightedge= rightedge->next) {
- if (!rightedge->edge->movfeatpos) {
+ if (!rightedge->edge->subseg->movfeat) {
trace("no: rhs fixed ("); trace_edgeend(rightedge); trace(")\n");
goto no_extend_this;
}
- if (strcmp(leftedge->edge->segment, rightedge->edge->segment)) {
+ if (leftedge->edge->subseg->segment !=
+ rightedge->edge->subseg->segment) {
trace("no: lhs seg %s, rhs seg %s (",
- leftedge->edge->segment
- rightedge->edge->segment);
+ leftedge->edge->subseg->segment->segname,
+ rightedge->edge->subseg->segment->segname);
trace_edgeend(rightedge); trace(")\n");
goto no_extend_this;
}
rightedge;
rightedge= rightedge->next) {
rightedge->edge->distance += leftedge->edge->distance;
- edge_replumb(rightedge, edgeend_otherend(leftedge)->node);
+ edgeend_replumb(rightedge, edgeend_otherend(leftedge)->node);
}
edge_delete(leftedge->edge);
node_surely_orphaned(node);
}
}
-static EdgeEnd *edgeend_otherend(EdgeEnd *thisend) {
- return &thisend->edge->ends[!thisend->end];
-}
-
static void elimtrivial(void) {
/* Eliminate trivial nodes: ones which have only two edges, which
* come in on opposite sides, have the same subsegspec, and with the
* two ends identically aligned.
*/
- for (node=nodes_head; node; node=next_node) {
+ EdgeEnd *leftedge, *rightedge;
+ Node *node, *next_node;
+
+ for (node=all_nodes.head; node; node=next_node) {
next_node=node->next;
trace("elimtrivial node "); trace_node(node); trace(" ");
if (!(count_edges(&node->sides[0])==1 &&
}
leftedge= node->sides[0].head;
rightedge= node->sides[0].head;
- if (strcmp(leftedge->edge.segment,rightedge->edge.segment)) {
- trace("no, segments differ\n");
+ if (leftedge->edge->subseg != rightedge->edge->subseg) {
+ trace("no, (sub)segments differ\n");
continue;
}
- if (!!leftedge->edge.movfeatpos != !!rightedge->edge.movfeatpos ||
- strcmp(leftedge->edge.movfeatpos, rightedge->edge.movfeatpos)) {
- trace("no, movfeatpos's differ\n");
+ if (leftedge->edge->movpos != rightedge->edge->movpos) {
+ trace("no, movpos's differ\n");
continue;
}
if (leftedge->end == rightedge->end) {
}
trace(" yes:\n");
rightedge->edge->distance += leftedge->edge->distance;
- edge_replumb(rightedge, edgeend_otherend(leftedge)->node);
+ edgeend_replumb(rightedge, edgeend_otherend(leftedge)->node);
edge_delete(leftedge->edge);
node_surely_orphaned(node);
trace(" elimtrivial operation complete\n");
static void consistency(void) {
}
-static void print
+static void printforneato(void) {
+ Node *node;
+ EdgeEnd *edgeend;
+ Edge *edge;
+ int side;
+
+ output("digraph L {\n");
+
+ for (node=all_nodes.head; node; node=node->next) {
+ output(" n%pO -> n%pI [len=0];\n",
+ node, node);
+ for (side=0; side<2; side++) {
+ for (edgeend=node->sides[side].head; edgeend; edgeend=edgeend->next) {
+ if (edgeend->end) continue; /* do each edge once, from end 0, only */
+ edge= edgeend->edge;
+ output(" n%p%c -> n%p%c [label=\"",
+ edge->ends[0].node->node, "OI"[edge->ends[0].node->side],
+ edge->ends[1].node->node, "OI"[edge->ends[1].node->side]);
+ if (!edge->subseg->segment->segname) {
+ output("?");
+ } else {
+ output(edge->subseg->segment->segname);
+ if (edge->subseg->movfeat) {
+ output("/%s%d",edge->subseg->movfeat,edge->movpos);
+ }
+ }
+ output("\"];\n");
+ }
+ }
+ }
+ output("}\n");
+}
+
+typedef struct {
+ const char *name;
+ void (*fn)(void);
+} OpInfo;
+
+static const OpInfo opinfos[]= {
+#define OI(x) { #x, x },
+ OI(printforneato)
+ OI(consistency)
+ OI(extendsplits)
+ OI(elimtrivial)
+ { 0,0 }
+};
+
+static void usage(void) {
+ const OpInfo *oi;
+
+ fprintf(stderr,
+ "usage: .../redactgraph <operation> [<operation>...]\n"
+ "operations:\n");
+ for (oi=opinfos; oi->name; oi++) {
+ fprintf(stderr," %s\n",oi->name);
+ }
+ fflush(stderr);
+ exit(8);
+}
+
+int main(int argc, const char *const *argv) {
+ const OpInfo *oi;
+ const char *arg;
+
+ if (!argv[0] || !argv[1]) usage();
+
+ while ((arg= *++argv)) {
+ for (oi=opinfos; oi->name && strcmp(arg,oi->name); oi++);
+ if (!oi->name) usage();
+ oi->fn();
+ }
+ trace("\n");
+ output("\n");
+ if (ferror(stdout) || fflush(stdout)) { perror("stdout"); exit(12); }
+ exit(0);
+}