1
0
mirror of git://projects.qi-hardware.com/fped.git synced 2024-11-22 08:51:53 +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:
werner 2010-04-26 15:18:01 +00:00
parent e047cc074d
commit 190bcaf982
7 changed files with 233 additions and 5 deletions

View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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
View 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
View 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 */