Date:2010-04-26 17:18:01 (9 years 3 months ago)
Author:werner
Commit:190bcaf982869388b508a0a4c97cff62fbb73038
Message:Added a topological sort algorithm, for use when dumping.

- tsort.h, tsort.c, Makefile: stable topological sort with priorities
- fpd.l, fpd.y: added directive %tsort to test-drive the sort algorithm
- README: documented %tsort



git-svn-id: http://svn.openmoko.org/trunk/eda/fped@5942 99fdad57-331a-0410-800a-d7fa5415bdb3
Files: Makefile (1 diff)
README (2 diffs)
TODO (1 diff)
fpd.l (1 diff)
fpd.y (4 diffs)
tsort.c (1 diff)
tsort.h (1 diff)

Change Details

Makefile
1616
1717OBJS = fped.o expr.o coord.o obj.o delete.o inst.o util.o error.o \
1818       unparse.o file.o dump.o kicad.o postscript.o meas.o \
19       layer.o overlap.o hole.o \
19       layer.o overlap.o hole.o tsort.o \
2020       cpp.o lex.yy.o y.tab.o \
2121       gui.o gui_util.o gui_style.o gui_inst.o gui_status.o gui_canvas.o \
2222       gui_tool.o gui_over.o gui_meas.o gui_frame.o gui_frame_drag.o
README
582582Experimental: debugging directives
583583----------------------------------
584584
585For debugging and regression tests, fped supports the following commands
586that mimick the effect of GUI operations:
585For debugging and regression tests, fped supports the following commands,
586most of which mimick the effect of GUI operations:
587587
588588%del <identifier>
589589%move <identifier> [<number>] <identifier>
590590%print <expression>
591591%dump
592592%exit
593%tsort { -<id> | +<id> | <id-before> <id-after> [<number>] ... }
593594
594595%del and %move take as their first argument the name of the vector or
595596object to manipulate. For this purpose, also objects can be labeled.
...... 
608609
609610%dump writes the footprint definition in the fped language to standard
610611output. %exit immediately exits fped, without invoking the GUI.
612
613%tsort is used to test-drive the topological sort algorithm. The items
614in the curly braces are declarations of nodes with (-<id>) or without
615(+<id>) decay or edges in the partial order. The optional number is
616the edge's priority. See tsort.c for details.
TODO
6969- live update of value when entering strings and expressions ?
7070- advanced: non-standard solder mask
7171- advanced: solder paste exceptions (subtractive, additive)
72- advanced: holes
7372- advanced: silk line width
7473- future: consider editing non-canvas items (e.g., variable names/values) in
7574  place
fpd.l
133133                  return TOK_DBG_DUMP; }
134134<INITIAL>"%exit" { BEGIN(NOKEYWORD);
135135                  return TOK_DBG_EXIT; }
136<INITIAL>"%tsort" { BEGIN(NOKEYWORD);
137                  return TOK_DBG_TSORT; }
136138
137139<INITIAL>[a-zA-Z_][a-zA-Z_0-9]*: { *strchr(yytext, ':') = 0;
138140                  yylval.id = unique(yytext);
fpd.y
2222#include "meas.h"
2323#include "gui_status.h"
2424#include "dump.h"
25#include "tsort.h"
2526#include "fpd.h"
2627
2728
...... 
4647
4748static const char *id_sin, *id_cos, *id_sqrt;
4849
50static struct tsort *tsort;
51
4952
5053static struct frame *find_frame(const char *name)
5154{
...... 
289292%token TOK_MEAS TOK_MEASX TOK_MEASY TOK_UNIT
290293%token TOK_NEXT TOK_NEXT_INVERTED TOK_MAX TOK_MAX_INVERTED
291294%token TOK_DBG_DEL TOK_DBG_MOVE TOK_DBG_PRINT TOK_DBG_DUMP
292%token TOK_DBG_EXIT
295%token TOK_DBG_EXIT TOK_DBG_TSORT
293296
294297%token <num> NUMBER
295298%token <str> STRING
...... 
481484        {
482485            exit(0);
483486        }
487    | TOK_DBG_TSORT '{'
488        {
489            tsort = begin_tsort();
490        }
491        sort_items '}'
492        {
493            void **sort, **walk;
494
495            sort = end_tsort(tsort);
496            for (walk = sort; *walk; walk++)
497                printf("%s\n", (char *) *walk);
498            free(sort);
499        }
500    ;
501
502sort_items:
503    | sort_items '+' ID
504        {
505            add_node(tsort, (void *) $3, 0);
506        }
507    | sort_items '-' ID
508        {
509            add_node(tsort, (void *) $3, 1);
510        }
511    | sort_items ID ID opt_num
512        {
513            struct node *a, *b;
514
515            /* order is important here ! */
516            a = add_node(tsort, (void *) $2, 0);
517            b = add_node(tsort, (void *) $3, 0);
518            add_edge(a, b, $4.n);
519        }
484520    ;
485521
486522table:
tsort.c
1/*
2 * tsort.c - Topological sort
3 *
4 * Written 2010 by Werner Almesberger
5 * Copyright 2010 by Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13/*
14 * We use a slight variation of Kahn's algorithm. The difference is that we add
15 * a priority. Edges with the highest priority get selected before edges with
16 * lower priority.
17 *
18 * We maintain the initial list of nodes in the order in which they were added.
19 * Therefore, the first node with inbound edges will always be sorted first.
20 * E.g., the root frame.
21 *
22 * add_node and add_edge can be invoked multiple times with the same
23 * parameters. In the case of add_node, simply the existing node is returned.
24 * In the case of add_edge, the new edge's priority is added to the priority of
25 * the previous edges.
26 *
27 * Priority is accumulated in a node until the node is output. If a node has
28 * the "decay" flag set, it resets the priorities of all other nodes when
29 * output. E.g., when outputting a vector, all priorities accumulated from
30 * previous vectors (towards referencing them with ".") lose their effect.
31 *
32 * Last but not least, the algorithm is stable: a pre-existing order that
33 * conflicts neither with the partial order nor the priorities is preserved.
34 *
35 * Thus, we have the following sorting criteria, in decreasing importance:
36 * - the destination if an edge never precedes its origin
37 * - higher priority comes before lower priority
38 * - earlier add_node comes before later
39 */
40
41
42#include <stdlib.h>
43#include <stdio.h>
44#include <limits.h>
45
46#include "util.h"
47#include "tsort.h"
48
49
50struct edge {
51    struct node *to;
52    int priority; /* edge priority */
53    struct edge *next;
54};
55
56struct node {
57    void *user;
58    struct edge *edges; /* outbound edges */
59    int incoming; /* number of incoming edges */
60    int priority; /* cumulative node priority */
61    int decay; /* all node prio. decay after issuing this */
62    struct node *next;
63};
64
65struct tsort {
66    struct node *nodes;
67    struct node **next_node;
68    int n_nodes;
69};
70
71
72void add_edge(struct node *from, struct node *to, int priority)
73{
74    struct edge **edge;
75
76    for (edge = &from->edges; *edge; edge = &(*edge)->next)
77        if ((*edge)->to == to) {
78            (*edge)->priority += priority;
79            return;
80        }
81    *edge = alloc_type(struct edge);
82    (*edge)->to = to;
83    (*edge)->priority = priority;
84    (*edge)->next = NULL;
85    to->incoming++;
86}
87
88
89struct node *add_node(struct tsort *tsort, void *user, int decay)
90{
91    struct node *node;
92
93    for (node = tsort->nodes; node; node = node->next)
94        if (node->user == user)
95            return node;
96    node = alloc_type(struct node);
97    node->user = user;
98    node->edges = NULL;
99    node->incoming = 0;
100    node->priority = 0;
101    node->decay = decay;
102    node->next = NULL;
103    *tsort->next_node = node;
104    tsort->next_node = &node->next;
105    tsort->n_nodes++;
106    return node;
107}
108
109
110struct tsort *begin_tsort(void)
111{
112    struct tsort *tsort;
113
114    tsort = alloc_type(struct tsort);
115    tsort->nodes = NULL;
116    tsort->next_node = &tsort->nodes;
117    tsort->n_nodes = 0;
118    return tsort;
119}
120
121
122void **end_tsort(struct tsort *tsort)
123{
124    struct node **walk, **first, *node;
125    struct edge *edge;
126    void **res;
127    int n = 0;
128
129    res = alloc_size(sizeof(void *)*(tsort->n_nodes+1));
130    while (1) {
131        first = NULL;
132        for (walk = &tsort->nodes; *walk; walk = &(*walk)->next) {
133            if ((*walk)->incoming)
134                continue;
135            if (!first || (*first)->priority < (*walk)->priority)
136                first = walk;
137        }
138        if (!first)
139            break;
140        if ((*first)->decay)
141            for (node = tsort->nodes; node; node = node->next)
142                node->priority = 0;
143        node = *first;
144        *first = node->next;
145        res[n++] = node->user;
146        while (node->edges) {
147            edge = node->edges;
148            edge->to->incoming--;
149            edge->to->priority += edge->priority;
150            node->edges = edge->next;
151            free(edge);
152        }
153        free(node);
154    }
155    if (tsort->nodes) /* we have at least one cycle */
156        abort();
157    free(tsort);
158    res[n] = NULL;
159    return res;
160}
tsort.h
1/*
2 * tsort.h - Topological sort
3 *
4 * Written 2010 by Werner Almesberger
5 * Copyright 2010 by Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#ifndef TSORT_H
14#define TSORT_H
15
16struct node;
17struct tsort;
18
19struct node *add_node(struct tsort *tsort, void *user, int decay);
20void add_edge(struct node *from, struct node *to, int priority);
21
22struct tsort *begin_tsort(void);
23void **end_tsort(struct tsort *tsort);
24
25#endif /* !TSORT_H */

Archive Download the corresponding diff file

Branches:
master



interactive