[9] | 1 | /* topo - topological sort Author: Kent Williams */
|
---|
| 2 |
|
---|
| 3 | /*
|
---|
| 4 | ** topo - perform a topological sort of the output of lorder.
|
---|
| 5 | **
|
---|
| 6 | ** Usage : topo [infile] [outfile]
|
---|
| 7 | **
|
---|
| 8 | ** Author: Kent Williams (williams@umaxc.weeg.uiowa.edu)
|
---|
| 9 | */
|
---|
| 10 |
|
---|
| 11 | #include <ctype.h>
|
---|
| 12 | #include <stdlib.h>
|
---|
| 13 | #include <string.h>
|
---|
| 14 | #include <stdio.h>
|
---|
| 15 |
|
---|
| 16 | typedef struct __v {
|
---|
| 17 | struct __v *next; /* link list node */
|
---|
| 18 | int indegree, /* number of edges into this vertex */
|
---|
| 19 | visited, /* depth-first search visited flag */
|
---|
| 20 | on_the_path, /* used to find cycles */
|
---|
| 21 | has_a_cycle; /* true if a cycle at this vertex */
|
---|
| 22 | struct __e *out; /* outgoing edges from this vertex */
|
---|
| 23 | char key[1]; /* name of this vertex */
|
---|
| 24 | } vertex;
|
---|
| 25 |
|
---|
| 26 | typedef struct __e {
|
---|
| 27 | struct __e *next; /* link list node */
|
---|
| 28 | vertex *v; /* vertex to which this edge goes */
|
---|
| 29 | } edge;
|
---|
| 30 |
|
---|
| 31 | _PROTOTYPE(int main, (int argc, char **argv));
|
---|
| 32 | _PROTOTYPE(void *xmalloc, (size_t siz));
|
---|
| 33 | _PROTOTYPE(edge *new_edge, (vertex *v));
|
---|
| 34 | _PROTOTYPE(char *copyupto, (char *name, char *buf, int stop));
|
---|
| 35 | _PROTOTYPE(int child_of, (vertex *parent, vertex *child));
|
---|
| 36 | _PROTOTYPE(vertex *add_v, (char *s));
|
---|
| 37 | _PROTOTYPE(void readin, (void));
|
---|
| 38 | _PROTOTYPE(void pushname, (char *s));
|
---|
| 39 | _PROTOTYPE(char *popname, (void));
|
---|
| 40 | _PROTOTYPE(void topo, (void));
|
---|
| 41 | _PROTOTYPE(void print_cycle, (vertex *parent, vertex *child));
|
---|
| 42 | _PROTOTYPE(void dfs, (vertex *v));
|
---|
| 43 | _PROTOTYPE(void check_cycles, (void));
|
---|
| 44 |
|
---|
| 45 | /*
|
---|
| 46 | ** xmalloc -- standard do or die malloc front end.
|
---|
| 47 | */
|
---|
| 48 | void *
|
---|
| 49 | xmalloc(siz)
|
---|
| 50 | size_t siz;
|
---|
| 51 | {
|
---|
| 52 | void *rval = (void *)malloc(siz);
|
---|
| 53 | if(rval == NULL) {
|
---|
| 54 | fputs("Out of memory.\n",stderr);
|
---|
| 55 | exit(1);
|
---|
| 56 | }
|
---|
| 57 | return rval;
|
---|
| 58 | }
|
---|
| 59 |
|
---|
| 60 | /*
|
---|
| 61 | ** edge allocater.
|
---|
| 62 | */
|
---|
| 63 | edge *
|
---|
| 64 | new_edge(v)
|
---|
| 65 | vertex *v;
|
---|
| 66 | {
|
---|
| 67 | edge *rval;
|
---|
| 68 | rval = (edge *)xmalloc(sizeof(edge));
|
---|
| 69 | rval->v = v; return rval;
|
---|
| 70 | }
|
---|
| 71 |
|
---|
| 72 | /*
|
---|
| 73 | ** copyupto - copy until you see the stop character.
|
---|
| 74 | */
|
---|
| 75 | char *
|
---|
| 76 | copyupto(name,buf,stop)
|
---|
| 77 | char *name,*buf,stop;
|
---|
| 78 | {
|
---|
| 79 | while(*buf != '\0' && *buf != stop)
|
---|
| 80 | *name++ = *buf++;
|
---|
| 81 | *name = '\0';
|
---|
| 82 | while(*buf != '\0' && isspace(*buf))
|
---|
| 83 | buf++;
|
---|
| 84 | return buf;
|
---|
| 85 | }
|
---|
| 86 |
|
---|
| 87 | /*
|
---|
| 88 | ** find out if the vertex child is a child of the vertex parent.
|
---|
| 89 | */
|
---|
| 90 | int
|
---|
| 91 | child_of(parent,child)
|
---|
| 92 | vertex *parent,*child;
|
---|
| 93 | {
|
---|
| 94 | edge *e;
|
---|
| 95 | for(e = parent->out; e != NULL && e->v != child; e = e->next)
|
---|
| 96 | ;
|
---|
| 97 | return e == NULL ? 0 : 1;
|
---|
| 98 | }
|
---|
| 99 |
|
---|
| 100 | /*
|
---|
| 101 | ** the vertex set.
|
---|
| 102 | **
|
---|
| 103 | ** add_v adds a vertex to the set if it's not already there.
|
---|
| 104 | */
|
---|
| 105 | vertex *vset = NULL;
|
---|
| 106 |
|
---|
| 107 | vertex *
|
---|
| 108 | add_v(s)
|
---|
| 109 | char *s;
|
---|
| 110 | {
|
---|
| 111 | vertex *v,*last;
|
---|
| 112 | /*
|
---|
| 113 | ** go looking for this key in the vertex set.
|
---|
| 114 | */
|
---|
| 115 | for(last = v = vset; v != NULL && strcmp(v->key,s) != 0;
|
---|
| 116 | last = v, v = v->next)
|
---|
| 117 | ;
|
---|
| 118 | if(v != NULL) {
|
---|
| 119 | /*
|
---|
| 120 | ** use the move-to-front heuristic to keep this from being
|
---|
| 121 | ** an O(N^2) algorithm.
|
---|
| 122 | */
|
---|
| 123 | if(last != vset) {
|
---|
| 124 | last->next = v->next;
|
---|
| 125 | v->next = vset;
|
---|
| 126 | vset = v;
|
---|
| 127 | }
|
---|
| 128 | return v;
|
---|
| 129 | }
|
---|
| 130 |
|
---|
| 131 | v = (vertex *)xmalloc(sizeof(vertex) + strlen(s));
|
---|
| 132 |
|
---|
| 133 | v->out = NULL;
|
---|
| 134 | strcpy(v->key,s);
|
---|
| 135 | v->indegree =
|
---|
| 136 | v->on_the_path =
|
---|
| 137 | v->has_a_cycle =
|
---|
| 138 | v->visited = 0;
|
---|
| 139 | v->next = vset;
|
---|
| 140 | vset = v;
|
---|
| 141 | return v;
|
---|
| 142 | }
|
---|
| 143 |
|
---|
| 144 | /*
|
---|
| 145 | ** readin -- read in the dependency pairs.
|
---|
| 146 | */
|
---|
| 147 | void
|
---|
| 148 | readin()
|
---|
| 149 | {
|
---|
| 150 | static char buf[128];
|
---|
| 151 | static char name[64];
|
---|
| 152 | char *bp;
|
---|
| 153 | vertex *child,*parent;
|
---|
| 154 | edge *e;
|
---|
| 155 | while(fgets(buf,sizeof(buf),stdin) != NULL) {
|
---|
| 156 | bp = buf + strlen(buf);
|
---|
| 157 | if (bp > buf && bp[-1] == '\n') *--bp = 0;
|
---|
| 158 | bp = copyupto(name,buf,' ');
|
---|
| 159 | child = add_v(name);
|
---|
| 160 | parent = add_v(bp);
|
---|
| 161 | if(child != parent && !child_of(parent,child)) {
|
---|
| 162 | e = new_edge(child);
|
---|
| 163 | e->next = parent->out;
|
---|
| 164 | parent->out = e;
|
---|
| 165 | child->indegree++;
|
---|
| 166 | }
|
---|
| 167 | }
|
---|
| 168 | }
|
---|
| 169 |
|
---|
| 170 | /*
|
---|
| 171 | ** the topological sort produces names of modules in reverse of
|
---|
| 172 | ** the order we want them in, so use a stack to hold the names
|
---|
| 173 | ** until we get them all, then pop them off to print them.
|
---|
| 174 | */
|
---|
| 175 | struct name { struct name *next; char *s; }
|
---|
| 176 | *namelist = NULL;
|
---|
| 177 |
|
---|
| 178 | void
|
---|
| 179 | pushname(s)
|
---|
| 180 | char *s;
|
---|
| 181 | {
|
---|
| 182 | struct name *x = (struct name *)xmalloc(sizeof(struct name));
|
---|
| 183 | x->s = s;
|
---|
| 184 | x->next = namelist;
|
---|
| 185 | namelist = x;
|
---|
| 186 | }
|
---|
| 187 |
|
---|
| 188 | char *
|
---|
| 189 | popname() {
|
---|
| 190 | char *rval;
|
---|
| 191 | struct name *tmp;
|
---|
| 192 | if(namelist == NULL)
|
---|
| 193 | return NULL;
|
---|
| 194 | tmp = namelist;
|
---|
| 195 | rval = namelist->s;
|
---|
| 196 | namelist = namelist->next;
|
---|
| 197 | free(tmp);
|
---|
| 198 | return rval;
|
---|
| 199 | }
|
---|
| 200 |
|
---|
| 201 | /*
|
---|
| 202 | ** topo - do a topological sort of the dependency graph.
|
---|
| 203 | */
|
---|
| 204 | void topo() {
|
---|
| 205 | vertex *x = vset,*n;
|
---|
| 206 | edge *e;
|
---|
| 207 | vertex *outq = NULL,*tmp;
|
---|
| 208 | #define insq(x) ((x->next = outq),(outq = x))
|
---|
| 209 | #define deq() ((tmp = outq),(outq = outq->next),tmp)
|
---|
| 210 |
|
---|
| 211 | /*
|
---|
| 212 | ** find all vertices that don't depend on any other vertices
|
---|
| 213 | ** Since it breaks the "next" links to insert x into the queue,
|
---|
| 214 | ** x->next is saved before insq, to resume the list traversal.
|
---|
| 215 | */
|
---|
| 216 | while (x != NULL) {
|
---|
| 217 | n = x->next;
|
---|
| 218 | if(x->indegree == 0) {
|
---|
| 219 | insq(x);
|
---|
| 220 | pushname(x->key);
|
---|
| 221 | }
|
---|
| 222 | x = n;
|
---|
| 223 | }
|
---|
| 224 |
|
---|
| 225 | /*
|
---|
| 226 | ** for each vertex V with indegree of zero,
|
---|
| 227 | ** for each edge E from vertex V
|
---|
| 228 | ** subtract one from the indegree of the vertex V'
|
---|
| 229 | ** pointed to by E. If V' now has an indegree of zero,
|
---|
| 230 | ** add it to the set of vertices with indegree zero, and
|
---|
| 231 | ** push its name on the output stack.
|
---|
| 232 | */
|
---|
| 233 | while(outq != NULL) {
|
---|
| 234 | x = deq();
|
---|
| 235 | e = x->out;
|
---|
| 236 | while(e != NULL) {
|
---|
| 237 | if(--(e->v->indegree) == 0) {
|
---|
| 238 | insq(e->v);
|
---|
| 239 | pushname(e->v->key);
|
---|
| 240 | }
|
---|
| 241 | e = e->next;
|
---|
| 242 | }
|
---|
| 243 | }
|
---|
| 244 |
|
---|
| 245 | /*
|
---|
| 246 | ** print the vertex names in opposite of the order they were
|
---|
| 247 | ** encountered.
|
---|
| 248 | */
|
---|
| 249 | while(namelist != NULL)
|
---|
| 250 | puts(popname());
|
---|
| 251 | }
|
---|
| 252 |
|
---|
| 253 | /*
|
---|
| 254 | ** print_cycle --
|
---|
| 255 | ** A cycle has been detected between parent and child.
|
---|
| 256 | ** Start with the child, and look at each of its edges for
|
---|
| 257 | ** the parent.
|
---|
| 258 | **
|
---|
| 259 | ** We know a vertex is on the path from the child to the parent
|
---|
| 260 | ** because the depth-first search sets on_the_path true for each
|
---|
| 261 | ** vertex it visits.
|
---|
| 262 | */
|
---|
| 263 | void
|
---|
| 264 | print_cycle(parent,child)
|
---|
| 265 | vertex *parent, *child;
|
---|
| 266 | {
|
---|
| 267 | char *s;
|
---|
| 268 | vertex *x;
|
---|
| 269 | edge *e;
|
---|
| 270 | for(x = child; x != parent; ) {
|
---|
| 271 | pushname(x->key);
|
---|
| 272 | for(e = x->out; e != NULL; e = e->next) {
|
---|
| 273 | /*
|
---|
| 274 | ** stop looking for the path at the first node found
|
---|
| 275 | ** that's on the path. Watch out for cycles already
|
---|
| 276 | ** detected, because if you follow an edge into a cycle,
|
---|
| 277 | ** you're stuck in an infinite loop!
|
---|
| 278 | */
|
---|
| 279 | if(e->v->on_the_path && !e->v->has_a_cycle) {
|
---|
| 280 | x = e->v;
|
---|
| 281 | break;
|
---|
| 282 | }
|
---|
| 283 | }
|
---|
| 284 | }
|
---|
| 285 | /*
|
---|
| 286 | ** print the name of the parent, and then names of each of the
|
---|
| 287 | ** vertices on the path from the child to the parent.
|
---|
| 288 | */
|
---|
| 289 | fprintf(stderr,"%s\n",x->key);
|
---|
| 290 | while((s = popname()) != NULL)
|
---|
| 291 | fprintf(stderr,"%s\n",s);
|
---|
| 292 | }
|
---|
| 293 |
|
---|
| 294 | /*
|
---|
| 295 | ** depth first search for cycles in the dependency graph.
|
---|
| 296 | ** See "Introduction to Algorithms" by Udi Manber Addison-Wesley 1989
|
---|
| 297 | */
|
---|
| 298 | void
|
---|
| 299 | dfs(v)
|
---|
| 300 | vertex *v;
|
---|
| 301 | {
|
---|
| 302 | edge *e;
|
---|
| 303 |
|
---|
| 304 | if(v->visited) /* If you've been here before, don't go again! */
|
---|
| 305 | return;
|
---|
| 306 | v->visited++;
|
---|
| 307 | v->on_the_path++; /* this node is on the path from the root. */
|
---|
| 308 |
|
---|
| 309 | /*
|
---|
| 310 | ** depth-first search all outgoing edges.
|
---|
| 311 | */
|
---|
| 312 | for(e = v->out; e != NULL; e = e->next) {
|
---|
| 313 | if(!e->v->visited)
|
---|
| 314 | dfs(e->v);
|
---|
| 315 | if(e->v->on_the_path) {
|
---|
| 316 | fprintf(stderr,"cycle found between %s and %s\n",
|
---|
| 317 | v->key,e->v->key);
|
---|
| 318 | print_cycle(v,e->v);
|
---|
| 319 | v->has_a_cycle++;
|
---|
| 320 | }
|
---|
| 321 | }
|
---|
| 322 | v->on_the_path = 0;
|
---|
| 323 | }
|
---|
| 324 |
|
---|
| 325 | /*
|
---|
| 326 | ** check cycles starts the recursive depth-first search from
|
---|
| 327 | ** each vertex in vset.
|
---|
| 328 | */
|
---|
| 329 | void
|
---|
| 330 | check_cycles()
|
---|
| 331 | {
|
---|
| 332 | vertex *v;
|
---|
| 333 | for(v = vset; v != NULL; v = v->next)
|
---|
| 334 | dfs(v);
|
---|
| 335 | }
|
---|
| 336 |
|
---|
| 337 | /*
|
---|
| 338 | ** main program.
|
---|
| 339 | */
|
---|
| 340 | int main(argc,argv)
|
---|
| 341 | int argc;
|
---|
| 342 | char **argv;
|
---|
| 343 | {
|
---|
| 344 | if(argc > 1 && freopen(argv[1],"r",stdin) == NULL) {
|
---|
| 345 | perror(argv[1]);
|
---|
| 346 | exit(0);
|
---|
| 347 | }
|
---|
| 348 | if(argc > 2 && freopen(argv[2],"w",stdout) == NULL) {
|
---|
| 349 | perror(argv[2]);
|
---|
| 350 | exit(0);
|
---|
| 351 | }
|
---|
| 352 | readin();
|
---|
| 353 | check_cycles();
|
---|
| 354 | topo();
|
---|
| 355 | return(0);
|
---|
| 356 | }
|
---|