mirror of
git://projects.qi-hardware.com/fped.git
synced 2024-11-22 01:36:14 +02:00
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
This commit is contained in:
parent
e047cc074d
commit
190bcaf982
2
Makefile
2
Makefile
@ -16,7 +16,7 @@ UPLOAD = werner@sita.openmoko.org:public_html/fped/
|
|||||||
|
|
||||||
OBJS = fped.o expr.o coord.o obj.o delete.o inst.o util.o error.o \
|
OBJS = fped.o expr.o coord.o obj.o delete.o inst.o util.o error.o \
|
||||||
unparse.o file.o dump.o kicad.o postscript.o meas.o \
|
unparse.o file.o dump.o kicad.o postscript.o meas.o \
|
||||||
layer.o overlap.o hole.o \
|
layer.o overlap.o hole.o tsort.o \
|
||||||
cpp.o lex.yy.o y.tab.o \
|
cpp.o lex.yy.o y.tab.o \
|
||||||
gui.o gui_util.o gui_style.o gui_inst.o gui_status.o gui_canvas.o \
|
gui.o gui_util.o gui_style.o gui_inst.o gui_status.o gui_canvas.o \
|
||||||
gui_tool.o gui_over.o gui_meas.o gui_frame.o gui_frame_drag.o
|
gui_tool.o gui_over.o gui_meas.o gui_frame.o gui_frame_drag.o
|
||||||
|
10
README
10
README
@ -582,14 +582,15 @@ would print "width = 1mm"
|
|||||||
Experimental: debugging directives
|
Experimental: debugging directives
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
For debugging and regression tests, fped supports the following commands
|
For debugging and regression tests, fped supports the following commands,
|
||||||
that mimick the effect of GUI operations:
|
most of which mimick the effect of GUI operations:
|
||||||
|
|
||||||
%del <identifier>
|
%del <identifier>
|
||||||
%move <identifier> [<number>] <identifier>
|
%move <identifier> [<number>] <identifier>
|
||||||
%print <expression>
|
%print <expression>
|
||||||
%dump
|
%dump
|
||||||
%exit
|
%exit
|
||||||
|
%tsort { -<id> | +<id> | <id-before> <id-after> [<number>] ... }
|
||||||
|
|
||||||
%del and %move take as their first argument the name of the vector or
|
%del and %move take as their first argument the name of the vector or
|
||||||
object to manipulate. For this purpose, also objects can be labeled.
|
object to manipulate. For this purpose, also objects can be labeled.
|
||||||
@ -608,3 +609,8 @@ anchor index vec/frame line/rect/pad arc measurement
|
|||||||
|
|
||||||
%dump writes the footprint definition in the fped language to standard
|
%dump writes the footprint definition in the fped language to standard
|
||||||
output. %exit immediately exits fped, without invoking the GUI.
|
output. %exit immediately exits fped, without invoking the GUI.
|
||||||
|
|
||||||
|
%tsort is used to test-drive the topological sort algorithm. The items
|
||||||
|
in the curly braces are declarations of nodes with (-<id>) or without
|
||||||
|
(+<id>) decay or edges in the partial order. The optional number is
|
||||||
|
the edge's priority. See tsort.c for details.
|
||||||
|
1
TODO
1
TODO
@ -69,7 +69,6 @@ Future directions:
|
|||||||
- live update of value when entering strings and expressions ?
|
- live update of value when entering strings and expressions ?
|
||||||
- advanced: non-standard solder mask
|
- advanced: non-standard solder mask
|
||||||
- advanced: solder paste exceptions (subtractive, additive)
|
- advanced: solder paste exceptions (subtractive, additive)
|
||||||
- advanced: holes
|
|
||||||
- advanced: silk line width
|
- advanced: silk line width
|
||||||
- future: consider editing non-canvas items (e.g., variable names/values) in
|
- future: consider editing non-canvas items (e.g., variable names/values) in
|
||||||
place
|
place
|
||||||
|
2
fpd.l
2
fpd.l
@ -133,6 +133,8 @@ SP [\t ]*
|
|||||||
return TOK_DBG_DUMP; }
|
return TOK_DBG_DUMP; }
|
||||||
<INITIAL>"%exit" { BEGIN(NOKEYWORD);
|
<INITIAL>"%exit" { BEGIN(NOKEYWORD);
|
||||||
return TOK_DBG_EXIT; }
|
return TOK_DBG_EXIT; }
|
||||||
|
<INITIAL>"%tsort" { BEGIN(NOKEYWORD);
|
||||||
|
return TOK_DBG_TSORT; }
|
||||||
|
|
||||||
<INITIAL>[a-zA-Z_][a-zA-Z_0-9]*: { *strchr(yytext, ':') = 0;
|
<INITIAL>[a-zA-Z_][a-zA-Z_0-9]*: { *strchr(yytext, ':') = 0;
|
||||||
yylval.id = unique(yytext);
|
yylval.id = unique(yytext);
|
||||||
|
38
fpd.y
38
fpd.y
@ -22,6 +22,7 @@
|
|||||||
#include "meas.h"
|
#include "meas.h"
|
||||||
#include "gui_status.h"
|
#include "gui_status.h"
|
||||||
#include "dump.h"
|
#include "dump.h"
|
||||||
|
#include "tsort.h"
|
||||||
#include "fpd.h"
|
#include "fpd.h"
|
||||||
|
|
||||||
|
|
||||||
@ -46,6 +47,8 @@ static int n_vars, n_values;
|
|||||||
|
|
||||||
static const char *id_sin, *id_cos, *id_sqrt;
|
static const char *id_sin, *id_cos, *id_sqrt;
|
||||||
|
|
||||||
|
static struct tsort *tsort;
|
||||||
|
|
||||||
|
|
||||||
static struct frame *find_frame(const char *name)
|
static struct frame *find_frame(const char *name)
|
||||||
{
|
{
|
||||||
@ -289,7 +292,7 @@ static void append_root_frame(void)
|
|||||||
%token TOK_MEAS TOK_MEASX TOK_MEASY TOK_UNIT
|
%token TOK_MEAS TOK_MEASX TOK_MEASY TOK_UNIT
|
||||||
%token TOK_NEXT TOK_NEXT_INVERTED TOK_MAX TOK_MAX_INVERTED
|
%token TOK_NEXT TOK_NEXT_INVERTED TOK_MAX TOK_MAX_INVERTED
|
||||||
%token TOK_DBG_DEL TOK_DBG_MOVE TOK_DBG_PRINT TOK_DBG_DUMP
|
%token TOK_DBG_DEL TOK_DBG_MOVE TOK_DBG_PRINT TOK_DBG_DUMP
|
||||||
%token TOK_DBG_EXIT
|
%token TOK_DBG_EXIT TOK_DBG_TSORT
|
||||||
|
|
||||||
%token <num> NUMBER
|
%token <num> NUMBER
|
||||||
%token <str> STRING
|
%token <str> STRING
|
||||||
@ -481,6 +484,39 @@ debug_item:
|
|||||||
{
|
{
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
| TOK_DBG_TSORT '{'
|
||||||
|
{
|
||||||
|
tsort = begin_tsort();
|
||||||
|
}
|
||||||
|
sort_items '}'
|
||||||
|
{
|
||||||
|
void **sort, **walk;
|
||||||
|
|
||||||
|
sort = end_tsort(tsort);
|
||||||
|
for (walk = sort; *walk; walk++)
|
||||||
|
printf("%s\n", (char *) *walk);
|
||||||
|
free(sort);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
sort_items:
|
||||||
|
| sort_items '+' ID
|
||||||
|
{
|
||||||
|
add_node(tsort, (void *) $3, 0);
|
||||||
|
}
|
||||||
|
| sort_items '-' ID
|
||||||
|
{
|
||||||
|
add_node(tsort, (void *) $3, 1);
|
||||||
|
}
|
||||||
|
| sort_items ID ID opt_num
|
||||||
|
{
|
||||||
|
struct node *a, *b;
|
||||||
|
|
||||||
|
/* order is important here ! */
|
||||||
|
a = add_node(tsort, (void *) $2, 0);
|
||||||
|
b = add_node(tsort, (void *) $3, 0);
|
||||||
|
add_edge(a, b, $4.n);
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
table:
|
table:
|
||||||
|
160
tsort.c
Normal file
160
tsort.c
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* tsort.c - Topological sort
|
||||||
|
*
|
||||||
|
* Written 2010 by Werner Almesberger
|
||||||
|
* Copyright 2010 by Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use a slight variation of Kahn's algorithm. The difference is that we add
|
||||||
|
* a priority. Edges with the highest priority get selected before edges with
|
||||||
|
* lower priority.
|
||||||
|
*
|
||||||
|
* We maintain the initial list of nodes in the order in which they were added.
|
||||||
|
* Therefore, the first node with inbound edges will always be sorted first.
|
||||||
|
* E.g., the root frame.
|
||||||
|
*
|
||||||
|
* add_node and add_edge can be invoked multiple times with the same
|
||||||
|
* parameters. In the case of add_node, simply the existing node is returned.
|
||||||
|
* In the case of add_edge, the new edge's priority is added to the priority of
|
||||||
|
* the previous edges.
|
||||||
|
*
|
||||||
|
* Priority is accumulated in a node until the node is output. If a node has
|
||||||
|
* the "decay" flag set, it resets the priorities of all other nodes when
|
||||||
|
* output. E.g., when outputting a vector, all priorities accumulated from
|
||||||
|
* previous vectors (towards referencing them with ".") lose their effect.
|
||||||
|
*
|
||||||
|
* Last but not least, the algorithm is stable: a pre-existing order that
|
||||||
|
* conflicts neither with the partial order nor the priorities is preserved.
|
||||||
|
*
|
||||||
|
* Thus, we have the following sorting criteria, in decreasing importance:
|
||||||
|
* - the destination if an edge never precedes its origin
|
||||||
|
* - higher priority comes before lower priority
|
||||||
|
* - earlier add_node comes before later
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "tsort.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct edge {
|
||||||
|
struct node *to;
|
||||||
|
int priority; /* edge priority */
|
||||||
|
struct edge *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct node {
|
||||||
|
void *user;
|
||||||
|
struct edge *edges; /* outbound edges */
|
||||||
|
int incoming; /* number of incoming edges */
|
||||||
|
int priority; /* cumulative node priority */
|
||||||
|
int decay; /* all node prio. decay after issuing this */
|
||||||
|
struct node *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tsort {
|
||||||
|
struct node *nodes;
|
||||||
|
struct node **next_node;
|
||||||
|
int n_nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void add_edge(struct node *from, struct node *to, int priority)
|
||||||
|
{
|
||||||
|
struct edge **edge;
|
||||||
|
|
||||||
|
for (edge = &from->edges; *edge; edge = &(*edge)->next)
|
||||||
|
if ((*edge)->to == to) {
|
||||||
|
(*edge)->priority += priority;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*edge = alloc_type(struct edge);
|
||||||
|
(*edge)->to = to;
|
||||||
|
(*edge)->priority = priority;
|
||||||
|
(*edge)->next = NULL;
|
||||||
|
to->incoming++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct node *add_node(struct tsort *tsort, void *user, int decay)
|
||||||
|
{
|
||||||
|
struct node *node;
|
||||||
|
|
||||||
|
for (node = tsort->nodes; node; node = node->next)
|
||||||
|
if (node->user == user)
|
||||||
|
return node;
|
||||||
|
node = alloc_type(struct node);
|
||||||
|
node->user = user;
|
||||||
|
node->edges = NULL;
|
||||||
|
node->incoming = 0;
|
||||||
|
node->priority = 0;
|
||||||
|
node->decay = decay;
|
||||||
|
node->next = NULL;
|
||||||
|
*tsort->next_node = node;
|
||||||
|
tsort->next_node = &node->next;
|
||||||
|
tsort->n_nodes++;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct tsort *begin_tsort(void)
|
||||||
|
{
|
||||||
|
struct tsort *tsort;
|
||||||
|
|
||||||
|
tsort = alloc_type(struct tsort);
|
||||||
|
tsort->nodes = NULL;
|
||||||
|
tsort->next_node = &tsort->nodes;
|
||||||
|
tsort->n_nodes = 0;
|
||||||
|
return tsort;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void **end_tsort(struct tsort *tsort)
|
||||||
|
{
|
||||||
|
struct node **walk, **first, *node;
|
||||||
|
struct edge *edge;
|
||||||
|
void **res;
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
res = alloc_size(sizeof(void *)*(tsort->n_nodes+1));
|
||||||
|
while (1) {
|
||||||
|
first = NULL;
|
||||||
|
for (walk = &tsort->nodes; *walk; walk = &(*walk)->next) {
|
||||||
|
if ((*walk)->incoming)
|
||||||
|
continue;
|
||||||
|
if (!first || (*first)->priority < (*walk)->priority)
|
||||||
|
first = walk;
|
||||||
|
}
|
||||||
|
if (!first)
|
||||||
|
break;
|
||||||
|
if ((*first)->decay)
|
||||||
|
for (node = tsort->nodes; node; node = node->next)
|
||||||
|
node->priority = 0;
|
||||||
|
node = *first;
|
||||||
|
*first = node->next;
|
||||||
|
res[n++] = node->user;
|
||||||
|
while (node->edges) {
|
||||||
|
edge = node->edges;
|
||||||
|
edge->to->incoming--;
|
||||||
|
edge->to->priority += edge->priority;
|
||||||
|
node->edges = edge->next;
|
||||||
|
free(edge);
|
||||||
|
}
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
if (tsort->nodes) /* we have at least one cycle */
|
||||||
|
abort();
|
||||||
|
free(tsort);
|
||||||
|
res[n] = NULL;
|
||||||
|
return res;
|
||||||
|
}
|
25
tsort.h
Normal file
25
tsort.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* tsort.h - Topological sort
|
||||||
|
*
|
||||||
|
* Written 2010 by Werner Almesberger
|
||||||
|
* Copyright 2010 by Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TSORT_H
|
||||||
|
#define TSORT_H
|
||||||
|
|
||||||
|
struct node;
|
||||||
|
struct tsort;
|
||||||
|
|
||||||
|
struct node *add_node(struct tsort *tsort, void *user, int decay);
|
||||||
|
void add_edge(struct node *from, struct node *to, int priority);
|
||||||
|
|
||||||
|
struct tsort *begin_tsort(void);
|
||||||
|
void **end_tsort(struct tsort *tsort);
|
||||||
|
|
||||||
|
#endif /* !TSORT_H */
|
Loading…
Reference in New Issue
Block a user