2015-09-27 11:50:18 +00:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
|
|
|
#include <bio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
typedef struct Symbol Symbol;
|
|
|
|
typedef struct Event Event;
|
|
|
|
typedef struct Signal Signal;
|
|
|
|
|
|
|
|
struct Symbol {
|
|
|
|
char *name;
|
|
|
|
int t;
|
|
|
|
double e;
|
|
|
|
Symbol *next;
|
|
|
|
};
|
|
|
|
struct Event {
|
|
|
|
double t;
|
|
|
|
int val;
|
|
|
|
Event *next;
|
|
|
|
char *data;
|
|
|
|
int line;
|
|
|
|
};
|
|
|
|
struct Signal {
|
|
|
|
char *name;
|
|
|
|
Event *ev;
|
|
|
|
Signal *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
int lineno, lastc, peeked;
|
|
|
|
char sname[512];
|
|
|
|
double sval;
|
|
|
|
double width, rheight;
|
|
|
|
double mint, maxt;
|
|
|
|
double left, right;
|
|
|
|
int nsig;
|
|
|
|
Biobuf *bp;
|
|
|
|
Symbol *stab[256];
|
|
|
|
Signal *sigfirst, **siglast = &sigfirst;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
SYMFREE,
|
|
|
|
SYMNUM,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
VZ,
|
|
|
|
VX,
|
|
|
|
VL,
|
|
|
|
VH,
|
|
|
|
VMULT,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
CMD = -1,
|
|
|
|
SYM = -2,
|
|
|
|
NUM = -3,
|
|
|
|
EOF = -4,
|
2015-09-29 18:49:28 +00:00
|
|
|
STR = -5,
|
2015-09-27 11:50:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
Tfmt(Fmt *f)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
n = va_arg(f->args, int);
|
|
|
|
if(n >= 0 && n < 0x80 && isprint(n))
|
|
|
|
return fmtprint(f, "'%c'", n);
|
|
|
|
else
|
|
|
|
switch(n){
|
|
|
|
case CMD: return fmtprint(f, ".%s", sname);
|
|
|
|
case SYM: return fmtprint(f, "'%s'", sname);
|
|
|
|
case NUM: return fmtprint(f, "%g", sval);
|
|
|
|
case EOF: return fmtprint(f, "EOF");
|
2015-09-29 18:49:28 +00:00
|
|
|
case STR: return fmtprint(f, "%#q", sname);
|
2015-09-27 11:50:18 +00:00
|
|
|
default: return fmtprint(f, "%d", n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
emalloc(int n)
|
|
|
|
{
|
|
|
|
void *v;
|
|
|
|
|
|
|
|
v = malloc(n);
|
|
|
|
if(v == nil)
|
|
|
|
sysfatal("malloc: %r");
|
|
|
|
memset(v, 0, n);
|
|
|
|
setmalloctag(v, getcallerpc(&n));
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
error(int l, char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list va;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
va_start(va, fmt);
|
|
|
|
s = vsmprint(fmt, va);
|
|
|
|
fprint(2, "%d %s\n", l, s);
|
|
|
|
free(s);
|
|
|
|
va_end(va);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
hash(char *s)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
|
|
|
for(c = 0; *s != 0; s++)
|
|
|
|
c += *s;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Symbol *
|
|
|
|
getsym(char *st)
|
|
|
|
{
|
|
|
|
Symbol *s, **p;
|
|
|
|
|
|
|
|
for(p = &stab[hash(st)%nelem(stab)]; s = *p, s != nil; p = &s->next){
|
|
|
|
if(strcmp(s->name, st) == 0)
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
s = emalloc(sizeof(Symbol));
|
|
|
|
s->name = strdup(st);
|
|
|
|
*p = s;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
issym(int c)
|
|
|
|
{
|
|
|
|
return isalnum(c) || c == '_' || c >= 0x80;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
numfsm(int c, int *st)
|
|
|
|
{
|
|
|
|
enum {
|
|
|
|
PREDOT,
|
|
|
|
POSTDOT,
|
|
|
|
ESIGN,
|
|
|
|
EDIG
|
|
|
|
};
|
|
|
|
|
|
|
|
switch(*st){
|
|
|
|
case PREDOT:
|
|
|
|
if(c == '.')
|
|
|
|
*st = POSTDOT;
|
|
|
|
if(c == 'e')
|
|
|
|
*st = ESIGN;
|
|
|
|
return isdigit(c) || c == '.' || c == 'e';
|
|
|
|
case POSTDOT:
|
|
|
|
if(c == 'e')
|
|
|
|
*st = ESIGN;
|
|
|
|
return isdigit(c) || c == 'e';
|
|
|
|
case ESIGN:
|
|
|
|
*st = EDIG;
|
|
|
|
return isdigit(c) || c == '+' || c == '-';
|
|
|
|
case EDIG:
|
|
|
|
return isdigit(c);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
lex(void)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
char *p;
|
|
|
|
int st;
|
|
|
|
|
|
|
|
do{
|
|
|
|
c = Bgetc(bp);
|
|
|
|
if(c < 0)
|
|
|
|
return EOF;
|
|
|
|
if(!isspace(c))
|
|
|
|
break;
|
|
|
|
if(c == '\n')
|
|
|
|
lineno++;
|
|
|
|
lastc = c;
|
|
|
|
}while(1);
|
|
|
|
|
|
|
|
if(lastc == 10 && c == '.'){
|
|
|
|
for(p = sname; c = Bgetc(bp), issym(c); )
|
|
|
|
if(p < sname + sizeof(sname) - 1)
|
|
|
|
*p++ = c;
|
|
|
|
Bungetc(bp);
|
|
|
|
*p = 0;
|
|
|
|
return CMD;
|
|
|
|
}
|
|
|
|
if(isdigit(c) || c == '.'){
|
|
|
|
st = 0;
|
|
|
|
for(p = sname; numfsm(c, &st); c = Bgetc(bp))
|
|
|
|
if(p < sname + sizeof(sname) - 1)
|
|
|
|
*p++ = c;
|
|
|
|
Bungetc(bp);
|
|
|
|
*p = 0;
|
|
|
|
sval = strtol(sname, &p, 0);
|
|
|
|
if(*p != 0)
|
|
|
|
sval = strtod(sname, &p);
|
|
|
|
if(*p != 0)
|
|
|
|
error(lineno, "invalid number %s", sname);
|
|
|
|
return NUM;
|
|
|
|
}
|
|
|
|
if(issym(c)){
|
|
|
|
for(p = sname; issym(c); c = Bgetc(bp))
|
|
|
|
if(p < sname + sizeof(sname) - 1)
|
|
|
|
*p++ = c;
|
|
|
|
Bungetc(bp);
|
|
|
|
*p = 0;
|
|
|
|
return SYM;
|
|
|
|
}
|
2015-09-29 18:49:28 +00:00
|
|
|
if(c == '\''){
|
|
|
|
for(p = sname; c = Bgetc(bp), c != '\'' || Bgetc(bp) == '\''; )
|
|
|
|
if(p < sname + sizeof(sname) - 1)
|
|
|
|
*p++ = c;
|
|
|
|
Bungetc(bp);
|
|
|
|
*p = 0;
|
|
|
|
return STR;
|
|
|
|
}
|
2015-09-27 11:50:18 +00:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
next(void)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if(peeked != 0){
|
|
|
|
rc = peeked;
|
|
|
|
peeked = 0;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
return lex();
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
peek(void)
|
|
|
|
{
|
|
|
|
if(peeked == 0)
|
|
|
|
peeked = lex();
|
|
|
|
return peeked;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
expect(int n)
|
|
|
|
{
|
|
|
|
int s;
|
|
|
|
|
|
|
|
if((s = peek()) != n)
|
|
|
|
error(lineno, "expected %T, got %T", n, s);
|
|
|
|
else
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
|
|
|
|
static double expr(void);
|
|
|
|
|
|
|
|
static double
|
|
|
|
factor(void)
|
|
|
|
{
|
|
|
|
int t;
|
|
|
|
double g;
|
|
|
|
Symbol *s;
|
|
|
|
|
|
|
|
switch(t = next()){
|
|
|
|
case NUM:
|
|
|
|
return sval;
|
|
|
|
case SYM:
|
|
|
|
s = getsym(sname);
|
|
|
|
if(s->t != SYMNUM)
|
|
|
|
error(lineno, "not a number: %s", s->name);
|
|
|
|
return s->e;
|
|
|
|
case '(':
|
|
|
|
g = expr();
|
|
|
|
expect(')');
|
|
|
|
return g;
|
|
|
|
default:
|
|
|
|
error(lineno, "factor: unexpected %T", t);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static double
|
|
|
|
term(void)
|
|
|
|
{
|
|
|
|
double g;
|
|
|
|
|
|
|
|
g = factor();
|
|
|
|
while(peek() == '*' || peek() == '/'){
|
|
|
|
switch(next()){
|
|
|
|
case '*': g *= factor(); break;
|
|
|
|
case '/': g /= factor(); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return g;
|
|
|
|
}
|
|
|
|
|
|
|
|
static double
|
|
|
|
expr(void)
|
|
|
|
{
|
|
|
|
int s;
|
|
|
|
double g;
|
|
|
|
|
|
|
|
s = 1;
|
|
|
|
if(peek() == '+' || peek() == '-')
|
|
|
|
s = next() == '-' ? -1 : 1;
|
|
|
|
g = s * term();
|
|
|
|
while(peek() == '+' || peek() == '-'){
|
|
|
|
s = next() == '-' ? -1 : 1;
|
|
|
|
g += s * term();
|
|
|
|
}
|
|
|
|
return g;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
assign(Symbol *s)
|
|
|
|
{
|
|
|
|
next();
|
|
|
|
if(s->t != SYMFREE){
|
|
|
|
error(lineno, "symbol already exists: %s", s->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
s->t = SYMNUM;
|
|
|
|
s->e = expr();
|
|
|
|
expect(';');
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
parseval(Event *e)
|
|
|
|
{
|
|
|
|
int t;
|
|
|
|
|
|
|
|
switch(t = next()){
|
|
|
|
case SYM:
|
|
|
|
if(strcmp(sname, "x") == 0)
|
|
|
|
return VX;
|
|
|
|
if(strcmp(sname, "z") == 0)
|
|
|
|
return VZ;
|
|
|
|
e->data = strdup(sname);
|
|
|
|
return VMULT;
|
|
|
|
case NUM:
|
|
|
|
if(sval == 0)
|
|
|
|
return VL;
|
|
|
|
if(sval == 1)
|
|
|
|
return VH;
|
|
|
|
e->data = smprint("%g", sval);
|
|
|
|
return VMULT;
|
2015-09-29 18:49:28 +00:00
|
|
|
case STR:
|
|
|
|
e->data = strdup(sname);
|
|
|
|
return VMULT;
|
2015-09-27 11:50:18 +00:00
|
|
|
default:
|
|
|
|
error(lineno, "unexpected %T", t);
|
|
|
|
return VZ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
append(double off, Event ***ep, Event *e)
|
|
|
|
{
|
|
|
|
Event *f;
|
|
|
|
|
|
|
|
for(; e != nil; e = e->next){
|
|
|
|
f = emalloc(sizeof(Event));
|
|
|
|
f->t = e->t + off;
|
|
|
|
f->val = e->val;
|
|
|
|
f->line = e->line;
|
|
|
|
if(e->data != nil)
|
|
|
|
f->data = strdup(e->data);
|
|
|
|
**ep = f;
|
|
|
|
*ep = &f->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
freeev(Event *e)
|
|
|
|
{
|
|
|
|
Event *en;
|
|
|
|
|
|
|
|
for(; e != nil; e = en){
|
|
|
|
en = e->next;
|
|
|
|
free(e->data);
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Event *
|
|
|
|
events(double *off, int ronly)
|
|
|
|
{
|
|
|
|
int rela;
|
|
|
|
Event *e, *ev, **ep;
|
|
|
|
int i, n;
|
|
|
|
double f;
|
|
|
|
Symbol *sy;
|
|
|
|
double len;
|
|
|
|
int line;
|
|
|
|
|
|
|
|
rela = 0;
|
|
|
|
line = 0;
|
|
|
|
ev = nil;
|
|
|
|
ep = &ev;
|
|
|
|
for(;;)
|
|
|
|
switch(peek()){
|
|
|
|
case '+':
|
|
|
|
rela = 1;
|
|
|
|
next();
|
|
|
|
break;
|
|
|
|
case '}':
|
|
|
|
case ';':
|
|
|
|
return ev;
|
|
|
|
case ':':
|
|
|
|
next();
|
|
|
|
e = emalloc(sizeof(Event));
|
|
|
|
e->t = *off;
|
|
|
|
e->val = parseval(e);
|
|
|
|
e->line = line;
|
|
|
|
line = 0;
|
|
|
|
*ep = e;
|
|
|
|
ep = &e->next;
|
|
|
|
break;
|
|
|
|
case '|':
|
|
|
|
line = 1;
|
|
|
|
next();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
f = expr();
|
|
|
|
if(peek() == '{'){
|
|
|
|
next();
|
|
|
|
if(f < 0 || isNaN(f) || f >= 0x7fffffff){
|
|
|
|
error(lineno, "invalid repeat count");
|
|
|
|
f = 0;
|
|
|
|
}
|
|
|
|
len = 0;
|
|
|
|
e = events(&len, 1);
|
|
|
|
expect('}');
|
|
|
|
n = f + 0.5;
|
|
|
|
for(i = 0; i < n; i++){
|
|
|
|
append(*off, &ep, e);
|
|
|
|
*off += len;
|
|
|
|
}
|
|
|
|
if(*off > maxt) maxt = *off;
|
|
|
|
freeev(e);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(ronly && !rela){
|
|
|
|
error(lineno, "only relative addressing allowed");
|
|
|
|
rela = 1;
|
|
|
|
}
|
|
|
|
if(peek() == SYM){
|
|
|
|
next();
|
|
|
|
sy = getsym(sname);
|
|
|
|
if(sy->t == SYMFREE)
|
|
|
|
error(lineno, "undefined %s", sy->name);
|
|
|
|
else
|
|
|
|
f *= sy->e;
|
|
|
|
}
|
|
|
|
if(rela)
|
|
|
|
*off += f;
|
|
|
|
else
|
|
|
|
*off = f;
|
|
|
|
if(peek() == '['){
|
|
|
|
next();
|
|
|
|
sy = getsym(sname);
|
|
|
|
if(sy->t != SYMFREE && sy->t != SYMNUM)
|
|
|
|
error(lineno, "already defined %s", sy->name);
|
|
|
|
else{
|
|
|
|
sy->t = SYMNUM;
|
|
|
|
sy->e = *off;
|
|
|
|
}
|
|
|
|
expect(']');
|
|
|
|
}
|
|
|
|
if(*off < mint) mint = *off;
|
|
|
|
if(*off > maxt) maxt = *off;
|
|
|
|
rela = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
signal(char *st)
|
|
|
|
{
|
|
|
|
Signal *s;
|
|
|
|
double off;
|
|
|
|
|
|
|
|
s = emalloc(sizeof(Signal));
|
|
|
|
s->name = strdup(st);
|
|
|
|
s->ev = events(&off, 0);
|
|
|
|
expect(';');
|
|
|
|
*siglast = s;
|
|
|
|
siglast = &s->next;
|
|
|
|
nsig++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
slantfill(double x1, double x2, double t, double b, double tw)
|
|
|
|
{
|
|
|
|
double x;
|
|
|
|
double sw = 0.05;
|
|
|
|
double soff = 0.05;
|
|
|
|
|
|
|
|
for(x = x1; x < x2 - sw; x += soff)
|
|
|
|
print("line from %g,%g to %g,%g\n", x, t, x+sw, b);
|
|
|
|
if(x < x2)
|
|
|
|
print("line from %g,%g to %g,%g\n", x, t, (2*sw*tw+2*tw*x+sw*x2)/(sw+2*tw), (sw*t+t*(x-x2)+b*(2*tw-x+x2))/(sw+2*tw));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sigout(Signal *s, double top)
|
|
|
|
{
|
|
|
|
Event *e, *n;
|
|
|
|
double l, w, t, b, x1, x2, tw, m;
|
|
|
|
|
|
|
|
for(e = s->ev; e != nil && e->next != nil && e->next->t < left; e = e->next)
|
|
|
|
;
|
|
|
|
if(e == nil)
|
|
|
|
return;
|
|
|
|
b = top - rheight * 0.75;
|
|
|
|
t = top - rheight * 0.25;
|
|
|
|
tw = width * 0.003;
|
|
|
|
m = (t+b)/2;
|
|
|
|
l = width * 0.2;
|
|
|
|
w = width * 0.8 / (right - left);
|
|
|
|
x1 = l;
|
|
|
|
print("\"%s\" ljust at %g,%g\n", s->name, width * 0.1, m);
|
|
|
|
while(n = e->next, n != nil && n->t < right){
|
|
|
|
x2 = (n->t - left) * w + l;
|
|
|
|
if(n->line)
|
|
|
|
print("line from %g,%g to %g,%g dashed\n", x2, 0.0, x2, nsig*rheight);
|
|
|
|
switch(e->val){
|
|
|
|
case VZ:
|
|
|
|
print("line from %g,%g to %g,%g\n", x1, m, x2, m);
|
|
|
|
break;
|
|
|
|
case VL:
|
|
|
|
print("line from %g,%g to %g,%g\n", x1, b, x2-tw, b);
|
|
|
|
print("line from %g,%g to %g,%g\n", x2-tw, b, x2, m);
|
|
|
|
break;
|
|
|
|
case VH:
|
|
|
|
print("line from %g,%g to %g,%g\n", x1, t, x2-tw, t);
|
|
|
|
print("line from %g,%g to %g,%g\n", x2-tw, t, x2, m);
|
|
|
|
break;
|
|
|
|
case VMULT:
|
|
|
|
print("\"%s\" at %g,%g\n", e->data, (x1+x2)/2, m);
|
|
|
|
if(0){
|
|
|
|
case VX:
|
|
|
|
slantfill(x1, x2-tw, t, b, tw);
|
|
|
|
}
|
|
|
|
print("line from %g,%g to %g,%g\n", x1, b, x2-tw, b);
|
|
|
|
print("line from %g,%g to %g,%g\n", x2-tw, b, x2, m);
|
|
|
|
print("line from %g,%g to %g,%g\n", x1, t, x2-tw, t);
|
|
|
|
print("line from %g,%g to %g,%g\n", x2-tw, t, x2, m);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprint(2, "unknown event type %d\n", e->val);
|
|
|
|
}
|
|
|
|
switch(n->val){
|
|
|
|
case VL:
|
|
|
|
print("line from %g,%g to %g,%g\n", x2, m, x2+tw, b);
|
|
|
|
break;
|
|
|
|
case VH:
|
|
|
|
print("line from %g,%g to %g,%g\n", x2, m, x2+tw, t);
|
|
|
|
break;
|
|
|
|
case VMULT:
|
|
|
|
case VX:
|
|
|
|
print("line from %g,%g to %g,%g\n", x2, m, x2+tw, b);
|
|
|
|
print("line from %g,%g to %g,%g\n", x2, m, x2+tw, t);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
e = e->next;
|
|
|
|
if(e->val == VZ)
|
|
|
|
x1 = x2;
|
|
|
|
else
|
|
|
|
x1 = x2 + tw;
|
|
|
|
}
|
|
|
|
x2 = (right - left) * w + l;
|
|
|
|
switch(e->val){
|
|
|
|
case VZ:
|
|
|
|
print("line from %g,%g to %g,%g\n", x1, m, x2, m);
|
|
|
|
break;
|
|
|
|
case VL:
|
|
|
|
print("line from %g,%g to %g,%g\n", x1, b, x2, b);
|
|
|
|
break;
|
|
|
|
case VH:
|
|
|
|
print("line from %g,%g to %g,%g\n", x1, t, x2, t);
|
|
|
|
break;
|
|
|
|
case VMULT:
|
|
|
|
print("\"%s\" at %g,%g\n", e->data, (x1+x2)/2, m);
|
|
|
|
if(0){
|
|
|
|
case VX:
|
|
|
|
slantfill(x1, x2, t, b, tw);
|
|
|
|
}
|
|
|
|
print("line from %g,%g to %g,%g\n", x1, b, x2, b);
|
|
|
|
print("line from %g,%g to %g,%g\n", x1, t, x2, t);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprint(2, "unknown event type %d\n", e->val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
parseopts(char *l)
|
|
|
|
{
|
|
|
|
char *f[3];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = tokenize(l, f, nelem(f));
|
|
|
|
if(rc != 3){
|
|
|
|
error(lineno, ".TPS wrong syntax");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
width = strtod(f[1], 0);
|
|
|
|
rheight = strtod(f[2], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cleansym(void)
|
|
|
|
{
|
|
|
|
Symbol **p, *s, *sn;
|
|
|
|
Signal *si, *sin;
|
|
|
|
Event *e, *en;
|
|
|
|
|
|
|
|
for(p = stab; p < stab + nelem(stab); p++)
|
|
|
|
for(s = *p, *p = nil; s != nil; s = sn){
|
|
|
|
|
|
|
|
free(s->name);
|
|
|
|
sn = s->next;
|
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
memset(stab, 0, sizeof(stab));
|
|
|
|
|
|
|
|
for(si = sigfirst; si != nil; si = sin){
|
|
|
|
for(e = si->ev; e != nil; e = en){
|
|
|
|
en = e->next;
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
free(si->name);
|
|
|
|
sin = si->next;
|
|
|
|
free(si);
|
|
|
|
}
|
|
|
|
siglast = &sigfirst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
diagram(char *l)
|
|
|
|
{
|
|
|
|
Symbol *s;
|
|
|
|
Signal *si;
|
|
|
|
int t;
|
|
|
|
double top;
|
|
|
|
|
|
|
|
lastc = 10;
|
|
|
|
mint = 0;
|
|
|
|
maxt = 0;
|
|
|
|
nsig = 0;
|
|
|
|
parseopts(l);
|
|
|
|
|
|
|
|
for(;;){
|
|
|
|
switch(t = next()){
|
|
|
|
case SYM:
|
|
|
|
s = getsym(sname);
|
|
|
|
if(peek() == '=')
|
|
|
|
assign(s);
|
|
|
|
else
|
|
|
|
signal(s->name);
|
|
|
|
break;
|
2015-09-29 18:49:28 +00:00
|
|
|
case STR:
|
|
|
|
signal(sname);
|
|
|
|
break;
|
2015-09-27 11:50:18 +00:00
|
|
|
case CMD:
|
|
|
|
if(strcmp(sname, "TPE") == 0)
|
|
|
|
goto end;
|
|
|
|
error(lineno, "unknown command %s", sname);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error(lineno, "unexpected %T", t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end:
|
|
|
|
|
|
|
|
print(".PS %g %g\n", width, rheight * nsig);
|
|
|
|
left = mint;
|
|
|
|
right = maxt;
|
|
|
|
top = rheight * nsig;
|
|
|
|
for(si = sigfirst; si != nil; si = si->next, top -= rheight)
|
|
|
|
sigout(si, top);
|
|
|
|
print(".PE\n");
|
|
|
|
|
|
|
|
cleansym();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
run(char *f)
|
|
|
|
{
|
|
|
|
char *l;
|
|
|
|
|
|
|
|
if(f == nil)
|
|
|
|
bp = Bfdopen(0, OREAD);
|
|
|
|
else
|
|
|
|
bp = Bopen(f, OREAD);
|
|
|
|
if(bp == nil)
|
|
|
|
sysfatal("open: %r");
|
|
|
|
Blethal(bp, nil);
|
|
|
|
lineno = 1;
|
|
|
|
|
|
|
|
for(;;){
|
|
|
|
l = Brdstr(bp, '\n', 1);
|
|
|
|
if(l == nil)
|
|
|
|
break;
|
|
|
|
lineno++;
|
|
|
|
if(strncmp(l, ".TPS", 4) == 0 && (!l[4] || isspace(l[4])))
|
|
|
|
diagram(l);
|
|
|
|
else
|
|
|
|
print("%s\n", l);
|
|
|
|
free(l);
|
|
|
|
}
|
|
|
|
Bterm(bp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
usage(void)
|
|
|
|
{
|
|
|
|
fprint(2, "usage: %s [ files ]\n", argv0);
|
|
|
|
exits("usage");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
fmtinstall('T', Tfmt);
|
2015-09-29 18:49:28 +00:00
|
|
|
quotefmtinstall();
|
2015-09-27 11:50:18 +00:00
|
|
|
|
|
|
|
ARGBEGIN {
|
|
|
|
default: usage();
|
|
|
|
} ARGEND;
|
|
|
|
|
|
|
|
if(argc == 0)
|
|
|
|
run(nil);
|
|
|
|
else
|
|
|
|
for(i = 0; i < argc; i++)
|
|
|
|
run(argv[i]);
|
|
|
|
|
|
|
|
exits(nil);
|
|
|
|
}
|