Commit Diff


commit - 434d1b41b61a9771f4cec2ca6c0a00b067a50fa0
commit + b6d98463b416e9d95bc88f948b4abdff6b24aede
blob - /dev/null
blob + 1e0a12d4f7b624ee48eecc267481e51cf1eb49c6 (mode 644)
--- /dev/null
+++ src/cmd/tpic/Changes
@@ -0,0 +1,24 @@
+30 Nov 1988	ehg
+Copied from /n/bowell/usr/src/cmd/pic.
+
+16 Jan 1989	ehg
+Updates from /n/coma/usr/bwk/pic.
+Brian picked up printlf() and I moved space() in openpl() in pixel and 4014,
+	so no changes were needed in the source imported from bowell and bwk.
+bwk's print.c calls arc(), which is translated in pl$DEV.c into a call to
+	devarc() whose code is in lib$DEV/arc.c.
+I didn't understand howard's dotline change and it conflicted
+	with using pure bwk code, so I commented it out in pltex.c.
+
+8 Sep 1989	hwt
+Updates from /n/bowell/usr/src/cmd/pic
+Some changes in linegen.c (bigger buffers), misc.c, picl.l, picy.y, symtab.c
+I removed the \t-><tab> transformation in picl.l (bwk agreed it was bogus).
+Put the dotline change back in (to get smaller output files, and avoid
+	problems where lines were bunching together).
+
+11 Sep 1989	hwt
+Went back to troff dotline (the postscript one doesn't act the same
+	as troff when scale!=1).
+Changed default pen size from 8 to 9 (to give same thickness lines
+	as default pic), and made dots change size with pen size.
blob - /dev/null
blob + 9c98d197734555687eeaefd3faa276b86eb441e0 (mode 644)
--- /dev/null
+++ src/cmd/tpic/arcgen.c
@@ -0,0 +1,214 @@
+#include	<stdio.h>
+#include	<math.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+obj*
+arcgen(int type)	/* handles circular and (eventually) elliptical arcs */
+{
+	static double prevw = HT10;
+	static double prevh = HT5;
+	static double prevrad = HT2;
+	static int dtox[2][4] ={ 1, -1, -1, 1, 1, 1, -1, -1 };
+	static int dtoy[2][4] ={ 1, 1, -1, -1, -1, 1, 1, -1 };
+	static int dctrx[2][4] ={ 0, -1, 0, 1, 0, 1, 0, -1 };
+	static int dctry[2][4] ={ 1, 0, -1, 0, -1, 0, 1, 0 };
+	static int nexthv[2][4] ={ U_DIR, L_DIR, D_DIR, R_DIR, D_DIR, R_DIR, U_DIR, L_DIR };
+	double dx2, dy2, ht, phi, r, d;
+	int i, head, to, at, cw, invis, ddtype;
+	obj *p, *ppos;
+	double fromx, fromy, tox, toy;
+	Attr *ap;
+
+	tox = 0;
+	toy = 0;
+	prevrad = getfval("arcrad");
+	prevh = getfval("arrowht");
+	prevw = getfval("arrowwid");
+	fromx = curx;
+	fromy = cury;
+	head = to = at = cw = invis = ddtype = 0;
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case TEXTATTR:
+			savetext(ap->a_sub, ap->a_val.p);
+			break;
+		case HEAD:
+			head += ap->a_val.i;
+			break;
+		case INVIS:
+			invis = INVIS;
+			break;
+		case HEIGHT:	/* length of arrowhead */
+			prevh = ap->a_val.f;
+			break;
+		case WIDTH:	/* width of arrowhead */
+			prevw = ap->a_val.f;
+			break;
+		case RADIUS:
+			prevrad = ap->a_val.f;
+			break;
+		case DIAMETER:
+			prevrad = ap->a_val.f / 2;
+			break;
+		case CW:
+			cw = 1;
+			break;
+		case FROM:	/* start point of arc */
+			ppos = ap->a_val.o;
+			fromx = ppos->o_x;
+			fromy = ppos->o_y;
+			break;
+		case TO:	/* end point of arc */
+			ppos = ap->a_val.o;
+			tox = ppos->o_x;
+			toy = ppos->o_y;
+			to++;
+			break;
+		case AT:	/* center of arc */
+			ppos = ap->a_val.o;
+			curx = ppos->o_x;
+			cury = ppos->o_y;
+			at = 1;
+			break;
+		case UP:
+			hvmode = U_DIR;
+			break;
+		case DOWN:
+			hvmode = D_DIR;
+			break;
+		case RIGHT:
+			hvmode = R_DIR;
+			break;
+		case LEFT:
+			hvmode = L_DIR;
+			break;
+		}
+	}
+	if (!at && !to) {	/* the defaults are mostly OK */
+		curx = fromx + prevrad * dctrx[cw][hvmode];
+		cury = fromy + prevrad * dctry[cw][hvmode];
+		tox = fromx + prevrad * dtox[cw][hvmode];
+		toy = fromy + prevrad * dtoy[cw][hvmode];
+		hvmode = nexthv[cw][hvmode];
+	}
+	else if (!at) {
+		dx2 = (tox - fromx) / 2;
+		dy2 = (toy - fromy) / 2;
+		phi = atan2(dy2, dx2) + (cw ? -PI/2 : PI/2);
+		if (prevrad <= 0.0)
+			prevrad = dx2*dx2+dy2*dy2;
+		for (r=prevrad; (d = r*r - (dx2*dx2+dy2*dy2)) <= 0.0; r *= 2)
+			;	/* this kludge gets around too-small radii */
+		prevrad = r;
+		ht = sqrt(d);
+		curx = fromx + dx2 + ht * cos(phi);
+		cury = fromy + dy2 + ht * sin(phi);
+		dprintf("dx2,dy2=%g,%g, phi=%g, r,ht=%g,%g\n",
+			dx2, dy2, phi, r, ht);
+	}
+	else if (at && !to) {	/* do we have all the cases??? */
+		tox = fromx + prevrad * dtox[cw][hvmode];
+		toy = fromy + prevrad * dtoy[cw][hvmode];
+		hvmode = nexthv[cw][hvmode];
+	}
+	if (cw) {	/* interchange roles of from-to and heads */
+		double temp;
+		temp = fromx; fromx = tox; tox = temp;
+		temp = fromy; fromy = toy; toy = temp;
+		if (head == HEAD1)
+			head = HEAD2;
+		else if (head == HEAD2)
+			head = HEAD1;
+	}
+	p = makenode(type, 7);
+	arc_extreme(fromx, fromy, tox, toy, curx, cury);
+	p->o_val[0] = fromx;
+	p->o_val[1] = fromy;
+	p->o_val[2] = tox;
+	p->o_val[3] = toy;
+	if (cw) {
+		curx = fromx;
+		cury = fromy;
+	} else {
+		curx = tox;
+		cury = toy;
+	}
+	p->o_val[4] = prevw;
+	p->o_val[5] = prevh;
+	p->o_val[6] = prevrad;
+	p->o_attr = head | (cw ? CW_ARC : 0) | invis | ddtype;
+	if (head)
+		p->o_nhead = getfval("arrowhead");
+	dprintf("arc rad %g at %g %g from %g %g to %g %g head %g %g\n",
+		prevrad, p->o_x, p->o_y,
+		p->o_val[0], p->o_val[1], p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5]);
+	return(p);
+}
+
+/***************************************************************************
+   bounding box of a circular arc             Eric Grosse  24 May 84
+
+Conceptually, this routine generates a list consisting of the start,
+end, and whichever north, east, south, and west points lie on the arc.
+The bounding box is then the range of this list.
+    list = {start,end}
+    j = quadrant(start)
+    k = quadrant(end)
+    if( j==k && long way 'round )  append north,west,south,east
+    else
+      while( j != k )
+         append center+radius*[j-th of north,west,south,east unit vectors]
+         j += 1  (mod 4)
+    return( bounding box of list )
+The following code implements this, with simple optimizations.
+***********************************************************************/
+
+
+void
+arc_extreme(double x0, double y0, double x1, double y1, double xc, double yc)
+{
+	/* assumes center isn't too far out */
+	double r, xmin, ymin, xmax, ymax;
+	int j, k;
+	x0 -= xc; y0 -= yc;	/* move to center */
+	x1 -= xc; y1 -= yc;
+	xmin = (x0<x1)?x0:x1; ymin = (y0<y1)?y0:y1;
+	xmax = (x0>x1)?x0:x1; ymax = (y0>y1)?y0:y1;
+	r = sqrt(x0*x0 + y0*y0);
+	if (r > 0.0) {
+		j = quadrant(x0,y0);
+		k = quadrant(x1,y1);
+		if (j == k && y1*x0 < x1*y0) {
+			/* viewed as complex numbers, if Im(z1/z0)<0, arc is big */
+			if( xmin > -r) xmin = -r; if( ymin > -r) ymin = -r;
+			if( xmax <  r) xmax =  r; if( ymax <  r) ymax =  r;
+		} else {
+			while (j != k) {
+				switch (j) {
+					case 1: if( ymax <  r) ymax =  r; break; /* north */
+					case 2: if( xmin > -r) xmin = -r; break; /* west */
+					case 3: if( ymin > -r) ymin = -r; break; /* south */
+					case 4: if( xmax <  r) xmax =  r; break; /* east */
+				}
+				j = j%4 + 1;
+			}
+		}
+	}
+	xmin += xc; ymin += yc;
+	xmax += xc; ymax += yc;
+	extreme(xmin, ymin);
+	extreme(xmax, ymax);
+}
+
+int
+quadrant(double x, double y)
+{
+	if (     x>=0.0 && y> 0.0) return(1);
+	else if( x< 0.0 && y>=0.0) return(2);
+	else if( x<=0.0 && y< 0.0) return(3);
+	else if( x> 0.0 && y<=0.0) return(4);
+	else			   return 0;	/* shut up lint */
+}
+
blob - /dev/null
blob + 4b4bfe98929052ad47a2fb1b8c2b75b985e14569 (mode 644)
--- /dev/null
+++ src/cmd/tpic/blockgen.c
@@ -0,0 +1,223 @@
+#include	<stdio.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+#define	NBRACK	20	/* depth of [...] */
+#define	NBRACE	20	/* depth of {...} */
+
+struct pushstack stack[NBRACK];
+int	nstack	= 0;
+struct pushstack bracestack[NBRACE];
+int	nbstack	= 0;
+
+obj*
+leftthing(int c)	/* called for {... or [... */
+			/* really ought to be separate functions */
+{
+	obj *p;
+
+	if (c == '[') {
+		if (nstack >= NBRACK)
+			ERROR "[...] nested too deep" FATAL;
+		stack[nstack].p_x = curx;
+		stack[nstack].p_y = cury;
+		stack[nstack].p_hvmode = hvmode;
+		curx = cury = 0;
+		stack[nstack].p_xmin = xmin;
+		stack[nstack].p_xmax = xmax;
+		stack[nstack].p_ymin = ymin;
+		stack[nstack].p_ymax = ymax;
+		nstack++;
+		xmin = ymin = 30000;
+		xmax = ymax = -30000;
+		p = makenode(BLOCK, 7);
+		p->o_val[4] = nobj;	/* 1st item within [...] */
+		if (p->o_nobj != nobj-1)
+			fprintf(stderr, "nobjs wrong%d %d\n", p->o_nobj, nobj);
+	} else {
+		if (nbstack >= NBRACK)
+			ERROR "{...} nested too deep" FATAL;
+		bracestack[nbstack].p_x = curx;
+		bracestack[nbstack].p_y = cury;
+		bracestack[nbstack].p_hvmode = hvmode;
+		nbstack++;
+		p = NULL;
+	}
+	return(p);
+}
+
+obj*
+rightthing(obj *p, int c)	/* called for ... ] or ... } */
+{
+	obj *q;
+
+	if (c == '}') {
+		nbstack--;
+		curx = bracestack[nbstack].p_x;
+		cury = bracestack[nbstack].p_y;
+		hvmode = bracestack[nbstack].p_hvmode;
+		q = makenode(MOVE, 0);
+		dprintf("M %g %g\n", curx, cury);
+	} else {
+		nstack--;
+		curx = stack[nstack].p_x;
+		cury = stack[nstack].p_y;
+		hvmode = stack[nstack].p_hvmode;
+		q = makenode(BLOCKEND, 7);
+		q->o_val[4] = p->o_nobj + 1;	/* back pointer */
+		p->o_val[5] = q->o_nobj - 1;	/* forward pointer */
+		p->o_val[0] = xmin; p->o_val[1] = ymin;
+		p->o_val[2] = xmax; p->o_val[3] = ymax;
+		p->o_symtab = q->o_symtab = stack[nstack+1].p_symtab;
+		xmin = stack[nstack].p_xmin;
+		ymin = stack[nstack].p_ymin;
+		xmax = stack[nstack].p_xmax;
+		ymax = stack[nstack].p_ymax;
+	}
+	return(q);
+}
+
+obj*
+blockgen(obj *p, obj *q)	/* handles [...] */
+{
+	int i, invis, at, with;
+	double ddval, h, w, xwith, ywith;
+	double x0, y0, x1, y1, cx, cy;
+	obj *ppos;
+	Attr *ap;
+
+	invis = at = 0;
+	with = xwith = ywith = 0;
+	ddval = 0;
+	w = p->o_val[2] - p->o_val[0];
+	h = p->o_val[3] - p->o_val[1];
+	cx = (p->o_val[2] + p->o_val[0]) / 2;	/* geom ctr of [] wrt local orogin */
+	cy = (p->o_val[3] + p->o_val[1]) / 2;
+	dprintf("cx,cy=%g,%g\n", cx, cy);
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case HEIGHT:
+			h = ap->a_val.f;
+			break;
+		case WIDTH:
+			w = ap->a_val.f;
+			break;
+		case WITH:
+			with = ap->a_val.i;	/* corner */
+			break;
+		case PLACE:	/* actually with position ... */
+			ppos = ap->a_val.o;
+			xwith = cx - ppos->o_x;
+			ywith = cy - ppos->o_y;
+			with = PLACE;
+			break;
+		case AT:
+		case FROM:
+			ppos = ap->a_val.o;
+			curx = ppos->o_x;
+			cury = ppos->o_y;
+			at++;
+			break;
+		case INVIS:
+			invis = INVIS;
+			break;
+		case TEXTATTR:
+			savetext(ap->a_sub, ap->a_val.p);
+			break;
+		}
+	}
+	if (with) {
+		switch (with) {
+		case NORTH:	ywith = -h / 2; break;
+		case SOUTH:	ywith = h / 2; break;
+		case EAST:	xwith = -w / 2; break;
+		case WEST:	xwith = w / 2; break;
+		case NE:	xwith = -w / 2; ywith = -h / 2; break;
+		case SE:	xwith = -w / 2; ywith = h / 2; break;
+		case NW:	xwith = w / 2; ywith = -h / 2; break;
+		case SW:	xwith = w / 2; ywith = h / 2; break;
+		}
+		curx += xwith;
+		cury += ywith;
+	}
+	if (!at) {
+		if (isright(hvmode))
+			curx += w / 2;
+		else if (isleft(hvmode))
+			curx -= w / 2;
+		else if (isup(hvmode))
+			cury += h / 2;
+		else
+			cury -= h / 2;
+	}
+	x0 = curx - w / 2;
+	y0 = cury - h / 2;
+	x1 = curx + w / 2;
+	y1 = cury + h / 2;
+	extreme(x0, y0);
+	extreme(x1, y1);
+	p->o_x = curx;
+	p->o_y = cury;
+	p->o_nt1 = ntext1;
+	p->o_nt2 = ntext;
+	ntext1 = ntext;
+	p->o_val[0] = w;
+	p->o_val[1] = h;
+	p->o_val[2] = cx;
+	p->o_val[3] = cy;
+	p->o_val[5] = q->o_nobj - 1;		/* last item in [...] */
+	p->o_ddval = ddval;
+	p->o_attr = invis;
+	dprintf("[] %g %g %g %g at %g %g, h=%g, w=%g\n", x0, y0, x1, y1, curx, cury, h, w);
+	if (isright(hvmode))
+		curx = x1;
+	else if (isleft(hvmode))
+		curx = x0;
+	else if (isup(hvmode))
+		cury = y1;
+	else
+		cury = y0;
+	for (i = 0; i <= 5; i++)
+		q->o_val[i] = p->o_val[i];
+	stack[nstack+1].p_symtab = NULL;	/* so won't be found again */
+	blockadj(p);	/* fix up coords for enclosed blocks */
+	return(p);
+}
+
+void
+blockadj(obj *p)	/* adjust coords in block starting at p */
+{
+	double dx, dy;
+	int n, lev;
+
+	dx = p->o_x - p->o_val[2];
+	dy = p->o_y - p->o_val[3];
+	n = p->o_nobj + 1;
+	dprintf("into blockadj: dx,dy=%g,%g\n", dx, dy);
+	for (lev = 1; lev > 0; n++) {
+		p = objlist[n];
+		if (p->o_type == BLOCK)
+			lev++;
+		else if (p->o_type == BLOCKEND)
+			lev--;
+		dprintf("blockadj: type=%d o_x,y=%g,%g;", p->o_type, p->o_x, p->o_y);
+		p->o_x += dx;
+		p->o_y += dy;
+		dprintf(" becomes %g,%g\n", p->o_x, p->o_y);
+		switch (p->o_type) {	/* other absolute coords */
+		case LINE:
+		case ARROW:
+		case SPLINE:
+			p->o_val[0] += dx;
+			p->o_val[1] += dy;
+			break;
+		case ARC:
+			p->o_val[0] += dx;
+			p->o_val[1] += dy;
+			p->o_val[2] += dx;
+			p->o_val[3] += dy;
+			break;
+		}
+	}
+}
blob - /dev/null
blob + 95d4046d062ee110808124346d6abe200e7a65ae (mode 644)
--- /dev/null
+++ src/cmd/tpic/boxgen.c
@@ -0,0 +1,113 @@
+#include	<stdio.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+obj*
+boxgen(void)
+{
+	static double prevh = HT;
+	static double prevw = WID;	/* golden mean, sort of */
+	int i, at, battr, with;
+	double ddval, fillval, xwith, ywith;
+	double h, w, x0, y0, x1, y1;
+	obj *p, *ppos;
+	Attr *ap;
+
+	h = getfval("boxht");
+	w = getfval("boxwid");
+	at = battr = with = 0;
+	ddval = fillval = xwith = ywith = 0;
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case HEIGHT:
+			h = ap->a_val.f;
+			break;
+		case WIDTH:
+			w = ap->a_val.f;
+			break;
+		case SAME:
+			h = prevh;
+			w = prevw;
+			break;
+		case WITH:
+			with = ap->a_val.i;	/* corner */
+			break;
+		case AT:
+			ppos = ap->a_val.o;
+			curx = ppos->o_x;
+			cury = ppos->o_y;
+			at++;
+			break;
+		case INVIS:
+			battr |= INVIS;
+			break;
+		case DOT:
+		case DASH:
+			battr |= ap->a_type==DOT ? DOTBIT : DASHBIT;
+			if (ap->a_sub == DEFAULT)
+				ddval = getfval("dashwid");
+			else
+				ddval = ap->a_val.f;
+			break;
+		case FILL:
+			battr |= FILLBIT;
+			if (ap->a_sub == DEFAULT)
+				fillval = getfval("fillval");
+			else
+				fillval = ap->a_val.f;
+			break;
+		case TEXTATTR:
+			savetext(ap->a_sub, ap->a_val.p);
+			break;
+		}
+	}
+	if (with) {
+		switch (with) {
+		case NORTH:	ywith = -h / 2; break;
+		case SOUTH:	ywith = h / 2; break;
+		case EAST:	xwith = -w / 2; break;
+		case WEST:	xwith = w / 2; break;
+		case NE:	xwith = -w / 2; ywith = -h / 2; break;
+		case SE:	xwith = -w / 2; ywith = h / 2; break;
+		case NW:	xwith = w / 2; ywith = -h / 2; break;
+		case SW:	xwith = w / 2; ywith = h / 2; break;
+		}
+		curx += xwith;
+		cury += ywith;
+	}
+	if (!at) {
+		if (isright(hvmode))
+			curx += w / 2;
+		else if (isleft(hvmode))
+			curx -= w / 2;
+		else if (isup(hvmode))
+			cury += h / 2;
+		else
+			cury -= h / 2;
+	}
+	x0 = curx - w / 2;
+	y0 = cury - h / 2;
+	x1 = curx + w / 2;
+	y1 = cury + h / 2;
+	extreme(x0, y0);
+	extreme(x1, y1);
+	p = makenode(BOX, 2);
+	p->o_val[0] = w;
+	p->o_val[1] = h;
+	p->o_attr = battr;
+	p->o_ddval = ddval;
+	p->o_fillval = fillval;
+	dprintf("B %g %g %g %g at %g %g, h=%g, w=%g\n", x0, y0, x1, y1, curx, cury, h, w);
+	if (isright(hvmode))
+		curx = x1;
+	else if (isleft(hvmode))
+		curx = x0;
+	else if (isup(hvmode))
+		cury = y1;
+	else
+		cury = y0;
+	prevh = h;
+	prevw = w;
+	return(p);
+}
blob - /dev/null
blob + a1dbc9371d165632238cbd358f18c0e7fbfaa86a (mode 644)
--- /dev/null
+++ src/cmd/tpic/circgen.c
@@ -0,0 +1,127 @@
+#include	<stdio.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+obj*
+circgen(int type)
+{
+	static double rad[2] = { HT2, WID2 };
+	static double rad2[2] = { HT2, HT2 };
+	int i, at, t, with, battr;
+	double xwith, ywith;
+	double r, r2, ddval, fillval;
+	obj *p, *ppos;
+	Attr *ap;
+
+	battr = at = 0;
+	with = xwith = ywith = fillval = 0;
+	t = (type == CIRCLE) ? 0 : 1;
+	r = 0;
+	r2 = 0;
+	ddval = 0;
+	if (type == CIRCLE)
+		r = r2 = getfval("circlerad");
+	else if (type == ELLIPSE) {
+		r = getfval("ellipsewid") / 2;
+		r2 = getfval("ellipseht") / 2;
+	}
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case TEXTATTR:
+			savetext(ap->a_sub, ap->a_val.p);
+			break;
+		case RADIUS:
+			r = ap->a_val.f;
+			break;
+		case DIAMETER:
+		case WIDTH:
+			r = ap->a_val.f / 2;
+			break;
+		case HEIGHT:
+			r2 = ap->a_val.f / 2;
+			break;
+		case SAME:
+			r = rad[t];
+			r2 = rad2[t];
+			break;
+		case WITH:
+			with = ap->a_val.i;
+			break;
+		case AT:
+			ppos = ap->a_val.o;
+			curx = ppos->o_x;
+			cury = ppos->o_y;
+			at++;
+			break;
+		case INVIS:
+			battr |= INVIS;
+			break;
+		case DOT:
+		case DASH:
+			battr |= ap->a_type==DOT ? DOTBIT : DASHBIT;
+			if (ap->a_sub == DEFAULT)
+				ddval = getfval("dashwid");
+			else
+				ddval = ap->a_val.f;
+			break;
+		case FILL:
+			battr |= FILLBIT;
+			if (ap->a_sub == DEFAULT)
+				fillval = getfval("fillval");
+			else
+				fillval = ap->a_val.f;
+			break;
+		}
+	}
+	if (type == CIRCLE)
+		r2 = r;	/* probably superfluous */
+	if (with) {
+		switch (with) {
+		case NORTH:	ywith = -r2; break;
+		case SOUTH:	ywith = r2; break;
+		case EAST:	xwith = -r; break;
+		case WEST:	xwith = r; break;
+		case NE:	xwith = -r * 0.707; ywith = -r2 * 0.707; break;
+		case SE:	xwith = -r * 0.707; ywith = r2 * 0.707; break;
+		case NW:	xwith = r * 0.707; ywith = -r2 * 0.707; break;
+		case SW:	xwith = r * 0.707; ywith = r2 * 0.707; break;
+		}
+		curx += xwith;
+		cury += ywith;
+	}
+	if (!at) {
+		if (isright(hvmode))
+			curx += r;
+		else if (isleft(hvmode))
+			curx -= r;
+		else if (isup(hvmode))
+			cury += r2;
+		else
+			cury -= r2;
+	}
+	p = makenode(type, 2);
+	p->o_val[0] = rad[t] = r;
+	p->o_val[1] = rad2[t] = r2;
+	if (r <= 0 || r2 <= 0) {
+		ERROR "%s has invalid radius %g\n", (type==CIRCLE) ? "circle" : "ellipse", r<r2 ? r : r2 WARNING;
+	}
+	p->o_attr = battr;
+	p->o_ddval = ddval;
+	p->o_fillval = fillval;
+	extreme(curx+r, cury+r2);
+	extreme(curx-r, cury-r2);
+	if (type == CIRCLE)
+		dprintf("C %g %g %g\n", curx, cury, r);
+	if (type == ELLIPSE)
+		dprintf("E %g %g %g %g\n", curx, cury, r, r2);
+	if (isright(hvmode))
+		curx += r;
+	else if (isleft(hvmode))
+		curx -= r;
+	else if (isup(hvmode))
+		cury += r2;
+	else
+		cury -= r2;
+	return(p);
+}
blob - /dev/null
blob + 6990314e72eaae9a330ad9229029e9e7cedf0ee4 (mode 644)
--- /dev/null
+++ src/cmd/tpic/for.c
@@ -0,0 +1,94 @@
+#include <stdio.h>
+#include "pic.h"
+#include "y.tab.h"
+
+#define	SLOP	1.001
+
+typedef struct {
+	char	*var;	/* index variable */
+	double	to;	/* limit */
+	double	by;
+	int	op;	/* operator */
+	char	*str;	/* string to push back */
+} For;
+
+For	forstk[10];	/* stack of for loops */
+For	*forp = forstk;	/* pointer to current top */
+
+void
+forloop(char *var, double from, double to, int op, double by, char *str)	/* set up a for loop */
+{
+	dprintf("# for %s from %g to %g by %c %g \n",
+		var, from, to, op, by);
+	if (++forp >= forstk+10)
+		ERROR "for loop nested too deep" FATAL;
+	forp->var = var;
+	forp->to = to;
+	forp->op = op;
+	forp->by = by;
+	forp->str = str;
+	setfval(var, from);
+	nextfor();
+	unput('\n');
+}
+
+void
+nextfor(void)	/* do one iteration of a for loop */
+{
+	/* BUG:  this should depend on op and direction */
+	if (getfval(forp->var) > SLOP * forp->to) {	/* loop is done */
+		free(forp->str);
+		if (--forp < forstk)
+			ERROR "forstk popped too far" FATAL;
+	} else {		/* another iteration */
+		pushsrc(String, "\nEndfor\n");
+		pushsrc(String, forp->str);
+	}
+}
+
+void
+endfor(void)	/* end one iteration of for loop */
+{
+	struct symtab *p = lookup(forp->var);
+
+	switch (forp->op) {
+	case '+':
+	case ' ':
+		p->s_val.f += forp->by;
+		break;
+	case '-':
+		p->s_val.f -= forp->by;
+		break;
+	case '*':
+		p->s_val.f *= forp->by;
+		break;
+	case '/':
+		p->s_val.f /= forp->by;
+		break;
+	}
+	nextfor();
+}
+
+char*
+ifstat(double expr, char *thenpart, char *elsepart)
+{
+	dprintf("if %g then <%s> else <%s>\n", expr, thenpart, elsepart? elsepart : "");
+	if (expr) {
+		unput('\n');
+		pushsrc(Free, thenpart);
+		pushsrc(String, thenpart);
+		unput('\n');
+  		if (elsepart)
+			free(elsepart);
+		return thenpart;	/* to be freed later */
+	} else {
+		free(thenpart);
+		if (elsepart) {
+			unput('\n');
+			pushsrc(Free, elsepart);
+			pushsrc(String, elsepart);
+			unput('\n');
+		}
+		return elsepart;
+	}
+}
blob - /dev/null
blob + 817488c87867a0ca2bc68f709b7802a6b41a5c5c (mode 644)
--- /dev/null
+++ src/cmd/tpic/input.c
@@ -0,0 +1,608 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "pic.h"
+#include "y.tab.h"
+
+Infile	infile[10];
+Infile	*curfile = infile;
+
+#define	MAXSRC	50
+Src	src[MAXSRC];	/* input source stack */
+Src	*srcp	= src;
+
+void
+pushsrc(int type, char *ptr)	/* new input source */
+{
+	if (++srcp >= src + MAXSRC)
+		ERROR "inputs nested too deep" FATAL;
+	srcp->type = type;
+	srcp->sp = ptr;
+	if (dbg > 1) {
+		printf("\n%3d ", srcp - src);
+		switch (srcp->type) {
+		case File:
+			printf("push file %s\n", ((Infile *)ptr)->fname);
+			break;
+		case Macro:
+			printf("push macro <%s>\n", ptr);
+			break;
+		case Char:
+			printf("push char <%c>\n", *ptr);
+			break;
+		case Thru:
+			printf("push thru\n");
+			break;
+		case String:
+			printf("push string <%s>\n", ptr);
+			break;
+		case Free:
+			printf("push free <%s>\n", ptr);
+			break;
+		default:
+			ERROR "pushed bad type %d", srcp->type FATAL;
+		}
+	}
+}
+
+void
+popsrc(void)	/* restore an old one */
+{
+	if (srcp <= src)
+		ERROR "too many inputs popped" FATAL;
+	if (dbg > 1) {
+		printf("%3d ", srcp - src);
+		switch (srcp->type) {
+		case File:
+			printf("pop file\n");
+			break;
+		case Macro:
+			printf("pop macro\n");
+			break;
+		case Char:
+			printf("pop char <%c>\n", *srcp->sp);
+			break;
+		case Thru:
+			printf("pop thru\n");
+			break;
+		case String:
+			printf("pop string\n");
+			break;
+		case Free:
+			printf("pop free\n");
+			break;
+		default:
+			ERROR "pop weird input %d", srcp->type FATAL;
+		}
+	}
+	srcp--;
+}
+
+void
+definition(char *s)	/* collect definition for s and install */
+	/* definitions picked up lexically */
+{
+	char *p;
+	struct symtab *stp;
+
+	p = delimstr("definition");
+	stp = lookup(s);
+	if (stp != NULL) {	/* it's there before */
+		if (stp->s_type != DEFNAME) {
+			ERROR "%s used as variable and definition", s WARNING;
+			return;
+		}
+		free(stp->s_val.p);
+		stp->s_val.p = p;
+	} else {
+		YYSTYPE u;
+		u.p = p;
+		makevar(tostring(s), DEFNAME, u);
+	}
+	dprintf("installing %s as `%s'\n", s, p);
+}
+
+char*
+delimstr(char *s)	/* get body of X ... X */
+		/* message if too big */
+{
+	int c, delim, rdelim, n, deep;
+	static char *buf = NULL;
+	static int nbuf = 0;
+	char *p;
+
+	if (buf == NULL)
+		buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
+	while ((delim = input()) == ' ' || delim == '\t' || delim == '\n')
+		;
+	rdelim = baldelim(delim, "{}");		/* could be "(){}[]`'" */
+	deep = 1;
+	for (p = buf; ; ) {
+		c = input();
+		if (c == rdelim)
+			if (--deep == 0)
+				break;
+		if (c == delim)
+			deep++;
+		if (p >= buf + nbuf) {
+			n = p - buf;
+			buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
+			p = buf + n;
+		}
+		if (c == EOF)
+			ERROR "end of file in %s %c %.20s... %c", s, delim, buf, delim FATAL;
+		*p++ = c;
+	}
+	*p = '\0';
+	dprintf("delimstr %s %c <%s> %c\n", s, delim, buf, delim);
+	return tostring(buf);
+}
+
+int
+baldelim(int c, char *s)	/* replace c by balancing entry in s */
+{
+	for ( ; *s; s += 2)
+		if (*s == c)
+			return s[1];
+	return c;
+}
+
+void
+undefine(char *s)	/* undefine macro */
+{
+	while (*s != ' ' && *s != '\t')		/* skip "undef..." */
+		s++;
+	while (*s == ' ' || *s == '\t')
+		s++;
+	freedef(s);
+}
+
+
+Arg	args[10];	/* argument frames */
+Arg	*argfp = args;	/* frame pointer */
+int	argcnt;		/* number of arguments seen so far */
+
+void
+dodef(struct symtab *stp)	/* collect args and switch input to defn */
+{
+	int i, len;
+	char *p;
+	Arg *ap;
+
+	ap = argfp+1;
+	if (ap >= args+10)
+		ERROR "arguments too deep" FATAL;
+	argcnt = 0;
+	if (input() != '(')
+		ERROR "disaster in dodef" FATAL;
+	if (ap->argval == 0)
+		ap->argval = malloc(1000);
+	for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
+		ap->argstk[argcnt++] = p;
+		if (input() == ')')
+			break;
+	}
+	for (i = argcnt; i < MAXARGS; i++)
+		ap->argstk[i] = "";
+	if (dbg)
+		for (i = 0; i < argcnt; i++)
+			printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
+	argfp = ap;
+	pushsrc(Macro, stp->s_val.p);
+}
+
+int
+getarg(char *p)	/* pick up single argument, store in p, return length */
+{
+	int n, c, npar;
+
+	n = npar = 0;
+	for ( ;; ) {
+		c = input();
+		if (c == EOF)
+			ERROR "end of file in getarg" FATAL;
+		if (npar == 0 && (c == ',' || c == ')'))
+			break;
+		if (c == '"')	/* copy quoted stuff intact */
+			do {
+				*p++ = c;
+				n++;
+			} while ((c = input()) != '"' && c != EOF);
+		else if (c == '(')
+			npar++;
+		else if (c == ')')
+			npar--;
+		n++;
+		*p++ = c;
+	}
+	*p = 0;
+	unput(c);
+	return(n + 1);
+}
+
+#define	PBSIZE	2000
+char	pbuf[PBSIZE];		/* pushback buffer */
+char	*pb	= pbuf-1;	/* next pushed back character */
+
+char	ebuf[200];		/* collect input here for error reporting */
+char	*ep	= ebuf;
+
+int	begin	= 0;
+extern	int	thru;
+extern	struct symtab	*thrudef;
+extern	char	*untilstr;
+
+int
+input(void)
+{
+	int c;
+
+	if (thru && begin) {
+		do_thru();
+		begin = 0;
+	}
+	c = nextchar();
+	if (dbg > 1)
+		printf(" <%c>", c);
+	if (ep >= ebuf + sizeof ebuf)
+		ep = ebuf;
+	return *ep++ = c;
+}
+
+int
+nextchar(void)
+{
+	int c;
+
+  loop:
+	switch (srcp->type) {
+	default:
+		c = -1;
+		break;
+	case Free:	/* free string */
+		free(srcp->sp);
+		popsrc();
+		goto loop;
+	case Thru:	/* end of pushed back line */
+		begin = 1;
+		popsrc();
+		c = '\n';
+		break;
+	case Char:
+		if (pb >= pbuf) {
+			c = *pb--;
+			popsrc();
+			break;
+		} else {	/* can't happen? */
+			popsrc();
+			goto loop;
+		}
+	case String:
+		c = *srcp->sp++;
+		if (c == '\0') {
+			popsrc();
+			goto loop;
+		} else {
+			if (*srcp->sp == '\0')	/* empty, so pop */
+				popsrc();
+			break;
+		}
+	case Macro:
+		c = *srcp->sp++;
+		if (c == '\0') {
+			if (--argfp < args)
+				ERROR "argfp underflow" FATAL;
+			popsrc();
+			goto loop;
+		} else if (c == '$' && isdigit(*srcp->sp)) {
+			int n = 0;
+			while (isdigit(*srcp->sp))
+				n = 10 * n + *srcp->sp++ - '0';
+			if (n > 0 && n <= MAXARGS)
+				pushsrc(String, argfp->argstk[n-1]);
+			goto loop;
+		}
+		break;
+	case File:
+		c = getc(curfile->fin);
+		if (c == EOF) {
+			if (curfile == infile)
+				ERROR "end of file inside .PS/.PE" FATAL;
+			if (curfile->fin != stdin) {
+				fclose(curfile->fin);
+				free(curfile->fname);	/* assumes allocated */
+			}
+			curfile--;
+			printlf(curfile->lineno, curfile->fname);
+			popsrc();
+			thru = 0;	/* chicken out */
+			thrudef = 0;
+			if (untilstr) {
+				free(untilstr);
+				untilstr = 0;
+			}
+			goto loop;
+		}
+		if (c == '\n')
+			curfile->lineno++;
+		break;
+	}
+	return c;
+}
+
+void
+do_thru(void)	/* read one line, make into a macro expansion */
+{
+	int c, i;
+	char *p;
+	Arg *ap;
+
+	ap = argfp+1;
+	if (ap >= args+10)
+		ERROR "arguments too deep" FATAL;
+	if (ap->argval == NULL)
+		ap->argval = malloc(1000);
+	p = ap->argval;
+	argcnt = 0;
+	c = nextchar();
+	if (thru == 0) {	/* end of file was seen, so thru is done */
+		unput(c);
+		return;
+	}
+	for ( ; c != '\n' && c != EOF; ) {
+		if (c == ' ' || c == '\t') {
+			c = nextchar();
+			continue;
+		}
+		ap->argstk[argcnt++] = p;
+		if (c == '"') {
+			do {
+				*p++ = c;
+				if ((c = nextchar()) == '\\') {
+					*p++ = c;
+					*p++ = nextchar();
+					c = nextchar();
+				}
+			} while (c != '"' && c != '\n' && c != EOF);
+			*p++ = '"';
+			if (c == '"')
+				c = nextchar();
+		} else {
+			do {
+				*p++ = c;
+			} while ((c = nextchar())!=' ' && c!='\t' && c!='\n' && c!=',' && c!=EOF);
+			if (c == ',')
+				c = nextchar();
+		}
+		*p++ = '\0';
+	}
+	if (c == EOF)
+		ERROR "unexpected end of file in do_thru" FATAL;
+	if (argcnt == 0) {	/* ignore blank line */
+		pushsrc(Thru, (char *) 0);
+		return;
+	}
+	for (i = argcnt; i < MAXARGS; i++)
+		ap->argstk[i] = "";
+	if (dbg)
+		for (i = 0; i < argcnt; i++)
+			printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
+	if (strcmp(ap->argstk[0], ".PE") == 0) {
+		thru = 0;
+		thrudef = 0;
+		pushsrc(String, "\n.PE\n");
+		return;
+	}
+	if (untilstr && strcmp(ap->argstk[0], untilstr) == 0) {
+		thru = 0;
+		thrudef = 0;
+		free(untilstr);
+		untilstr = 0;
+		return;
+	}
+	pushsrc(Thru, (char *) 0);
+	dprintf("do_thru pushing back <%s>\n", thrudef->s_val.p);
+	argfp = ap;
+	pushsrc(Macro, thrudef->s_val.p);
+}
+
+int
+unput(int c)
+{
+	if (++pb >= pbuf + sizeof pbuf)
+		ERROR "pushback overflow" FATAL;
+	if (--ep < ebuf)
+		ep = ebuf + sizeof(ebuf) - 1;
+	*pb = c;
+	pushsrc(Char, pb);
+	return c;
+}
+
+void
+pbstr(char *s)
+{
+	pushsrc(String, s);
+}
+
+double
+errcheck(double x, char *s)
+{
+	extern int errno;
+
+	if (errno == EDOM) {
+		errno = 0;
+		ERROR "%s argument out of domain", s WARNING;
+	} else if (errno == ERANGE) {
+		errno = 0;
+		ERROR "%s result out of range", s WARNING;
+	}
+	return x;
+}
+
+char	errbuf[200];
+
+void
+yyerror(char *s)
+{
+	extern char *cmdname;
+
+	if (synerr)
+		return;
+	fflush(stdout);
+	fprintf(stderr, "%s: %s", cmdname, s);
+	if (errno > 0)
+		fprintf(stderr, " (%s)", strerror(errno));
+	fprintf(stderr, " near line %d, file %s\n",
+		curfile->lineno, curfile->fname);
+	eprint();
+	synerr = 1;
+	errno = 0;
+}
+
+void
+eprint(void)	/* try to print context around error */
+{
+	char *p, *q;
+
+	p = ep - 1;
+	if (p > ebuf && *p == '\n')
+		p--;
+	for ( ; p >= ebuf && *p != '\n'; p--)
+		;
+	while (*p == '\n')
+		p++;
+	fprintf(stderr, " context is\n\t");
+	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
+		;
+	while (p < q)
+		putc(*p++, stderr);
+	fprintf(stderr, " >>> ");
+	while (p < ep)
+		putc(*p++, stderr);
+	fprintf(stderr, " <<< ");
+	while (pb >= pbuf)
+		putc(*pb--, stderr);
+	fgets(ebuf, sizeof ebuf, curfile->fin);
+	fprintf(stderr, "%s", ebuf);
+	pbstr("\n.PE\n");	/* safety first */
+	ep = ebuf;
+}
+
+void yywrap(void) {;}
+
+char	*newfile = 0;		/* filename for file copy */
+char	*untilstr = 0;		/* string that terminates a thru */
+int	thru	= 0;		/* 1 if copying thru macro */
+struct symtab	*thrudef = 0;		/* macro being used */
+
+void
+copyfile(char *s)	/* remember file to start reading from */
+{
+	newfile = s;
+}
+
+void
+copydef(struct symtab *p)	/* remember macro symtab ptr */
+{
+	thrudef = p;
+}
+
+struct symtab*
+copythru(char *s)	/* collect the macro name or body for thru */
+{
+	struct symtab *p;
+	char *q, *addnewline();
+
+	p = lookup(s);
+	if (p != NULL) {
+		if (p->s_type == DEFNAME) {
+			p->s_val.p = addnewline(p->s_val.p);
+			return p;
+		} else
+			ERROR "%s used as define and name", s FATAL;
+	}
+	/* have to collect the definition */
+	pbstr(s);	/* first char is the delimiter */
+	q = delimstr("thru body");
+	s = "nameless";
+	p = lookup(s);
+	if (p != NULL) {
+		if (p->s_val.p)
+			free(p->s_val.p);
+		p->s_val.p = q;
+	} else {
+		YYSTYPE u;
+		u.p = q;
+		p = makevar(tostring(s), DEFNAME, u);
+	}
+	p->s_val.p = addnewline(p->s_val.p);
+	dprintf("installing %s as `%s'\n", s, p->s_val.p);
+	return p;
+}
+
+char*
+addnewline(char *p)	/* add newline to end of p */
+{
+	int n;
+
+	n = strlen(p);
+	if (p[n-1] != '\n') {
+		p = realloc(p, n+2);
+		p[n] = '\n';
+		p[n+1] = '\0';
+	}
+	return p;
+}
+
+void
+copyuntil(char *s)	/* string that terminates a thru */
+{
+	untilstr = s;
+}
+
+void
+copy(void)	/* begin input from file, etc. */
+{
+	FILE *fin;
+
+	if (newfile) {
+		if ((fin = fopen(newfile, "r")) == NULL)
+			ERROR "can't open file %s", newfile FATAL;
+		curfile++;
+		curfile->fin = fin;
+		curfile->fname = newfile;
+		curfile->lineno = 0;
+		printlf(1, curfile->fname);
+		pushsrc(File, curfile->fname);
+		newfile = 0;
+	}
+	if (thrudef) {
+		thru = 1;
+		begin = 1;	/* wrong place */
+	}
+}
+
+char	shellbuf[1000], *shellp;
+
+void
+shell_init(void)	/* set up to interpret a shell command */
+{
+	sprintf(shellbuf, "sh -c '");
+	shellp = shellbuf + strlen(shellbuf);
+}
+
+void
+shell_text(char *s)	/* add string to command being collected */
+{
+	while (*shellp++ = *s++)
+		;
+	shellp--;
+}
+
+void
+shell_exec(void)	/* do it */
+{
+	*shellp++ = '\'';
+	*shellp = '\0';
+	system(shellbuf);
+}
blob - /dev/null
blob + a5394232d54b06816181342e9196f3c96369c285 (mode 644)
--- /dev/null
+++ src/cmd/tpic/linegen.c
@@ -0,0 +1,210 @@
+#include	<stdio.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+obj*
+linegen(int type)
+{
+	static double prevdx = HT;
+	static double prevdy = 0;
+	static double prevw = HT10;
+	static double prevh = HT5;
+	int i, j, some, head, ddtype, invis, chop;
+	double ddval, chop1, chop2, x0, y0, x1, y1;
+	double sin(), cos(), atan2(), theta;
+	double defx, defy;
+	obj *p, *ppos;
+	static int xtab[] = { 1, 0, -1, 0 };	/* R=0, U=1, L=2, D=3 */
+	static int ytab[] = { 0, 1, 0, -1 };
+	double dx[500], dy[500];
+	int ndxy;
+	double nx, ny;
+	Attr *ap;
+
+	nx = curx;
+	ny = cury;
+	defx = getfval("linewid");
+	defy = getfval("lineht");
+	prevh = getfval("arrowht");
+	prevw = getfval("arrowwid");
+	dx[0] = dy[0] = ndxy = some = head = invis = 0;
+	chop = chop1 = chop2 = 0;
+	ddtype = ddval = 0;
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case TEXTATTR:
+			savetext(ap->a_sub, ap->a_val.p);
+			break;
+		case HEAD:
+			head += ap->a_val.i;
+			break;
+		case INVIS:
+			invis = INVIS;
+			break;
+		case CHOP:
+			if (chop++ == 0)
+				chop1 = chop2 = ap->a_val.f;
+			else
+				chop2 = ap->a_val.f;
+			break;
+		case DOT:
+		case DASH:
+			ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT;
+			if (ap->a_sub == DEFAULT)
+				ddval = getfval("dashwid");
+			else
+				ddval = ap->a_val.f;
+			break;
+		case SAME:
+			dx[ndxy] = prevdx;
+			dy[ndxy] = prevdy;
+			some++;
+			break;
+		case LEFT:
+			dx[ndxy] -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
+			some++;
+			hvmode = L_DIR;
+			break;
+		case RIGHT:
+			dx[ndxy] += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
+			some++;
+			hvmode = R_DIR;
+			break;
+		case UP:
+			dy[ndxy] += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
+			some++;
+			hvmode = U_DIR;
+			break;
+		case DOWN:
+			dy[ndxy] -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
+			some++;
+			hvmode = D_DIR;
+			break;
+		case HEIGHT:	/* length of arrowhead */
+			prevh = ap->a_val.f;
+			break;
+		case WIDTH:	/* width of arrowhead */
+			prevw = ap->a_val.f;
+			break;
+		case TO:
+			if (some) {
+				nx += dx[ndxy];
+				ny += dy[ndxy];
+				ndxy++;
+				dx[ndxy] = dy[ndxy] = some = 0;
+			}
+			ppos = attr[i].a_val.o;
+			dx[ndxy] = ppos->o_x - nx;
+			dy[ndxy] = ppos->o_y - ny;
+			some++;
+			break;
+		case BY:
+			if (some) {
+				nx += dx[ndxy];
+				ny += dy[ndxy];
+				ndxy++;
+				dx[ndxy] = dy[ndxy] = some = 0;
+			}
+			ppos = ap->a_val.o;
+			dx[ndxy] = ppos->o_x;
+			dy[ndxy] = ppos->o_y;
+			some++;
+			break;
+		case THEN:	/* turn off any previous accumulation */
+			if (some) {
+				nx += dx[ndxy];
+				ny += dy[ndxy];
+				ndxy++;
+				dx[ndxy] = dy[ndxy] = some = 0;
+			}
+			break;
+		case FROM:
+		case AT:
+			ppos = ap->a_val.o;
+			nx = curx = ppos->o_x;
+			ny = cury = ppos->o_y;
+			break;
+		}
+	}
+	if (some) {
+		nx += dx[ndxy];
+		ny += dy[ndxy];
+		ndxy++;
+		defx = dx[ndxy-1];
+		defy = dy[ndxy-1];
+	} else {
+		defx *= xtab[hvmode];
+		defy *= ytab[hvmode];
+		dx[ndxy] = defx;
+		dy[ndxy] = defy;
+		ndxy++;
+		nx += defx;
+		ny += defy;
+	}
+	prevdx = defx;
+	prevdy = defy;
+	if (chop) {
+		if (chop == 1 && chop1 == 0)	/* just said "chop", so use default */
+			chop1 = chop2 = getfval("circlerad");
+		theta = atan2(dy[0], dx[0]);
+		x0 = chop1 * cos(theta);
+		y0 = chop1 * sin(theta);
+		curx += x0;
+		cury += y0;
+		dx[0] -= x0;
+		dy[0] -= y0;
+
+		theta = atan2(dy[ndxy-1], dx[ndxy-1]);
+		x1 = chop2 * cos(theta);
+		y1 = chop2 * sin(theta);
+		nx -= x1;
+		ny -= y1;
+		dx[ndxy-1] -= x1;
+		dy[ndxy-1] -= y1;
+		dprintf("chopping %g %g %g %g; cur=%g,%g end=%g,%g\n",
+			x0, y0, x1, y1, curx, cury, nx, ny);
+	}
+	p = makenode(type, 5 + 2 * ndxy);
+	curx = p->o_val[0] = nx;
+	cury = p->o_val[1] = ny;
+	if (head || type == ARROW) {
+		p->o_nhead = getfval("arrowhead");
+		p->o_val[2] = prevw;
+		p->o_val[3] = prevh;
+		if (head == 0)
+			head = HEAD2;	/* default arrow head */
+	}
+	p->o_attr = head | invis | ddtype;
+	p->o_val[4] = ndxy;
+	nx = p->o_x;
+	ny = p->o_y;
+	for (i = 0, j = 5; i < ndxy; i++, j += 2) {
+		p->o_val[j] = dx[i];
+		p->o_val[j+1] = dy[i];
+		if (type == LINE || type == ARROW)
+			extreme(nx += dx[i], ny += dy[i]);
+		else if (type == SPLINE && i < ndxy-1) {
+			/* to compute approx extreme of spline at p,
+			/* compute midway between p-1 and p+1,
+			/* then go 3/4 from there to p */
+			double ex, ey, xi, yi, xi1, yi1;
+			xi = nx + dx[i]; yi = ny + dy[i];	/* p */
+			xi1 = xi + dx[i+1]; yi1 = yi + dy[i+1];	/* p+1 */
+			ex = (nx+xi1)/2; ey = (ny+yi1)/2;	/* midway */
+			ex += 0.75*(xi-ex); ey += 0.75*(yi-ey);
+			extreme(ex, ey);
+			nx = xi; ny = yi;
+		}
+			
+	}
+	p->o_ddval = ddval;
+	if (dbg) {
+		printf("S or L from %g %g to %g %g with %d elements:\n", p->o_x, p->o_y, curx, cury, ndxy);
+		for (i = 0, j = 5; i < ndxy; i++, j += 2)
+			printf("%g %g\n", p->o_val[j], p->o_val[j+1]);
+	}
+	extreme(p->o_x, p->o_y);
+	extreme(curx, cury);
+	return(p);
+}
blob - /dev/null
blob + ed310d5d6e0aff0fdaea8947ebf0dd5244344d7d (mode 644)
--- /dev/null
+++ src/cmd/tpic/main.c
@@ -0,0 +1,277 @@
+#include	<stdio.h>
+#include	<signal.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+obj	**objlist = 0;		/* store the elements here */
+int	nobjlist = 0;		/* size of objlist array */
+int	nobj	= 0;
+
+Attr	*attr;	/* attributes stored here as collected */
+int	nattrlist = 0;
+int	nattr	= 0;	/* number of entries in attr_list */
+
+Text	*text	= 0;	/* text strings stored here as collected */
+int	ntextlist = 0;		/* size of text[] array */
+int	ntext	= 0;
+int	ntext1	= 0;	/* record ntext here on entry to each figure */
+
+double	curx	= 0;
+double	cury	= 0;
+
+int	hvmode	= R_DIR;	/* R => join left to right, D => top to bottom, etc. */
+
+int	codegen	= 0;	/* 1=>output for this picture; 0=>no output */
+int	PEseen	= 0;	/* 1=> PE seen during parsing */
+
+double	deltx	= 6;	/* max x value in output, for scaling */
+double	delty	= 6;	/* max y value in output, for scaling */
+int	dbg	= 0;
+int	lineno	= 0;
+char	*filename	= "-";
+int	synerr	= 0;
+int	anyerr	= 0;	/* becomes 1 if synerr ever 1 */
+char	*cmdname;
+
+double	xmin	= 30000;	/* min values found in actual data */
+double	ymin	= 30000;
+double	xmax	= -30000;	/* max */
+double	ymax	= -30000;
+
+int
+main(int argc, char **argv)
+{
+	char buf[20];
+	extern void fpecatch(int);
+
+	signal(SIGFPE, fpecatch);
+	cmdname = argv[0];
+	while (argc > 1 && *argv[1] == '-') {
+		switch (argv[1][1]) {
+		case 'd':
+			dbg = atoi(&argv[1][2]);
+			if (dbg == 0)
+				dbg = 1;
+			break;
+		}
+		argc--;
+		argv++;
+	}
+	setdefaults();
+	objlist = (obj **) grow((char *)objlist, "objlist", nobjlist += 1000, sizeof(obj *));
+	text = (Text *) grow((char *)text, "text", ntextlist += 1000, sizeof(Text));
+	attr = (Attr *) grow((char *)attr, "attr", nattrlist += 100, sizeof(Attr));
+
+	sprintf(buf, "/%d/", getpid());
+	pushsrc(String, buf);
+	definition("pid");
+
+	curfile = infile;
+	pushsrc(File, curfile->fname);
+	if (argc <= 1) {
+		curfile->fin = stdin;
+		curfile->fname = tostring("-");
+		getdata();
+	} else
+		while (argc-- > 1) {
+			if ((curfile->fin = fopen(*++argv, "r")) == NULL) {
+				fprintf(stderr, "%s: can't open %s\n", cmdname, *argv);
+				exit(1);
+			}
+			curfile->fname = tostring(*argv);
+			getdata();
+			fclose(curfile->fin);
+			free(curfile->fname);
+		}
+	exit(anyerr);
+	return 0;
+}
+
+void
+fpecatch(int arg)
+{
+	ERROR "floating point exception" FATAL;
+}
+
+char *
+grow(char *ptr, char *name, int num, int size)	/* make array bigger */
+{
+	char *p;
+
+	if (ptr == NULL)
+		p = malloc(num * size);
+	else
+		p = realloc(ptr, num * size);
+	if (p == NULL)
+		ERROR "can't grow %s to %d", name, num * size FATAL;
+	return p;
+}
+
+static struct {
+	char *name;
+	double val;
+	short scalable;		/* 1 => adjust when "scale" changes */
+} defaults[] ={
+	"scale", SCALE, 1,
+	"lineht", HT, 1,
+	"linewid", HT, 1,
+	"moveht", HT, 1,
+	"movewid", HT, 1,
+	"dashwid", HT10, 1,
+	"boxht", HT, 1,
+	"boxwid", WID, 1,
+	"circlerad", HT2, 1,
+	"arcrad", HT2, 1,
+	"ellipseht", HT, 1,
+	"ellipsewid", WID, 1,
+	"arrowht", HT5, 1,
+	"arrowwid", HT10, 1,
+	"arrowhead", 2, 0,		/* arrowhead style */
+	"textht", 0.0, 1,		/* 6 lines/inch is also a useful value */
+	"textwid", 0.0, 1,
+	"maxpsht", MAXHT, 0,
+	"maxpswid", MAXWID, 0,
+	"fillval", 0.3, 0,		/* gray value for filling boxes */
+	NULL, 0, 0
+};
+
+void
+setdefaults(void)	/* set default sizes for variables like boxht */
+{
+	int i;
+	YYSTYPE v;
+
+	for (i = 0; defaults[i].name != NULL; i++) {
+		v.f = defaults[i].val;
+		makevar(tostring(defaults[i].name), VARNAME, v);
+	}
+}
+
+void
+resetvar(void)	/* reset variables listed */
+{
+	int i, j;
+
+	if (nattr == 0) {	/* none listed, so do all */
+		setdefaults();
+		return;
+	}
+	for (i = 0; i < nattr; i++) {
+		for (j = 0; defaults[j].name != NULL; j++)
+			if (strcmp(defaults[j].name, attr[i].a_val.p) == 0) {
+				setfval(defaults[j].name, defaults[j].val);
+				free(attr[i].a_val.p);
+				break;
+			}
+	}
+}
+
+void
+checkscale(char *s)	/* if s is "scale", adjust default variables */
+{
+	int i;
+	double scale;
+
+	if (strcmp(s, "scale") == 0) {
+		scale = getfval("scale");
+		for (i = 1; defaults[i].name != NULL; i++)
+			if (defaults[i].scalable)
+				setfval(defaults[i].name, defaults[i].val * scale);
+	}
+}
+
+void
+getdata(void)
+{
+	char *p, buf[1000], buf1[100];
+	int ln;
+
+	curfile->lineno = 0;
+	printlf(1, curfile->fname);
+	while (fgets(buf, sizeof buf, curfile->fin) != NULL) {
+		curfile->lineno++;
+		if (*buf == '.' && *(buf+1) == 'P' && *(buf+2) == 'S') {
+			for (p = &buf[3]; *p == ' '; p++)
+				;
+			if (*p++ == '<') {
+				Infile svfile;
+				svfile = *curfile;
+				sscanf(p, "%s", buf1);
+				if ((curfile->fin=fopen(buf1, "r")) == NULL)
+					ERROR "can't open %s", buf1 FATAL;
+				curfile->fname = tostring(buf1);
+				getdata();
+				fclose(curfile->fin);
+				free(curfile->fname);
+				*curfile = svfile;
+				printlf(curfile->lineno, curfile->fname);
+				continue;
+			}
+			reset();
+			yyparse();
+			anyerr += synerr;
+			/* yylval.i now contains 'E' or 'F' from .PE or .PF */
+
+			deltx = (xmax - xmin) / getfval("scale");
+			delty = (ymax - ymin) / getfval("scale");
+			if (buf[3] == ' ') {	/* next things are wid & ht */
+				if (sscanf(&buf[4],"%lf %lf", &deltx, &delty) < 2)
+					delty = deltx * (ymax-ymin) / (xmax-xmin);
+				/* else {
+				/*	double xfac, yfac; */
+				/*	xfac = deltx / (xmax-xmin);
+				/*	yfac = delty / (ymax-ymin);
+				/*	if (xfac <= yfac)
+				/*		delty = xfac * (ymax-ymin);
+				/*	else
+				/*		deltx = yfac * (xmax-xmin);
+				/*}
+				*/
+			}
+			dprintf("deltx = %g, delty = %g\n", deltx, delty);
+			if (codegen && !synerr) {
+				openpl();	/* puts out .PS, with ht & wid stuck in */
+				printlf(curfile->lineno+1, NULL);
+				print();	/* assumes \n at end */
+				closepl();	/* does the .PE/F */
+			}
+			printlf(curfile->lineno+1, NULL);
+			fflush(stdout);
+		} else if (buf[0] == '.' && buf[1] == 'l' && buf[2] == 'f') {
+			if (sscanf(buf+3, "%d %s", &ln, buf1) == 2) {
+				free(curfile->fname);
+				printlf(curfile->lineno = ln, curfile->fname = tostring(buf1));
+			} else
+				printlf(curfile->lineno = ln, NULL);
+		} else
+			fputs(buf, stdout);
+	}
+}
+
+void
+reset(void)
+{
+	obj *op;
+	int i;
+	extern int nstack;
+
+	for (i = 0; i < nobj; i++) {
+		op = objlist[i];
+		if (op->o_type == BLOCK)
+			freesymtab(op->o_symtab);
+		free((char *)objlist[i]);
+	}
+	nobj = 0;
+	nattr = 0;
+	for (i = 0; i < ntext; i++)
+		if (text[i].t_val)
+			free(text[i].t_val);
+	ntext = ntext1 = 0;
+	codegen = synerr = 0;
+	nstack = 0;
+	curx = cury = 0;
+	PEseen = 0;
+	hvmode = R_DIR;
+	xmin = ymin = 30000;
+	xmax = ymax = -30000;
+}
blob - /dev/null
blob + 72e83303af55c3eaccd61034ee7f9f5fea4a78d2 (mode 644)
--- /dev/null
+++ src/cmd/tpic/misc.c
@@ -0,0 +1,463 @@
+#include	<stdio.h>
+#include	<string.h>
+#include	<math.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+int
+setdir(int n)	/* set direction (hvmode) from LEFT, RIGHT, etc. */
+{
+	switch (n) {
+	case UP:	hvmode = U_DIR; break;
+	case DOWN:	hvmode = D_DIR; break;
+	case LEFT:	hvmode = L_DIR; break;
+	case RIGHT:	hvmode = R_DIR; break;
+	}
+ 	return(hvmode);
+}
+
+int
+curdir(void)	/* convert current dir (hvmode) to RIGHT, LEFT, etc. */
+{
+	switch (hvmode) {
+	case R_DIR:	return RIGHT;
+	case L_DIR:	return LEFT;
+	case U_DIR:	return UP;
+	case D_DIR:	return DOWN;
+	}
+	ERROR "can't happen curdir" FATAL;
+	return 0;
+}
+
+double
+getcomp(obj *p, int t)	/* return component of a position */
+{
+	switch (t) {
+	case DOTX:
+		return p->o_x;
+	case DOTY:
+		return p->o_y;
+	case DOTWID:
+		switch (p->o_type) {
+		case BOX:
+		case BLOCK:
+		case TEXT:
+			return p->o_val[0];
+		case CIRCLE:
+		case ELLIPSE:
+			return 2 * p->o_val[0];
+		case LINE:
+		case ARROW:
+			return p->o_val[0] - p->o_x;
+		case PLACE:
+			return 0;
+		}
+	case DOTHT:
+		switch (p->o_type) {
+		case BOX:
+		case BLOCK:
+		case TEXT:
+			return p->o_val[1];
+		case CIRCLE:
+		case ELLIPSE:
+			return 2 * p->o_val[1];
+		case LINE:
+		case ARROW:
+			return p->o_val[1] - p->o_y;
+		case PLACE:
+			return 0;
+		}
+	case DOTRAD:
+		switch (p->o_type) {
+		case CIRCLE:
+		case ELLIPSE:
+			return p->o_val[0];
+		}
+	}
+	ERROR "you asked for a weird dimension or position" WARNING;
+	return 0;
+}
+
+double	exprlist[100];
+int	nexpr	= 0;
+
+void
+exprsave(double f)
+{
+	exprlist[nexpr++] = f;
+}
+
+char*
+sprintgen(char *fmt)
+{
+	char buf[1000];
+
+	sprintf(buf, fmt, exprlist[0], exprlist[1], exprlist[2], exprlist[3], exprlist[4]);
+	nexpr = 0;
+	free(fmt);
+	return tostring(buf);
+}
+
+void
+makefattr(int type, int sub, double f)	/* double attr */
+{
+	YYSTYPE val;
+	val.f = f;
+	makeattr(type, sub, val);
+}
+
+void
+makeoattr(int type, obj *o)	/* obj* attr */
+{
+	YYSTYPE val;
+	val.o = o;
+	makeattr(type, 0, val);
+}
+
+void
+makeiattr(int type, int i)	/* int attr */
+{
+	YYSTYPE val;
+	val.i = i;
+	makeattr(type, 0, val);
+}
+
+void
+maketattr(int sub, char *p)	/* text attribute: takes two */
+{
+	YYSTYPE val;
+	val.p = p;
+	makeattr(TEXTATTR, sub, val);
+}
+
+void
+addtattr(int sub)		/* add text attrib to existing item */
+{
+	attr[nattr-1].a_sub |= sub;
+}
+
+void
+makevattr(char *p)	/* varname attribute */
+{
+	YYSTYPE val;
+	val.p = p;
+	makeattr(VARNAME, 0, val);
+}
+
+void
+makeattr(int type, int sub, YYSTYPE val)	/* add attribute type and val */
+{
+	if (type == 0 && val.i == 0) {	/* clear table for next stat */
+		nattr = 0;
+		return;
+	}
+	if (nattr >= nattrlist)
+		attr = (Attr *) grow((char *)attr, "attr", nattrlist += 100, sizeof(Attr));
+	dprintf("attr %d:  %d %d %d\n", nattr, type, sub, val.i);
+	attr[nattr].a_type = type;
+	attr[nattr].a_sub = sub;
+	attr[nattr].a_val = val;
+	nattr++;
+}
+
+void
+printexpr(double f)	/* print expression for debugging */
+{
+	printf("%g\n", f);
+}
+
+void
+printpos(obj *p)	/* print position for debugging */
+{
+	printf("%g, %g\n", p->o_x, p->o_y);
+}
+
+char*
+tostring(char *s)
+{
+	char *p;
+
+	p = malloc(strlen(s)+1);
+	if (p == NULL)
+		ERROR "out of space in tostring on %s", s FATAL;
+	strcpy(p, s);
+	return(p);
+}
+
+obj*
+makepos(double x, double y)	/* make a position cell */
+{
+	obj *p;
+
+	p = makenode(PLACE, 0);
+	p->o_x = x;
+	p->o_y = y;
+	return(p);
+}
+
+obj*
+makebetween(double f, obj *p1, obj* p2)	/* make position between p1 and p2 */
+{
+	obj *p;
+
+	dprintf("fraction = %.2f\n", f);
+	p = makenode(PLACE, 0);
+	p->o_x = p1->o_x + f * (p2->o_x - p1->o_x);
+	p->o_y = p1->o_y + f * (p2->o_y - p1->o_y);
+	return(p);
+}
+
+obj*
+getpos(obj *p, int corner)	/* find position of point */
+{
+	double x, y;
+
+	whatpos(p, corner, &x, &y);
+	return makepos(x, y);
+}
+
+int
+whatpos(obj *p, int corner, double *px, double *py)	/* what is the position (no side effect) */
+{
+	double x, y, x1, y1;
+
+	dprintf("whatpos %p %d %d\n", p, p->o_type, corner);
+	x = p->o_x;
+	y = p->o_y;
+	x1 = 0;
+	y1 = 0;
+	if (p->o_type != PLACE) {
+		x1 = p->o_val[0];
+		y1 = p->o_val[1];
+	}
+	switch (p->o_type) {
+	case PLACE:
+		break;
+	case BOX:
+	case BLOCK:
+	case TEXT:
+		switch (corner) {
+		case NORTH:	y += y1 / 2; break;
+		case SOUTH:	y -= y1 / 2; break;
+		case EAST:	x += x1 / 2; break;
+		case WEST:	x -= x1 / 2; break;
+		case NE:	x += x1 / 2; y += y1 / 2; break;
+		case SW:	x -= x1 / 2; y -= y1 / 2; break;
+		case SE:	x += x1 / 2; y -= y1 / 2; break;
+		case NW:	x -= x1 / 2; y += y1 / 2; break;
+		case START:
+			if (p->o_type == BLOCK)
+				return whatpos(objlist[(int)p->o_val[2]], START, px, py);
+		case END:
+			if (p->o_type == BLOCK)
+				return whatpos(objlist[(int)p->o_val[3]], END, px, py);
+		}
+		break;
+	case ARC:
+		switch (corner) {
+		case START:
+			if (p->o_attr & CW_ARC) {
+				x = p->o_val[2]; y = p->o_val[3];
+			} else {
+				x = x1; y = y1;
+			}
+			break;
+		case END:
+			if (p->o_attr & CW_ARC) {
+				x = x1; y = y1;
+			} else {
+				x = p->o_val[2]; y = p->o_val[3];
+			}
+			break;
+		}
+		if (corner == START || corner == END)
+			break;
+		x1 = y1 = sqrt((x1-x)*(x1-x) + (y1-y)*(y1-y));
+		/* Fall Through! */
+	case CIRCLE:
+	case ELLIPSE:
+		switch (corner) {
+		case NORTH:	y += y1; break;
+		case SOUTH:	y -= y1; break;
+		case EAST:	x += x1; break;
+		case WEST:	x -= x1; break;
+		case NE:	x += 0.707 * x1; y += 0.707 * y1; break;
+		case SE:	x += 0.707 * x1; y -= 0.707 * y1; break;
+		case NW:	x -= 0.707 * x1; y += 0.707 * y1; break;
+		case SW:	x -= 0.707 * x1; y -= 0.707 * y1; break;
+		}
+		break;
+	case LINE:
+	case SPLINE:
+	case ARROW:
+		switch (corner) {
+		case START:	break;	/* already in place */
+		case END:	x = x1; y = y1; break;
+		default: /* change! */
+		case CENTER:	x = (x+x1)/2; y = (y+y1)/2; break;
+		case NORTH:	if (y1 > y) { x = x1; y = y1; } break;
+		case SOUTH:	if (y1 < y) { x = x1; y = y1; } break;
+		case EAST:	if (x1 > x) { x = x1; y = y1; } break;
+		case WEST:	if (x1 < x) { x = x1; y = y1; } break;
+		}
+		break;
+	case MOVE:
+		/* really ought to be same as line... */
+		break;
+	}
+	dprintf("whatpos returns %g %g\n", x, y);
+	*px = x;
+	*py = y;
+	return 1;
+}
+
+obj*
+gethere(void)	/* make a place for curx,cury */
+{
+	dprintf("gethere %g %g\n", curx, cury);
+	return(makepos(curx, cury));
+}
+
+obj*
+getlast(int n, int t)	/* find n-th previous occurrence of type t */
+{
+	int i, k;
+	obj *p;
+
+	k = n;
+	for (i = nobj-1; i >= 0; i--) {
+		p = objlist[i];
+		if (p->o_type == BLOCKEND) {
+			i = p->o_val[4];
+			continue;
+		}
+		if (p->o_type != t)
+			continue;
+		if (--k > 0)
+			continue;	/* not there yet */
+		dprintf("got a last of x,y= %g,%g\n", p->o_x, p->o_y);
+		return(p);
+	}
+	ERROR "there is no %dth last", n WARNING;
+	return(NULL);
+}
+
+obj*
+getfirst(int n, int t)	/* find n-th occurrence of type t */
+{
+	int i, k;
+	obj *p;
+
+	k = n;
+	for (i = 0; i < nobj; i++) {
+		p = objlist[i];
+		if (p->o_type == BLOCK && t != BLOCK) {	/* skip whole block */
+			i = p->o_val[5] + 1;
+			continue;
+		}
+		if (p->o_type != t)
+			continue;
+		if (--k > 0)
+			continue;	/* not there yet */
+		dprintf("got a first of x,y= %g,%g\n", p->o_x, p->o_y);
+		return(p);
+	}
+	ERROR "there is no %dth ", n WARNING;
+	return(NULL);
+}
+
+double
+getblkvar(obj *p, char *s)	/* find variable s2 in block p */
+{
+	YYSTYPE y, getblk();
+
+	y = getblk(p, s);
+	return y.f;
+}
+
+obj*
+getblock(obj *p, char *s)	/* find variable s in block p */
+{
+	YYSTYPE y, getblk();
+
+	y = getblk(p, s);
+	return y.o;
+}
+
+YYSTYPE
+getblk(obj *p, char *s)	/* find union type for s in p */
+{
+	static YYSTYPE bug;
+	struct symtab *stp;
+
+	if (p->o_type != BLOCK) {
+		ERROR ".%s is not in that block", s WARNING;
+		return(bug);
+	}
+	for (stp = p->o_symtab; stp != NULL; stp = stp->s_next)
+		if (strcmp(s, stp->s_name) == 0) {
+			dprintf("getblk %s found x,y= %g,%g\n",
+				s, (stp->s_val.o)->o_x, (stp->s_val.o)->o_y);
+			return(stp->s_val);
+		}
+	ERROR "there is no .%s in that []", s WARNING;
+	return(bug);
+}
+
+obj*
+fixpos(obj *p, double x, double y)
+{
+	dprintf("fixpos returns %g %g\n", p->o_x + x, p->o_y + y);
+	return makepos(p->o_x + x, p->o_y + y);
+}
+
+obj*
+addpos(obj *p, obj *q)
+{
+	dprintf("addpos returns %g %g\n", p->o_x+q->o_x, p->o_y+q->o_y);
+	return makepos(p->o_x+q->o_x, p->o_y+q->o_y);
+}
+
+obj*
+subpos(obj *p, obj *q)
+{
+	dprintf("subpos returns %g %g\n", p->o_x-q->o_x, p->o_y-q->o_y);
+	return makepos(p->o_x-q->o_x, p->o_y-q->o_y);
+}
+
+obj*
+makenode(int type, int n)
+{
+	obj *p;
+
+	p = (obj *) calloc(1, sizeof(obj) + (n-1)*sizeof(ofloat));
+	if (p == NULL)
+		ERROR "out of space in makenode" FATAL;
+	p->o_type = type;
+	p->o_count = n;
+	p->o_nobj = nobj;
+	p->o_mode = hvmode;
+	p->o_x = curx;
+	p->o_y = cury;
+	p->o_nt1 = ntext1;
+	p->o_nt2 = ntext;
+	ntext1 = ntext;	/* ready for next caller */
+	if (nobj >= nobjlist)
+		objlist = (obj **) grow((char *) objlist, "objlist",
+			nobjlist *= 2, sizeof(obj *));
+	objlist[nobj++] = p;
+	return(p);
+}
+
+void
+extreme(double x, double y)	/* record max and min x and y values */
+{
+	if (x > xmax)
+		xmax = x;
+	if (y > ymax)
+		ymax = y;
+	if (x < xmin)
+		xmin = x;
+	if (y < ymin)
+		ymin = y;
+}
blob - /dev/null
blob + 76bdcb368bb1ebb1d4c485f9268c8aba7a183945 (mode 644)
--- /dev/null
+++ src/cmd/tpic/mkfile
@@ -0,0 +1,39 @@
+<$PLAN9/src/mkhdr
+
+TARG=tpic
+YFILES=picy.y
+
+OFILES=\
+	arcgen.$O\
+	blockgen.$O\
+	boxgen.$O\
+	circgen.$O\
+	for.$O\
+	input.$O\
+	linegen.$O\
+	main.$O\
+	misc.$O\
+	movegen.$O\
+	picl.$O\
+	picy.$O\
+	pltex.$O\
+	print.$O\
+	symtab.$O\
+	tex.$O\
+	textgen.$O\
+
+HFILES=pic.h y.tab.h tex.h
+
+<$PLAN9/src/mkone
+
+YFLAGS=-d -S
+
+picy.c: y.tab.c
+	mv y.tab.c picy.c
+
+picl.$O: picl.l
+	9 lex  picl.l
+	$CC $CFLAGS lex.yy.c
+	rm lex.yy.c
+	mv lex.yy.$O picl.$O
+
blob - /dev/null
blob + 3a7e2021319371c823a0dc40b410a30a5f3c36ad (mode 644)
--- /dev/null
+++ src/cmd/tpic/movegen.c
@@ -0,0 +1,87 @@
+#include	<stdio.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+obj*
+movegen(void)
+{
+	static double prevdx, prevdy;
+	int i, some;
+	double defx, defy, dx, dy;
+	obj *p;
+	obj *ppos;
+	static int xtab[] = { 1, 0, -1, 0 };	/* R=0, U=1, L=2, D=3 */
+	static int ytab[] = { 0, 1, 0, -1 };
+	Attr *ap;
+
+	defx = getfval("movewid");
+	defy = getfval("moveht");
+	dx = dy = some = 0;
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case TEXTATTR:
+			savetext(ap->a_sub, ap->a_val.p);
+			break;
+		case SAME:
+			dx = prevdx;
+			dy = prevdy;
+			some++;
+			break;
+		case LEFT:
+			dx -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
+			some++;
+			hvmode = L_DIR;
+			break;
+		case RIGHT:
+			dx += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
+			some++;
+			hvmode = R_DIR;
+			break;
+		case UP:
+			dy += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
+			some++;
+			hvmode = U_DIR;
+			break;
+		case DOWN:
+			dy -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
+			some++;
+			hvmode = D_DIR;
+			break;
+		case TO:
+			ppos = ap->a_val.o;
+			dx = ppos->o_x - curx;
+			dy = ppos->o_y - cury;
+			some++;
+			break;
+		case BY:
+			ppos = ap->a_val.o;
+			dx = ppos->o_x;
+			dy = ppos->o_y;
+			some++;
+			break;
+		case FROM:
+		case AT:
+			ppos = ap->a_val.o;
+			curx = ppos->o_x;
+			cury = ppos->o_y;
+			break;
+		}
+	}
+	if (some) {
+		defx = dx;
+		defy = dy;
+	} else {
+		defx *= xtab[hvmode];
+		defy *= ytab[hvmode];
+	}
+	prevdx = defx;
+	prevdy = defy;
+	extreme(curx, cury);
+	curx += defx;
+	cury += defy;
+	extreme(curx, cury);
+	p = makenode(MOVE, 0);
+	dprintf("M %g %g\n", curx, cury);
+	return(p);
+}
blob - /dev/null
blob + 50e58009287e0016dee888e037aeeb80b38da401 (mode 644)
--- /dev/null
+++ src/cmd/tpic/pic.h
@@ -0,0 +1,285 @@
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifndef PI
+#define PI 3.1415926535897932384626433832795028841971693993751
+#endif
+
+#define	MAXWID	8.5	/* default limits max picture to 8.5 x 11; */
+#define	MAXHT	11	/* change to taste without peril */
+
+#define	dprintf	if(dbg)printf
+
+extern	char	errbuf[200];
+#define	ERROR	sprintf(errbuf,
+#define	FATAL	), yyerror(errbuf), exit(1)
+#define	WARNING	), yyerror(errbuf)
+
+#define	DEFAULT	0
+
+#define	HEAD1	1
+#define	HEAD2	2
+#define	HEAD12	(HEAD1+HEAD2)
+#define	INVIS	4
+#define	CW_ARC	8	/* clockwise arc */
+#define	DOTBIT	16	/* line styles */
+#define	DASHBIT	32
+#define	FILLBIT	64	/* gray-fill on boxes, etc. */
+
+#define	CENTER	01	/* text attributes */
+#define	LJUST	02
+#define	RJUST	04
+#define	ABOVE	010
+#define	BELOW	020
+#define	SPREAD	040
+
+#define	SCALE	1.0	/* default scale: units/inch */
+#define	WID	0.75	/* default width for boxes and ellipses */
+#define	WID2	0.375
+#define	HT	0.5	/* default height and line length */
+#define	HT2	(HT/2)
+#define	HT5	(HT/5)
+#define	HT10	(HT/10)
+
+/* these have to be like so, so that we can write */
+/* things like R & V, etc. */
+#define	H	0
+#define	V	1
+#define	R_DIR	0
+#define	U_DIR	1
+#define	L_DIR	2
+#define	D_DIR	3
+#define	ishor(n)	(((n) & V) == 0)
+#define	isvert(n)	(((n) & V) != 0)
+#define	isright(n)	((n) == R_DIR)
+#define	isleft(n)	((n) == L_DIR)
+#define	isdown(n)	((n) == D_DIR)
+#define	isup(n)		((n) == U_DIR)
+
+typedef	float	ofloat;	/* for o_val[] in obj;  could be double */
+
+typedef struct obj {	/* stores various things in variable length */
+	int	o_type;
+	int	o_count;	/* number of things */
+	int	o_nobj;		/* index in objlist */
+	int	o_mode;		/* hor or vert */
+	float	o_x;		/* coord of "center" */
+	float	o_y;
+	int	o_nt1;		/* 1st index in text[] for this object */
+	int	o_nt2;		/* 2nd; difference is #text strings */
+	int	o_attr;		/* HEAD, CW, INVIS, etc., go here */
+	int	o_size;		/* linesize */
+	int	o_nhead;	/* arrowhead style */
+	struct symtab *o_symtab; /* symtab for [...] */
+	float	o_ddval;	/* value of dot/dash expression */
+	float	o_fillval;	/* gray scale value */
+	ofloat	o_val[1];	/* actually this will be > 1 in general */
+				/* type is not always FLOAT!!!! */
+} obj;
+
+typedef union {		/* the yacc stack type */
+	int	i;
+	char	*p;
+	obj	*o;
+	double	f;
+	struct symtab *st;
+} YYSTYPE;
+
+extern	YYSTYPE	yylval, yyval;
+
+struct symtab {
+	char	*s_name;
+	int	s_type;
+	YYSTYPE	s_val;
+	struct symtab *s_next;
+};
+
+typedef struct {	/* attribute of an object */
+	int	a_type;
+	int	a_sub;
+	YYSTYPE	a_val;
+} Attr;
+
+typedef struct {
+	int	t_type;		/* CENTER, LJUST, etc. */
+	char	t_op;		/* optional sign for size changes */
+	char	t_size;		/* size, abs or rel */
+	char	*t_val;
+} Text;
+
+#define	String	01
+#define	Macro	02
+#define	File	04
+#define	Char	010
+#define	Thru	020
+#define	Free	040
+
+typedef struct {	/* input source */
+	int	type;	/* Macro, String, File */
+	char	*sp;	/* if String or Macro */
+} Src;
+
+extern	Src	src[], *srcp;	/* input source stack */
+
+typedef struct {
+	FILE	*fin;
+	char	*fname;
+	int	lineno;
+} Infile;
+
+extern	Infile	infile[], *curfile;
+
+#define	MAXARGS	20
+typedef struct {	/* argument stack */
+	char	*argstk[MAXARGS];	/* pointers to args */
+	char	*argval;	/* points to space containing args */
+} Arg;
+
+extern	int	dbg;
+extern	obj	**objlist;
+extern	int	nobj, nobjlist;
+extern	Attr	*attr;
+extern	int	nattr, nattrlist;
+extern	Text	*text;
+extern	int	ntextlist;
+extern	int	ntext;
+extern	int	ntext1;
+extern	double	curx, cury;
+extern	int	hvmode;
+extern	int	codegen;
+extern	int	PEseen;
+extern	double	deltx, delty;
+extern	int	lineno;
+extern	int	synerr;
+
+extern	double	xmin, ymin, xmax, ymax;
+
+struct pushstack {
+	double	p_x;
+	double	p_y;
+	int	p_hvmode;
+	double	p_xmin;
+	double	p_ymin;
+	double	p_xmax;
+	double	p_ymax;
+	struct symtab *p_symtab;
+};
+extern	struct pushstack stack[];
+extern	int	nstack;
+extern	int	cw;
+
+
+#define	Log10(x) errcheck(log10(x), "log")
+#define	Exp(x)	errcheck(exp(x), "exp")
+#define	Sqrt(x)	errcheck(sqrt(x), "sqrt")
+
+
+char*		addnewline(char *p)	/* add newline to end of p */;
+obj*		addpos(obj *p, obj *q);
+void		addtattr(int sub)		/* add text attrib to existing item */;
+void		arc(double xc, double yc, double x0, double y0, double x1, double y1)	/* draw arc with center xc,yc */;
+void		arc_extreme(double x0, double y0, double x1, double y1, double xc, double yc);
+obj*		arcgen(int type)	/* handles circular and (eventually) elliptical arcs */;
+void		arrow(double x0, double y0, double x1, double y1, double w, double h, double ang, int nhead) 	/* draw arrow (without shaft) */ /* head wid w, len h, rotated ang */ /* and drawn with nhead lines */;
+int		baldelim(int c, char *s)	/* replace c by balancing entry in s */;
+void		blockadj(obj *p)	/* adjust coords in block starting at p */;
+obj*		blockgen(obj *p, obj *q)	/* handles [...] */;
+obj*		boxgen(void);
+void		checkscale(char *s)	/* if s is "scale", adjust default variables */;
+obj*		circgen(int type);
+void		copy(void)	/* begin input from file, etc. */;
+void		copydef(struct symtab *p)	/* remember macro symtab ptr */;
+void		copyfile(char *s)	/* remember file to start reading from */;
+struct symtab*	copythru(char *s)	/* collect the macro name or body for thru */;
+void		copyuntil(char *s)	/* string that terminates a thru */;
+int		curdir(void)	/* convert current dir (hvmode) to RIGHT, LEFT, etc. */;
+void		definition(char *s)	/* collect definition for s and install */ /* definitions picked up lexically */;
+char*		delimstr(char *s)	/* get body of X ... X */ 	/* message if too big */;
+void		do_thru(void)	/* read one line, make into a macro expansion */;
+void		dodef(struct symtab *stp)	/* collect args and switch input to defn */;
+void		dot(void);
+void		dotbox(double x0, double y0, double x1, double y1, int ddtype, double ddval)	/* dotted or dashed box */;
+void		dotext(obj *p)	/* print text strings of p in proper vertical spacing */;
+void		dotline(double x0, double y0, double x1, double y1, int ddtype, double ddval);
+void		dotline(double x0, double y0, double x1, double y1, int ddtype, double ddval) /* dotted line */;
+void		ellipse(double x, double y, double r1, double r2);
+void		endfor(void)	/* end one iteration of for loop */;
+void		eprint(void)	/* try to print context around error */;
+double		errcheck(double x, char *s);
+void		exprsave(double f);
+void		extreme(double x, double y)	/* record max and min x and y values */;
+void		fillend(void);
+void		fillstart(double v)	/* only choose black, light grey (.75), or white, for now */;
+obj*		fixpos(obj *p, double x, double y);
+void		forloop(char *, double, double, int, double, char *)	/* set up a for loop */;
+void		fpecatch(int arg);
+void		freedef(char *s)	/* free definition for string s */;
+void		freesymtab(struct symtab *p)	/* free space used by symtab at p */;
+int		getarg(char *p)	/* pick up single argument, store in p, return length */;
+YYSTYPE		getblk(obj *p, char *s)	/* find union type for s in p */;
+double		getblkvar(obj *p, char *s)	/* find variable s2 in block p */;
+obj*		getblock(obj *p, char *s)	/* find variable s in block p */;
+double		getcomp(obj *p, int t)	/* return component of a position */;
+void		getdata(void);
+obj*		getfirst(int n, int t)	/* find n-th occurrence of type t */;
+double		getfval(char *s)	/* return float value of variable s */;
+obj*		gethere(void)	/* make a place for curx,cury */;
+obj*		getlast(int n, int t)	/* find n-th previous occurrence of type t */;
+obj*		getpos(obj *p, int corner)	/* find position of point */;
+YYSTYPE		getvar(char *s)	/* return value of variable s (usually pointer) */;
+char *		grow(char *ptr, char *name, int num, int size)	/* make array bigger */;
+char*		ifstat(double expr, char *thenpart, char *elsepart);
+int		input(void);
+void		label(char *s, int t, int nh)	/* text s of type t nh half-lines up */;
+obj*		leftthing(int c)	/* called for {... or [... */ 		/* really ought to be separate functions */;
+obj*		linegen(int type);
+struct symtab*	lookup(char *s)	/* find s in symtab */;
+int		main(int argc, char **argv);
+void		makeattr(int type, int sub, YYSTYPE val)	/* add attribute type and val */;
+obj*		makebetween(double f, obj *p1, obj* p2)	/* make position between p1 and p2 */;
+void		makefattr(int type, int sub, double f)	/* double attr */;
+void		makeiattr(int type, int i)	/* int attr */;
+obj*		makenode(int type, int n);
+void		makeoattr(int type, obj *o)	/* obj* attr */;
+obj*		makepos(double x, double y)	/* make a position cell */;
+void		maketattr(int sub, char *p)	/* text attribute: takes two */;
+struct symtab*	makevar(char *s, int t, YYSTYPE v)	/* make variable named s in table */ 	/* assumes s is static or from tostring */;
+void		makevattr(char *p)	/* varname attribute */;
+obj*		movegen(void);
+int		nextchar(void);
+void		nextfor(void)	/* do one iteration of a for loop */;
+void		pbstr(char *s);
+void		popsrc(void)	/* restore an old one */;
+void		print(void);
+void		printexpr(double f)	/* print expression for debugging */;
+void		printlf(int line, char *name);
+void		printpos(obj *p)	/* print position for debugging */;
+void		pushsrc(int type, char *ptr)	/* new input source */;
+int		quadrant(double x, double y);
+void		reset(void);
+void		resetvar(void)	/* reset variables listed */;
+obj*		rightthing(obj *p, int c)	/* called for ... ] or ... } */;
+void		savetext(int t, char *s)	/* record text elements for current object */;
+void		setdefaults(void)	/* set default sizes for variables like boxht */;
+int		setdir(int n)	/* set direction (hvmode) from LEFT, RIGHT, etc. */;
+void		setfval(char *s, double f)	/* set variable s to f */;
+void		shell_exec(void)	/* do it */;
+void		shell_init(void)	/* set up to interpret a shell command */;
+void		shell_text(char *s)	/* add string to command being collected */;
+void		space(double x0, double y0, double x1, double y1)	/* set limits of page */;
+void		spline(double x, double y, double/*sic*/ n, float *p, int dashed, double ddval);
+char*		sprintgen(char *fmt);
+obj*		subpos(obj *p, obj *q);
+obj*		textgen(void);
+char*		tostring(char *s);
+void		troff(char *s);
+obj*		troffgen(char *s)	/* save away a string of troff commands */;
+void		undefine(char *s)	/* undefine macro */;
+int		unput(int c);
+int		whatpos(obj *p, int corner, double *px, double *py)	/* what is the position (no side effect) */;
+void		yyerror(char *s);
+int		yyparse(void);
+
+#include "tex.h"
+
blob - /dev/null
blob + 8a706dc587eda5608ead5d20079b993f3836d5b5 (mode 644)
--- /dev/null
+++ src/cmd/tpic/picl.l
@@ -0,0 +1,261 @@
+%Start A str def sc br thru sh
+%e 1700
+%k 120
+%a 1800
+%o 1500
+%p 5000
+%n 700
+
+%{
+#undef	input
+#undef	unput
+#include <stdio.h>
+#include <ctype.h>
+#include "pic.h"
+#include "y.tab.h"
+
+extern	double	atof();
+extern	char	*filename;
+extern	struct	symtab	symtab[];
+extern	struct	symtab*copythru();
+
+#define	CADD	cbuf[clen++]=yytext[0]; if(clen>=CBUFLEN-1) {ERROR "string too long" WARNING; BEGIN A;}
+#define	CBUFLEN	500
+char	cbuf[CBUFLEN];
+int	c, clen, cflag, delim;
+int	ifsw	= 0;	/* 1 if if statement in progress */
+%}
+
+A	[a-zA-Z_]
+B	[a-zA-Z0-9_]
+D	[0-9]
+WS	[ \t]
+
+%%
+	switch (yybgin-yysvec-1) {	/* witchcraft */
+	case 0:
+		BEGIN A;
+		break;
+	case sc:
+		BEGIN A;
+		return('}');
+	case br:
+		BEGIN A;
+		return(']');
+	}
+
+<A>{WS}		;
+<A>"\\"\n	;
+<A>\n		{ return(ST); }
+<A>";"		{ return(ST); }
+<A>"}"		{ BEGIN sc; return(ST); }
+<A>"]"		{ BEGIN br; return(ST); }
+
+<A>^".PS".*	{ if (curfile == infile) ERROR ".PS found inside .PS/.PE" WARNING; }
+<A>^"."P[EF].*	{ if (curfile == infile) {
+			yylval.i = yytext[2];
+			PEseen = 1;
+			return(EOF);
+		  }
+		}
+<A>^".".*	{ yylval.p = tostring(yytext); return(TROFF); }
+
+<A>print	return(yylval.i = PRINT);
+<A>box		return(yylval.i = BOX);
+<A>circle	return(yylval.i = CIRCLE);
+<A>arc		return(yylval.i = ARC);
+<A>ellipse	return(yylval.i = ELLIPSE);
+<A>arrow	return(yylval.i = ARROW);
+<A>spline	return(yylval.i = SPLINE);
+<A>line		return(yylval.i = LINE);
+<A>move		return(yylval.i = MOVE);
+<A>"[]"		return(yylval.i = BLOCK);
+<A>reset	return(RESET);
+<A>sprintf	return(SPRINTF);
+
+<A>same		return(SAME);
+<A>between	return(BETWEEN);
+<A>and		return(AND);
+
+<A>of		;
+<A>the		;
+<A>way		;
+
+<A>"."(e|east)		{ yylval.i = EAST; return(CORNER); }
+<A>"."(r|right)		{ yylval.i = EAST; return(CORNER); }
+<A>"."(w|west)		{ yylval.i = WEST; return(CORNER); }
+<A>"."(l|left)		{ yylval.i = WEST; return(CORNER); }
+<A>"."(n|north)		{ yylval.i = NORTH; return(CORNER); }
+<A>"."(t|top)		{ yylval.i = NORTH; return(CORNER); }
+<A>"."(s|south)		{ yylval.i = SOUTH; return(CORNER); }
+<A>"."(b|bot|bottom)	{ yylval.i = SOUTH; return(CORNER); }
+<A>"."(c|center)	{ yylval.i = CENTER; return(CORNER); }
+<A>".start"		{ yylval.i = START; return(CORNER); }
+<A>".end"		{ yylval.i = END; return(CORNER); }
+<A>".ne"		{ yylval.i = NE; return(CORNER); }
+<A>".se"		{ yylval.i = SE; return(CORNER); }
+<A>".nw"		{ yylval.i = NW; return(CORNER); }
+<A>".sw"		{ yylval.i = SW; return(CORNER); }
+
+<A>top" "+of		{ yylval.i = NORTH; return(CORNER); }
+<A>north" "+of		{ yylval.i = NORTH; return(CORNER); }
+<A>bottom" "+of		{ yylval.i = SOUTH; return(CORNER); }
+<A>south" "+of		{ yylval.i = SOUTH; return(CORNER); }
+<A>left" "+of		{ yylval.i = WEST; return(CORNER); }
+<A>west" "+of		{ yylval.i = WEST; return(CORNER); }
+<A>right" "+of		{ yylval.i = EAST; return(CORNER); }
+<A>east" "+of		{ yylval.i = EAST; return(CORNER); }
+<A>center" "+of		{ yylval.i = CENTER; return(CORNER); }
+<A>start" "+of		{ yylval.i = START; return(CORNER); }
+<A>end" "+of		{ yylval.i = END; return(CORNER); }
+
+<A>height|ht	{ yylval.i = HEIGHT; return(ATTR); }
+<A>width|wid	{ yylval.i = WIDTH; return(ATTR); }
+<A>radius|rad	{ yylval.i = RADIUS; return(ATTR); }
+<A>diameter|diam { yylval.i = DIAMETER; return(ATTR); }
+<A>size		{ yylval.i = SIZE; return(ATTR); }
+<A>left		{ yylval.i = LEFT; return(DIR); }
+<A>right	{ yylval.i = RIGHT; return(DIR); }
+<A>up		{ yylval.i = UP; return(DIR); }
+<A>down		{ yylval.i = DOWN; return(DIR); }
+<A>cw		{ yylval.i = CW; return(ATTR); }
+<A>clockwise	{ yylval.i = CW; return(ATTR); }
+<A>ccw		{ yylval.i = CCW; return(ATTR); }
+<A>invis(ible)?	{ yylval.i = INVIS; return(ATTR); }
+<A>fill		{ yylval.i = FILL; return ATTR; }
+<A>solid	;
+<A>dot(ted)?	return(yylval.i = DOT);
+<A>dash(ed)?	return(yylval.i = DASH);
+<A>chop		return(yylval.i = CHOP);
+
+<A>spread	{ yylval.i = SPREAD; return TEXTATTR; }
+<A>ljust	{ yylval.i = LJUST; return TEXTATTR; }
+<A>rjust	{ yylval.i = RJUST; return TEXTATTR; }
+<A>above	{ yylval.i = ABOVE; return TEXTATTR; }
+<A>below	{ yylval.i = BELOW; return TEXTATTR; }
+<A>center	{ yylval.i = CENTER; return TEXTATTR; }
+
+<A>"<-"		{ yylval.i = HEAD1; return(HEAD); }
+<A>"->"		{ yylval.i = HEAD2; return(HEAD); }
+<A>"<->"	{ yylval.i = HEAD12; return(HEAD); }
+
+<A>".x"			return(yylval.i = DOTX);
+<A>".y"			return(yylval.i = DOTY);
+<A>"."(ht|height)	return(yylval.i = DOTHT);
+<A>"."(wid|width)	return(yylval.i = DOTWID);
+<A>"."(rad|radius)	return(yylval.i = DOTRAD);
+
+<A>from		return(yylval.i = FROM);
+<A>to		return(yylval.i = TO);
+<A>at		return(yylval.i = AT);
+<A>by		return(yylval.i = BY);
+<A>with		return(yylval.i = WITH);
+<A>last		return(yylval.i = LAST);
+
+<A>log		return(LOG);
+<A>exp		return(EXP);
+<A>sin		return(SIN);
+<A>cos		return(COS);
+<A>atan2	return(ATAN2);
+<A>sqrt		return(SQRT);
+<A>rand		return(RAND);
+<A>max		return(MAX);
+<A>min		return(MIN);
+<A>int		return(INT);
+
+<A>"=="		return(EQ);
+<A>">="		return(GE);
+<A>"<="		return(LE);
+<A>"!="		return(NEQ);
+<A>">"		return(GT);
+<A>"<"		return(LT);
+<A>"&&"		return(ANDAND);
+<A>"||"		return(OROR);
+<A>"!"		return(NOT);	
+
+<A>Here		return(yylval.i = HERE);
+
+<A>for		return(FOR);
+<A>^Endfor\n	{ endfor(); }
+<A>do		{ yylval.p = delimstr("loop body"); return(DOSTR); }
+
+<A>copy|include		return(COPY);
+<A>(thru|through){WS}+	{ BEGIN thru; return(THRU); }
+<thru>{A}{B}*|.		{ yylval.st = copythru(yytext); BEGIN A; return(DEFNAME); }
+<A>until		return(UNTIL);
+
+<A>if		{ ifsw = 1; return(IF); }
+<A>then		{ if (!ifsw) { yylval.i = THEN; return(ATTR); }
+		  yylval.p = delimstr("then part"); ifsw = 0;
+		  return(THENSTR); }
+<A>else		{ yylval.p = delimstr("else part"); return(ELSESTR); }
+
+<A>sh{WS}+	{ BEGIN sh;
+		  if ((delim = input()) == '{') delim = '}';	/* no nested {} */
+		  shell_init(); }
+<sh>{A}{B}*	{ struct symtab *p;
+		  if (yytext[0] == delim) {
+			shell_exec();
+			BEGIN A;
+		  } else {
+			p = lookup(yytext);
+			if (p != NULL && p->s_type == DEFNAME) {
+				c = input();
+				unput(c);
+				if (c == '(')
+					dodef(p);
+				else
+					pbstr(p->s_val.p);
+			} else
+				shell_text(yytext);
+		  }
+		}
+<sh>.|\n	{ if (yytext[0] == delim) {
+			shell_exec();
+			BEGIN A;
+		  } else
+			shell_text(yytext);
+		}
+
+<A>define{WS}+		{ BEGIN def; }
+<def>{A}{B}*		{ definition(yytext); BEGIN A; }
+<A>undef(ine)?{WS}+{A}{B}*	{ undefine(yytext); }
+
+<A>first		{ yylval.i = 1; return(NTH); }
+<A>{D}+(th|nd|rd|st)	{ yylval.i = atoi(yytext); return(NTH); }
+<A>({D}+("."?){D}*|"."{D}+)((e|E)("+"|-)?{D}+)?i? {
+		  	yylval.f = atof(yytext); return(NUMBER); }
+
+<A>{A}{B}* {	struct symtab *p;
+		p = lookup(yytext);
+		if (p != NULL && p->s_type == DEFNAME) {
+			c = input();
+			unput(c);
+			if (c == '(')	/* it's name(...) */
+				dodef(p);
+			else {	/* no argument list */
+				pbstr(p->s_val.p);
+				dprintf("pushing back `%s'\n", p->s_val.p);
+			}
+		} else if (islower(yytext[0])) {
+			yylval.p = tostring(yytext);
+			return(VARNAME);
+		} else {
+			yylval.p = tostring(yytext);
+			return(PLACENAME);
+		}
+	}
+
+<A>\"		{ BEGIN str; clen=0; }
+<str>\"		{ cbuf[clen]=0; yylval.p = tostring(cbuf); BEGIN A; return(TEXT); }
+<str>\n		{ cbuf[clen]=0; ERROR "missing quote in string \"%s\"", cbuf WARNING;
+				BEGIN A; return(ST); }
+<str>"\\\""	{ cbuf[clen++]='"'; }
+<str>"\\\\"	{ cbuf[clen++]='\\'; }
+<str>.		{ CADD; }
+
+<A>#.*		;
+
+<A>.		return(yylval.i = yytext[0]);
+
+%%
blob - /dev/null
blob + 25ffd4f941e16afa409e55727f9923c358e1fab7 (mode 644)
--- /dev/null
+++ src/cmd/tpic/picy.c
@@ -0,0 +1,1239 @@
+
+#line	2	"/usr/local/plan9/src/cmd/tpic/picy.y"
+#include <stdio.h>
+#include "pic.h"
+#include <math.h>
+YYSTYPE	y;
+int yylex(void);
+extern	int	yyerrflag;
+#ifndef	YYMAXDEPTH
+#define	YYMAXDEPTH	150
+#endif
+YYSTYPE	yylval;
+YYSTYPE	yyval;
+#define	BOX	1
+#define	LINE	2
+#define	ARROW	3
+#define	CIRCLE	4
+#define	ELLIPSE	5
+#define	ARC	6
+#define	SPLINE	7
+#define	BLOCK	8
+#define	TEXT	9
+#define	TROFF	10
+#define	MOVE	11
+#define	BLOCKEND	12
+#define	PLACE	13
+#define	PRINT	57359
+#define	RESET	57360
+#define	THRU	57361
+#define	UNTIL	57362
+#define	FOR	57363
+#define	IF	57364
+#define	COPY	57365
+#define	THENSTR	57366
+#define	ELSESTR	57367
+#define	DOSTR	57368
+#define	PLACENAME	57369
+#define	VARNAME	57370
+#define	SPRINTF	57371
+#define	DEFNAME	57372
+#define	ATTR	57373
+#define	TEXTATTR	57374
+#define	LEFT	57375
+#define	RIGHT	57376
+#define	UP	57377
+#define	DOWN	57378
+#define	FROM	57379
+#define	TO	57380
+#define	AT	57381
+#define	BY	57382
+#define	WITH	57383
+#define	HEAD	57384
+#define	CW	57385
+#define	CCW	57386
+#define	THEN	57387
+#define	HEIGHT	57388
+#define	WIDTH	57389
+#define	RADIUS	57390
+#define	DIAMETER	57391
+#define	LENGTH	57392
+#define	SIZE	57393
+#define	CORNER	57394
+#define	HERE	57395
+#define	LAST	57396
+#define	NTH	57397
+#define	SAME	57398
+#define	BETWEEN	57399
+#define	AND	57400
+#define	EAST	57401
+#define	WEST	57402
+#define	NORTH	57403
+#define	SOUTH	57404
+#define	NE	57405
+#define	NW	57406
+#define	SE	57407
+#define	SW	57408
+#define	START	57409
+#define	END	57410
+#define	DOTX	57411
+#define	DOTY	57412
+#define	DOTHT	57413
+#define	DOTWID	57414
+#define	DOTRAD	57415
+#define	NUMBER	57416
+#define	LOG	57417
+#define	EXP	57418
+#define	SIN	57419
+#define	COS	57420
+#define	ATAN2	57421
+#define	SQRT	57422
+#define	RAND	57423
+#define	MIN	57424
+#define	MAX	57425
+#define	INT	57426
+#define	DIR	57427
+#define	DOT	57428
+#define	DASH	57429
+#define	CHOP	57430
+#define	FILL	57431
+#define	ST	57432
+#define	OROR	57433
+#define	ANDAND	57434
+#define	GT	57435
+#define	LT	57436
+#define	LE	57437
+#define	GE	57438
+#define	EQ	57439
+#define	NEQ	57440
+#define	UMINUS	57441
+#define	NOT	57442
+#define YYEOFCODE 1
+#define YYERRCODE 2
+static	const	short	yyexca[] =
+{-1, 0,
+	1, 2,
+	-2, 0,
+-1, 1,
+	1, -1,
+	-2, 0,
+-1, 203,
+	94, 0,
+	95, 0,
+	96, 0,
+	97, 0,
+	98, 0,
+	99, 0,
+	-2, 156,
+-1, 210,
+	94, 0,
+	95, 0,
+	96, 0,
+	97, 0,
+	98, 0,
+	99, 0,
+	-2, 155,
+-1, 211,
+	94, 0,
+	95, 0,
+	96, 0,
+	97, 0,
+	98, 0,
+	99, 0,
+	-2, 157,
+-1, 212,
+	94, 0,
+	95, 0,
+	96, 0,
+	97, 0,
+	98, 0,
+	99, 0,
+	-2, 158,
+-1, 213,
+	94, 0,
+	95, 0,
+	96, 0,
+	97, 0,
+	98, 0,
+	99, 0,
+	-2, 159,
+-1, 214,
+	94, 0,
+	95, 0,
+	96, 0,
+	97, 0,
+	98, 0,
+	99, 0,
+	-2, 160,
+-1, 266,
+	94, 0,
+	95, 0,
+	96, 0,
+	97, 0,
+	98, 0,
+	99, 0,
+	-2, 156,
+};
+#define	YYNPROD	175
+#define	YYPRIVATE 57344
+#define	YYLAST	1551
+static	const	short	yyact[] =
+{
+ 171, 330, 137,  52, 316,  67, 270, 123, 124, 308,
+ 315,  42, 269, 239, 108,  32, 135, 160, 135, 159,
+ 158, 157,  94, 224, 130, 131, 132, 133, 134,  43,
+ 156, 155,  91,  50, 154, 153, 152, 151, 135,  97,
+  80, 104, 295, 294, 243, 232, 230,  40, 121, 126,
+ 129,  82, 123, 124, 312, 150, 147, 109, 110, 111,
+ 112, 113, 271,  50, 121, 225,  71, 106,  41, 162,
+ 101, 164, 128,  40, 331, 332, 333, 334, 136, 127,
+ 243, 167, 191, 187,  72,  73,  74,  75,  76,  77,
+  78,  79, 272, 200, 197, 109, 110, 111, 112, 113,
+ 136, 125, 121, 123, 124, 123, 124, 201, 203, 104,
+ 205, 206, 207, 208, 209, 210, 211, 212, 213, 214,
+ 215, 216, 217,  38, 218, 221, 231, 111, 112, 113,
+  50,  50, 121, 317, 123, 124, 192, 202, 204, 123,
+ 124, 195, 196, 166,  84, 229, 220, 223, 165,  95,
+  96,  35, 233, 234, 235, 236, 237, 238,  34, 240,
+ 241, 242, 189, 168, 283, 244, 246, 281,  36,  44,
+ 122, 249, 248, 250, 104, 104, 104, 104, 104,  89,
+ 123, 124, 258, 259, 260, 261,   4,  70,  85,  37,
+  92, 296, 263, 264, 227, 266,  50,  50,  50,  50,
+  50,  80, 265, 251, 252, 253, 254, 257, 119, 114,
+ 194, 115, 116, 117, 118, 109, 110, 111, 112, 113,
+ 274, 169, 121, 276, 283, 284,  37,  99, 188, 279,
+ 114, 194, 115, 116, 117, 118, 109, 110, 111, 112,
+ 113, 262,  85, 121, 281, 282, 190,  35, 277, 130,
+ 131, 132, 133, 134,  86,  87, 198, 227, 228, 162,
+ 193, 164,   2,  83,  36,  69,   1,   5,  37,  39,
+ 161, 301, 104, 104, 304,  26, 306,   6, 185,  24,
+  12,  24,  13, 147,  14,  24, 300, 199,  88,  81,
+ 309,  90, 310, 311,  50,  50, 278,  68, 163, 313,
+ 314, 302, 303,   0,   0,  24, 318,   0, 319, 140,
+ 144, 145, 141, 142, 143, 146, 247, 327,  24,  24,
+   0,  65,  66,  68, 280,   0,   0, 335,   0, 297,
+   0, 336,   0,   0,   0,   0, 337,   0,   0,  16,
+  20,  21,  17,  18,  19,  22,   0,  35,  25,  23,
+  51,  46,  10,  11, 267, 268,  30,  31,  29, 149,
+  24,   0, 102,  46,  36,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,  65,  66,  68,  53,  24,
+   0,   0,   0,   0,   0,   0,   0,  65,  66,  68,
+  53,   0,   0,   0,   0,   0,   0,  45,  55,  56,
+  57,  58,  59,  60,  61,  63,  62,  64,   0,  45,
+  55,  56,  57,  58,  59,  60,  61,  63,  62,  64,
+   9,   0,   0,   0,  48, 100,   0,   0, 299,  54,
+   0,   0,   0,   0,   0,   0,  48,  35,  93,   0,
+   0,  54,   0,   0,   0,   0,  27,   0,  33,   0,
+  49,   0,  51,  46,  36,   0, 170, 179,   0,   0,
+   0,   0, 173, 174, 175, 176, 177, 180, 140, 144,
+ 145, 141, 142, 143, 146, 245,   0,  65,  66,  68,
+  53, 178, 120, 119, 114, 194, 115, 116, 117, 118,
+ 109, 110, 111, 112, 113,   0,   0, 121,   0,  45,
+  55,  56,  57,  58,  59,  60,  61,  63,  62,  64,
+ 172, 181, 182, 183, 184,   0,   0,  35, 139,   0,
+   0,   0,  47,   8,   0,   8,  48,   0,  35,   8,
+   0,  54,  51,  46,  36,   0,   0,   0,   0,   0,
+  93,   0,   0,  51,  46,  36,   0,   0,   0,   8,
+   0,   0,   0,   0,   0,   0,   0,  65,  66,  68,
+  53,   0,   8, 103,   0,   0, 339,   0,  65,  66,
+  68,  53,   0,   0,   0,   0,   0,   0,   0,  45,
+  55,  56,  57,  58,  59,  60,  61,  63,  62,  64,
+  45,  55,  56,  57,  58,  59,  60,  61,  63,  62,
+  64,  51,  46,   0,   8,   0,  48,   0,   0,   0,
+   0,  54,   0,   0,   0,   0,   0,  48,   0,   0,
+  93,   0,  54,   8,   0,   0, 255,  66,  68,  53,
+   0,  49, 120, 119, 114, 194, 115, 116, 117, 118,
+ 109, 110, 111, 112, 113,   0,   0, 121,  45,  55,
+  56,  57,  58,  59,  60,  61,  63,  62,  64,  16,
+  20,  21,  17,  18,  19,  22,   0,  35,  25,  23,
+   0,   0,  10,  11,   0,  48,  30,  31,  29,   0,
+  54,   0,   7,  28,  36,   0,   0,   0, 256,  49,
+  16,  20,  21,  17,  18,  19,  22,   0,  35,  25,
+  23,   0,   0,  10,  11,   0,   0,  30,  31,  29,
+   0,   0,   0,   7,  28,  36,   0,   3,   0,  16,
+  20,  21,  17,  18,  19,  22,   0,  35,  25,  23,
+  51,  46,  10,  11,   0,   0,  30,  31,  29,   0,
+   9,   0,   7,  28,  36,  15, 140, 144, 145, 141,
+ 142, 143, 146, 148,   0,  65,  66,  68,  53,   0,
+   0,   0,   0,   0,   0,   0,  27, 186,  33,   0,
+   0,   9,   0,   0,   0,   0,  15,  45,  55,  56,
+  57,  58,  59,  60,  61,  63,  62,  64,  51,  46,
+   0,   0,   0,   0,  98,   0, 149,  27,   0,  33,
+   9,   0,   0,   0,  48,  15,   0,   0,   0,  54,
+   0,   0,   0,  65,  66,  68,  53,   0,  49,   0,
+   0,   0,   0,   0,   0,   0,  27,   0,  33,   0,
+  51,  46,   0,   0,   0,  45,  55,  56,  57,  58,
+  59,  60,  61,  63,  62,  64,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,  65,  66,  68,  53,   0,
+   0,   0,  48,   0,   0,   0,   0,  54,   0,   0,
+   0,   0,   0,   0,   0,   0, 222,  45,  55,  56,
+  57,  58,  59,  60,  61,  63,  62,  64,  16,  20,
+  21,  17,  18,  19,  22, 108,  35,  25,  23,   0,
+   0,  10,  11,   0,  48,  30,  31,  29,   0,  54,
+   0,   7,  28,  36,   0,   0,   0,   0, 219,   0,
+   0, 140, 144, 145, 141, 142, 143, 146, 138,   0,
+ 120, 119, 114, 107, 115, 116, 117, 118, 109, 110,
+ 111, 112, 113,   0,   0, 121,   0,   0, 106,   0,
+   0,   0,   0,   0, 226, 120, 119, 114, 194, 115,
+ 116, 117, 118, 109, 110, 111, 112, 113,   0,   9,
+ 121, 139,   0, 307,  15,   0,   0,   0,   0, 226,
+   0, 120, 119, 114, 194, 115, 116, 117, 118, 109,
+ 110, 111, 112, 113,   0,  27, 121,  33,   0, 305,
+   0,   0,   0,   0,   0, 226, 120, 119, 114, 194,
+ 115, 116, 117, 118, 109, 110, 111, 112, 113,   0,
+   0, 121,   0,   0,   0,   0,   0,   0,   0,   0,
+ 329, 120, 119, 114, 194, 115, 116, 117, 118, 109,
+ 110, 111, 112, 113,   0,   0, 121,   0,   0,   0,
+   0,   0,   0,   0,   0, 328, 120, 119, 114, 194,
+ 115, 116, 117, 118, 109, 110, 111, 112, 113,   0,
+   0, 121,   0,   0,   0,   0,   0,   0,   0,   0,
+ 322, 120, 119, 114, 194, 115, 116, 117, 118, 109,
+ 110, 111, 112, 113,   0,   0, 121,   0,   0,   0,
+   0,   0,   0,   0,   0, 321, 120, 119, 114, 194,
+ 115, 116, 117, 118, 109, 110, 111, 112, 113,   0,
+   0, 121,   0,   0,   0,   0,   0,   0,   0,   0,
+ 320, 120, 119, 114, 194, 115, 116, 117, 118, 109,
+ 110, 111, 112, 113,   0,   0, 121,   0,   0,   0,
+   0,   0,   0,   0,   0, 293, 120, 119, 114, 194,
+ 115, 116, 117, 118, 109, 110, 111, 112, 113,   0,
+   0, 121,   0,   0,   0,   0,   0,   0,   0,   0,
+ 290, 120, 119, 114, 194, 115, 116, 117, 118, 109,
+ 110, 111, 112, 113,   0,   0, 121,   0,   0,   0,
+   0,   0,   0,   0,   0, 288, 120, 119, 114, 194,
+ 115, 116, 117, 118, 109, 110, 111, 112, 113,   0,
+   0, 121,   0,   0,   0,   0,   0,   0,   0,   0,
+ 287, 120, 119, 114, 194, 115, 116, 117, 118, 109,
+ 110, 111, 112, 113,   0,   0, 121,   0,   0,   0,
+   0,   0,   0,   0,   0, 286, 120, 119, 114, 194,
+ 115, 116, 117, 118, 109, 110, 111, 112, 113,   0,
+   0, 121,   0, 108,   0,   0,   0,   0,   0,   0,
+ 285, 120, 119, 114, 194, 115, 116, 117, 118, 109,
+ 110, 111, 112, 113, 108,   0, 121,   0,   0,   0,
+   0,   0,   0,   0,   0, 226, 105,   0, 120, 119,
+ 114, 107, 115, 116, 117, 118, 109, 110, 111, 112,
+ 113,   0,   0, 121,   0,   0, 106,   0,   0, 120,
+ 119, 114, 107, 115, 116, 117, 118, 109, 110, 111,
+ 112, 113,   0,   0, 121,   0,   0, 106, 120, 119,
+ 114, 194, 115, 116, 117, 118, 109, 110, 111, 112,
+ 113,   0,   0, 121,   0,   0, 292, 120, 119, 114,
+ 194, 115, 116, 117, 118, 109, 110, 111, 112, 113,
+   0,   0, 121,   0,   0, 291, 120, 119, 114, 194,
+ 115, 116, 117, 118, 109, 110, 111, 112, 113,   0,
+   0, 121, 338,   0, 289, 120, 119, 114, 194, 115,
+ 116, 117, 118, 109, 110, 111, 112, 113,   0,   0,
+ 121,   0,   0, 275, 120, 119, 114, 194, 115, 116,
+ 117, 118, 109, 110, 111, 112, 113, 326,   0, 121,
+   0,   0, 273,   0,   0,   0,   0,   0,   0,   0,
+   0, 325,   0, 324,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0, 323, 120, 119,
+ 114, 194, 115, 116, 117, 118, 109, 110, 111, 112,
+ 113, 298,   0, 121, 120, 119, 114, 194, 115, 116,
+ 117, 118, 109, 110, 111, 112, 113,   0,   0, 121,
+   0,   0,   0, 120, 119, 114, 194, 115, 116, 117,
+ 118, 109, 110, 111, 112, 113,   0,   0, 121, 120,
+ 119, 114, 194, 115, 116, 117, 118, 109, 110, 111,
+ 112, 113,   0,   0, 121, 120, 119, 114, 194, 115,
+ 116, 117, 118, 109, 110, 111, 112, 113,   0,   0,
+ 121
+};
+static	const	short	yypact[] =
+{
+ 715,-1000, 884,-1000,-1000,  33, 884, -62, -22,-1000,
+ 516, 159,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,
+-1000,-1000,-1000,-1000, 139,-1000, 884,-1000, -40, 235,
+ 151, 505, 117,-1000, 118,-1000, -76,-1000,-1000, 686,
+ 335,-1000,1216,  80,  11,-1000, -40,-1000, 323, 703,
+ 180, -14, 917, 742, 323, -78, -79, -80, -81, -84,
+ -85, -94, -95, -96, -98, 243,-1000,  96,-1000,  53,
+-1000, 425, 425, 425, 425, 425, 425, 425, 425, 425,
+ 117, 655, 323, 235,-1000,-1000, 132, 139,  45,-1000,
+ 236,1392,  43, 323, 180,-1000,-1000, 139,-1000,-1000,
+ 884,   3, -36, -22,1237,-1000, 323, 703, 703, 323,
+ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ 323, 323,-1000, 803, 761,-1000, -59, -93, -45, 838,
+-1000,-1000,-1000,-1000,-1000,-1000, 230,  93, -68,-1000,
+-1000,-1000,-1000,-1000,-1000,-1000,-1000,  74, -69,-1000,
+ -59, 323, 323, 323, 323, 323, 323,-103, 323, 323,
+ 323, -70, 464, 305,-1000,-1000,-1000,-1000, 144,-1000,
+ 323,1392, 323, 703, 703, 703, 703, 574,-1000,-1000,
+-1000, 323, 323, 323, 323, 139,-1000,1392,-1000,-1000,
+-1000, 323, 323, 177, 323, 139, 139,1189,-104,-1000,
+-1000,1392, -48, -43,  34,  25,  25, -59, -59, -59,
+  -5,  -5,  -5,  -5,  -5, 136, 115, -59,1332, 323,
+ 180,1313, 323, 180,-1000, 269,-1000,-1000,-1000,-1000,
+ 217,-1000, 197,1164,1139,1114,1089,1294,1064,-1000,
+1275,1256,1039, 167,-1000, -71,-1000, -72,-1000,1392,
+1392,   5,   5,   5,   5, 243, 164,   5,1392,1392,
+1392,1392,-1000,1443, 390,-1000,  -5,-1000,-1000,-1000,
+ 323, 703, 703, 323, 889, 323, 863,-107, -34, 464,
+ 305,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000, 323,
+-1000, 323, 323,-1000, 140, 137,   2, 425, 323, 323,
+-106,1392,  39,   5,1392, 323,1392, 323,-1000,1014,
+ 989, 964,-1000,1427,1411,-1000, 323,-1000, 939, 914,
+-1000,-1000,-1000, -26,-1000, -26,-1000,1392,-1000,-1000,
+ 323,-1000,-1000,-1000,-1000, 323,1376, 540,-1000,-1000
+};
+static	const	short	yypgo[] =
+{
+   0,   0, 291, 522, 288, 158,   1, 286, 284, 282,
+ 280, 277, 186, 262,  29, 275, 267,  22,   5, 278,
+  15,   3,   2, 266, 265, 263, 144,  66, 241, 221
+};
+static	const	short	yyr1[] =
+{
+   0,  23,  23,  23,  13,  13,  12,  12,  12,  12,
+  12,  12,  12,  12,  12,  12,  12,  12,  12,  12,
+  12,  24,  24,  24,  24,   3,  10,  25,  25,  26,
+  26,  26,   9,   9,   9,   9,   8,   8,   2,   2,
+   2,   4,   6,   6,   6,   6,   6,  11,  16,  16,
+  16,  16,  16,  16,  16,  16,  16,  16,  28,  16,
+  15,  27,  27,  29,  29,  29,  29,  29,  29,  29,
+  29,  29,  29,  29,  29,  29,  29,  29,  29,  29,
+  29,  29,  29,  29,  29,  29,  29,  29,  19,  19,
+  20,  20,  20,   5,   5,   5,   7,   7,  14,  14,
+  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,
+  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,
+  17,  17,  17,  18,  18,  18,  21,  21,  21,  22,
+  22,  22,  22,  22,  22,  22,  22,   1,   1,   1,
+   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+   1,   1,   1,   1,   1
+};
+static	const	short	yyr2[] =
+{
+   0,   1,   0,   1,   1,   2,   2,   3,   3,   4,
+   4,   2,   1,   3,   3,   3,   3,   1,   1,   1,
+   1,   0,   1,   2,   3,   3,   2,   1,   2,   1,
+   2,   2,  10,   7,  10,   7,   4,   3,   1,   3,
+   3,   1,   1,   1,   1,   1,   0,   1,   2,   2,
+   2,   2,   2,   2,   2,   2,   2,   1,   0,   5,
+   1,   2,   0,   2,   1,   1,   2,   1,   2,   2,
+   2,   2,   2,   3,   4,   2,   1,   1,   1,   2,
+   1,   2,   1,   2,   1,   2,   1,   1,   1,   2,
+   1,   2,   2,   1,   4,   6,   1,   3,   1,   3,
+   3,   5,   5,   7,   7,   3,   3,   5,   6,   5,
+   1,   2,   2,   1,   2,   3,   3,   2,   3,   3,
+   1,   2,   2,   4,   4,   3,   2,   2,   1,   1,
+   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+   3,   3,   3,   3,   3,   2,   3,   2,   2,   2,
+   2,   2,   3,   4,   4,   3,   3,   3,   3,   3,
+   3,   3,   3,   2,   4,   4,   3,   4,   4,   6,
+   4,   3,   6,   6,   4
+};
+static	const	short	yychk[] =
+{
+-1000, -23, -13,   2, -12, -16, -11,  27,  -3,  85,
+  17,  18, -10,  -9,  -8,  90,   4,   7,   8,   9,
+   5,   6,  10,  14, -19,  13, -15, 111,  28,  23,
+  21,  22, -20, 113,  -5,  12,  29, -12,  90, -13,
+ 109,  90,  -1, -14,  -5,  74,  28,  -3, 101, 115,
+ -17,  27, -21,  55, 106,  75,  76,  77,  78,  79,
+  80,  81,  83,  82,  84,  52,  53, -18,  54, -24,
+  28, -27, -27, -27, -27, -27, -27, -27, -27, -27,
+ -20, -13,  91, -25, -26,  -5,  19,  20,  -4,  28,
+  -2,  -1,  -5, 115, -17,  32,  32, 115, 108, -12,
+  90, -14,  27,  -3,  -1,  90, 110,  95,  57, 100,
+ 101, 102, 103, 104,  94,  96,  97,  98,  99,  93,
+  92, 107,  90, 100, 101,  90,  -1, -14, -17,  -1,
+  69,  70,  71,  72,  73,  52, 114, -22,  11,  54,
+   4,   7,   8,   9,   5,   6,  10, -22,  11,  54,
+  -1, 115, 115, 115, 115, 115, 115, 115, 115, 115,
+ 115,  27, -21,  55, -18,  52,  90,  28, 110, -29,
+  31,  -1,  85,  37,  38,  39,  40,  41,  56,  32,
+  42,  86,  87,  88,  89, -19, 112,  -1, -26,  30,
+  -5,  37,  91,  24,  95,  98,  99,  -1,  -5, -12,
+  90,  -1, -14,  -1, -14,  -1,  -1,  -1,  -1,  -1,
+  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 115,
+ -17,  -1, 115, -17, 116, 110, 116,  27,  28,  52,
+ 114,  52, 114,  -1,  -1,  -1,  -1,  -1,  -1, 116,
+  -1,  -1,  -1, 114, -22,  11, -22,  11,  28,  -1,
+  -1, -14, -14, -14, -14,  52, 114, -14,  -1,  -1,
+  -1,  -1, -28,  -1,  -1,  25,  -1,  -5,  -5, 116,
+ 110, 110,  58, 110,  -1, 110,  -1, -17,  27, -21,
+  55,  27,  28,  27,  28, 116, 116, 116, 116, 110,
+ 116, 110, 110, 116, 114, 114,  27, -27,  38,  38,
+  -7,  -1, -14, -14,  -1, 110,  -1, 110, 116,  -1,
+  -1,  -1,  52,  -1,  -1, 116, 110,  94,  -1,  -1,
+ 116, 116, 116,  40,  26,  40,  26,  -1, 116, 116,
+  -6, 100, 101, 102, 103,  -6,  -1,  -1,  26,  26
+};
+static	const	short	yydef[] =
+{
+  -2,  -2,   1,   3,   4,   0,   0,   0,   0,  12,
+   0,  21,  17,  18,  19,  20,  62,  62,  62,  62,
+  62,  62,  62,  62,  62,  57,   0,  47,   0,   0,
+   0,   0,  88,  60,  90,  93,   0,   5,   6,   0,
+   0,  11,   0,   0,   0, 137, 138, 139,   0,   0,
+  98, 110,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0, 113, 120, 128,   0,
+  22,  48,  49,  50,  51,  52,  53,  54,  55,  56,
+  89,   0,   0,  26,  27,  29,   0,   0,   0,  41,
+   0,  38,   0,   0,   0,  92,  91,   0,   7,   8,
+  20,   0, 110, 139,   0,  13,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,  14,   0,   0,  15, 145,   0,  98,   0,
+ 147, 148, 149, 150, 151, 111,   0, 114, 136, 126,
+ 129, 130, 131, 132, 133, 134, 135, 117, 136, 127,
+ 163,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0, 112,   0,   0, 122, 121,  16,  23,   0,  61,
+  64,  65,  67,   0,   0,   0,   0,   0,  76,  77,
+  78,  80,  82,  84,  86,  87,  58,  25,  28,  30,
+  31,   0,   0,  37,   0,   0,   0,   0,   0,   9,
+  10, 100,   0,  -2,   0, 140, 141, 142, 143, 144,
+  -2,  -2,  -2,  -2,  -2, 161, 162, 166,   0,   0,
+ 105,   0,   0, 106,  99,   0, 146, 125, 152, 115,
+   0, 118,   0,   0,   0,   0,   0,   0,   0, 171,
+   0,   0,   0,   0, 116, 136, 119, 136,  24,  63,
+  66,  68,  69,  70,  71,  72,   0,  75,  79,  81,
+  83,  85,  62,   0,   0,  36,  -2,  39,  40,  94,
+   0,   0,   0,   0,   0,   0,   0,   0, 110,   0,
+   0, 123, 153, 124, 154, 164, 165, 167, 168,   0,
+ 170,   0,   0, 174,   0,   0,  73,  59,   0,   0,
+   0,  96,   0, 109, 101,   0, 102,   0, 107,   0,
+   0,   0,  74,   0,   0,  95,   0, 108,   0,   0,
+ 169, 172, 173,  46,  33,  46,  35,  97, 103, 104,
+   0,  42,  43,  44,  45,   0,   0,   0,  32,  34
+};
+static	const	short	yytok1[] =
+{
+   1,   4,   5,   6,   7,   8,   9,  10,  11,  12,
+  13,  14,  15,  16,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0, 104,   0,   0,
+ 115, 116, 102, 100, 110, 101, 114, 103,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0, 109,   0,
+   0,  91,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0, 113,   0, 112, 107,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0, 111,   0, 108
+};
+static	const	short	yytok2[] =
+{
+   2,   3,   0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,  17,  18,  19,  20,  21,
+  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
+  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,
+  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,
+  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,
+  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,
+  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,
+  82,  83,  84,  85,  86,  87,  88,  89,  90,  92,
+  93,  94,  95,  96,  97,  98,  99, 105, 106
+};
+static	const	long	yytok3[] =
+{
+   0
+};
+#define YYFLAG 		-1000
+#define YYERROR		goto yyerrlab
+#define YYACCEPT	return(0)
+#define YYABORT		return(1)
+#define	yyclearin	yychar = -1
+#define	yyerrok		yyerrflag = 0
+
+#ifdef	yydebug
+#include	"y.debug"
+#else
+#define	yydebug		0
+static	const	char*	yytoknames[1];		/* for debugging */
+static	const	char*	yystates[1];		/* for debugging */
+#endif
+
+/*	parser for yacc output	*/
+#ifdef YYARG
+#define	yynerrs		yyarg->yynerrs
+#define	yyerrflag	yyarg->yyerrflag
+#define yyval		yyarg->yyval
+#define yylval		yyarg->yylval
+#else
+int	yynerrs = 0;		/* number of errors */
+int	yyerrflag = 0;		/* error recovery flag */
+#endif
+
+static const char*
+yytokname(int yyc)
+{
+	static char x[10];
+
+	if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0]))
+	if(yytoknames[yyc-1])
+		return yytoknames[yyc-1];
+	sprintf(x, "<%d>", yyc);
+	return x;
+}
+
+static const char*
+yystatname(int yys)
+{
+	static char x[10];
+
+	if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0]))
+	if(yystates[yys])
+		return yystates[yys];
+	sprintf(x, "<%d>\n", yys);
+	return x;
+}
+
+static long
+#ifdef YYARG
+yylex1(struct Yyarg *yyarg)
+#else
+yylex1(void)
+#endif
+{
+	long yychar;
+	const long *t3p;
+	int c;
+
+#ifdef YYARG	
+	yychar = yylex(yyarg);
+#else
+	yychar = yylex();
+#endif
+	if(yychar <= 0) {
+		c = yytok1[0];
+		goto out;
+	}
+	if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) {
+		c = yytok1[yychar];
+		goto out;
+	}
+	if(yychar >= YYPRIVATE)
+		if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) {
+			c = yytok2[yychar-YYPRIVATE];
+			goto out;
+		}
+	for(t3p=yytok3;; t3p+=2) {
+		c = t3p[0];
+		if(c == yychar) {
+			c = t3p[1];
+			goto out;
+		}
+		if(c == 0)
+			break;
+	}
+	c = 0;
+
+out:
+	if(c == 0)
+		c = yytok2[1];	/* unknown char */
+	if(yydebug >= 3)
+		printf("lex %.4lX %s\n", yychar, yytokname(c));
+	return c;
+}
+
+int
+#ifdef YYARG
+yyparse(struct Yyarg *yyarg)
+#else
+yyparse(void)
+#endif
+{
+	struct
+	{
+		YYSTYPE	yyv;
+		int	yys;
+	} yys[YYMAXDEPTH], *yyp, *yypt;
+	const short *yyxi;
+	int yyj, yym, yystate, yyn, yyg;
+	long yychar;
+#ifndef YYARG
+	YYSTYPE save1, save2;
+	int save3, save4;
+
+	save1 = yylval;
+	save2 = yyval;
+	save3 = yynerrs;
+	save4 = yyerrflag;
+#endif
+
+	yystate = 0;
+	yychar = -1;
+	yynerrs = 0;
+	yyerrflag = 0;
+	yyp = &yys[-1];
+	goto yystack;
+
+ret0:
+	yyn = 0;
+	goto ret;
+
+ret1:
+	yyn = 1;
+	goto ret;
+
+ret:
+#ifndef YYARG
+	yylval = save1;
+	yyval = save2;
+	yynerrs = save3;
+	yyerrflag = save4;
+#endif
+	return yyn;
+
+yystack:
+	/* put a state and value onto the stack */
+	if(yydebug >= 4)
+		printf("char %s in %s", yytokname(yychar), yystatname(yystate));
+
+	yyp++;
+	if(yyp >= &yys[YYMAXDEPTH]) {
+		yyerror("yacc stack overflow");
+		goto ret1;
+	}
+	yyp->yys = yystate;
+	yyp->yyv = yyval;
+
+yynewstate:
+	yyn = yypact[yystate];
+	if(yyn <= YYFLAG)
+		goto yydefault; /* simple state */
+	if(yychar < 0)
+#ifdef YYARG
+		yychar = yylex1(yyarg);
+#else
+		yychar = yylex1();
+#endif
+	yyn += yychar;
+	if(yyn < 0 || yyn >= YYLAST)
+		goto yydefault;
+	yyn = yyact[yyn];
+	if(yychk[yyn] == yychar) { /* valid shift */
+		yychar = -1;
+		yyval = yylval;
+		yystate = yyn;
+		if(yyerrflag > 0)
+			yyerrflag--;
+		goto yystack;
+	}
+
+yydefault:
+	/* default state action */
+	yyn = yydef[yystate];
+	if(yyn == -2) {
+		if(yychar < 0)
+#ifdef YYARG
+		yychar = yylex1(yyarg);
+#else
+		yychar = yylex1();
+#endif
+
+		/* look through exception table */
+		for(yyxi=yyexca;; yyxi+=2)
+			if(yyxi[0] == -1 && yyxi[1] == yystate)
+				break;
+		for(yyxi += 2;; yyxi += 2) {
+			yyn = yyxi[0];
+			if(yyn < 0 || yyn == yychar)
+				break;
+		}
+		yyn = yyxi[1];
+		if(yyn < 0)
+			goto ret0;
+	}
+	if(yyn == 0) {
+		/* error ... attempt to resume parsing */
+		switch(yyerrflag) {
+		case 0:   /* brand new error */
+			yyerror("syntax error");
+			if(yydebug >= 1) {
+				printf("%s", yystatname(yystate));
+				printf("saw %s\n", yytokname(yychar));
+			}
+			goto yyerrlab;
+		yyerrlab:
+			yynerrs++;
+
+		case 1:
+		case 2: /* incompletely recovered error ... try again */
+			yyerrflag = 3;
+
+			/* find a state where "error" is a legal shift action */
+			while(yyp >= yys) {
+				yyn = yypact[yyp->yys] + YYERRCODE;
+				if(yyn >= 0 && yyn < YYLAST) {
+					yystate = yyact[yyn];  /* simulate a shift of "error" */
+					if(yychk[yystate] == YYERRCODE)
+						goto yystack;
+				}
+
+				/* the current yyp has no shift onn "error", pop stack */
+				if(yydebug >= 2)
+					printf("error recovery pops state %d, uncovers %d\n",
+						yyp->yys, (yyp-1)->yys );
+				yyp--;
+			}
+			/* there is no state on the stack with an error shift ... abort */
+			goto ret1;
+
+		case 3:  /* no shift yet; clobber input char */
+			if(yydebug >= YYEOFCODE)
+				printf("error recovery discards %s\n", yytokname(yychar));
+			if(yychar == YYEOFCODE)
+				goto ret1;
+			yychar = -1;
+			goto yynewstate;   /* try again in the same state */
+		}
+	}
+
+	/* reduction by production yyn */
+	if(yydebug >= 2)
+		printf("reduce %d in:\n\t%s", yyn, yystatname(yystate));
+
+	yypt = yyp;
+	yyp -= yyr2[yyn];
+	yyval = (yyp+1)->yyv;
+	yym = yyn;
+
+	/* consult goto table to find next state */
+	yyn = yyr1[yyn];
+	yyg = yypgo[yyn];
+	yyj = yyg + yyp->yys + 1;
+
+	if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn)
+		yystate = yyact[yyg];
+	switch(yym) {
+		
+case 3:
+#line	63	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ ERROR "syntax error" WARNING; } break;
+case 6:
+#line	72	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ codegen = 1; makeiattr(0, 0); } break;
+case 7:
+#line	73	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ rightthing(yypt[-2].yyv.o, '}'); yyval.o = yypt[-1].yyv.o; } break;
+case 8:
+#line	74	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ y.o=yypt[-0].yyv.o; makevar(yypt[-2].yyv.p,PLACENAME,y); yyval.o = yypt[-0].yyv.o; } break;
+case 9:
+#line	75	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ y.o=yypt[-0].yyv.o; makevar(yypt[-3].yyv.p,PLACENAME,y); yyval.o = yypt[-0].yyv.o; } break;
+case 10:
+#line	76	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ y.o=yypt[-1].yyv.o; makevar(yypt[-3].yyv.p,PLACENAME,y); yyval.o = yypt[-1].yyv.o; } break;
+case 11:
+#line	77	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ y.f = yypt[-1].yyv.f; yyval.o = y.o; yyval.o = makenode(PLACE, 0); } break;
+case 12:
+#line	78	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ setdir(yypt[-0].yyv.i); yyval.o = makenode(PLACE, 0); } break;
+case 13:
+#line	79	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ printexpr(yypt[-1].yyv.f); yyval.o = makenode(PLACE, 0); } break;
+case 14:
+#line	80	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ printpos(yypt[-1].yyv.o); yyval.o = makenode(PLACE, 0); } break;
+case 15:
+#line	81	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ printf("%s\n", yypt[-1].yyv.p); free(yypt[-1].yyv.p); yyval.o = makenode(PLACE, 0); } break;
+case 16:
+#line	82	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ resetvar(); makeiattr(0, 0); yyval.o = makenode(PLACE, 0); } break;
+case 22:
+#line	91	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makevattr(yypt[-0].yyv.p); } break;
+case 23:
+#line	92	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makevattr(yypt[-0].yyv.p); } break;
+case 24:
+#line	93	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makevattr(yypt[-0].yyv.p); } break;
+case 25:
+#line	97	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f=y.f=yypt[-0].yyv.f; makevar(yypt[-2].yyv.p,VARNAME,y); checkscale(yypt[-2].yyv.p); } break;
+case 26:
+#line	101	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ copy(); } break;
+case 29:
+#line	108	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ copyfile(yypt[-0].yyv.p); } break;
+case 30:
+#line	109	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ copydef(yypt[-0].yyv.st); } break;
+case 31:
+#line	110	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ copyuntil(yypt[-0].yyv.p); } break;
+case 32:
+#line	115	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ forloop(yypt[-8].yyv.p, yypt[-6].yyv.f, yypt[-4].yyv.f, yypt[-2].yyv.i, yypt[-1].yyv.f, yypt[-0].yyv.p); } break;
+case 33:
+#line	117	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ forloop(yypt[-5].yyv.p, yypt[-3].yyv.f, yypt[-1].yyv.f, '+', 1.0, yypt[-0].yyv.p); } break;
+case 34:
+#line	119	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ forloop(yypt[-8].yyv.p, yypt[-6].yyv.f, yypt[-4].yyv.f, yypt[-2].yyv.i, yypt[-1].yyv.f, yypt[-0].yyv.p); } break;
+case 35:
+#line	121	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ forloop(yypt[-5].yyv.p, yypt[-3].yyv.f, yypt[-1].yyv.f, '+', 1.0, yypt[-0].yyv.p); } break;
+case 36:
+#line	125	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ ifstat(yypt[-2].yyv.f, yypt[-1].yyv.p, yypt[-0].yyv.p); } break;
+case 37:
+#line	126	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ ifstat(yypt[-1].yyv.f, yypt[-0].yyv.p, (char *) 0); } break;
+case 39:
+#line	130	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = strcmp(yypt[-2].yyv.p,yypt[-0].yyv.p) == 0; free(yypt[-2].yyv.p); free(yypt[-0].yyv.p); } break;
+case 40:
+#line	131	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = strcmp(yypt[-2].yyv.p,yypt[-0].yyv.p) != 0; free(yypt[-2].yyv.p); free(yypt[-0].yyv.p); } break;
+case 41:
+#line	135	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ y.f = 0; makevar(yypt[-0].yyv.p, VARNAME, y); } break;
+case 42:
+#line	138	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.i = '+'; } break;
+case 43:
+#line	139	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.i = '-'; } break;
+case 44:
+#line	140	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.i = '*'; } break;
+case 45:
+#line	141	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.i = '/'; } break;
+case 46:
+#line	142	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.i = ' '; } break;
+case 47:
+#line	147	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = leftthing('{'); } break;
+case 48:
+#line	151	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = boxgen(); } break;
+case 49:
+#line	152	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = circgen(yypt[-1].yyv.i); } break;
+case 50:
+#line	153	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = circgen(yypt[-1].yyv.i); } break;
+case 51:
+#line	154	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = arcgen(yypt[-1].yyv.i); } break;
+case 52:
+#line	155	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = linegen(yypt[-1].yyv.i); } break;
+case 53:
+#line	156	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = linegen(yypt[-1].yyv.i); } break;
+case 54:
+#line	157	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = linegen(yypt[-1].yyv.i); } break;
+case 55:
+#line	158	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = movegen(); } break;
+case 56:
+#line	159	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = textgen(); } break;
+case 57:
+#line	160	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = troffgen(yypt[-0].yyv.p); } break;
+case 58:
+#line	161	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o=rightthing(yypt[-2].yyv.o,']'); } break;
+case 59:
+#line	162	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = blockgen(yypt[-4].yyv.o, yypt[-1].yyv.o); } break;
+case 60:
+#line	166	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = leftthing('['); } break;
+case 63:
+#line	175	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(yypt[-1].yyv.i, !DEFAULT, yypt[-0].yyv.f); } break;
+case 64:
+#line	176	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(yypt[-0].yyv.i, DEFAULT, 0.0); } break;
+case 65:
+#line	177	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(curdir(), !DEFAULT, yypt[-0].yyv.f); } break;
+case 66:
+#line	178	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(yypt[-1].yyv.i, !DEFAULT, yypt[-0].yyv.f); } break;
+case 67:
+#line	179	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(yypt[-0].yyv.i, DEFAULT, 0.0); } break;
+case 68:
+#line	180	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makeoattr(yypt[-1].yyv.i, yypt[-0].yyv.o); } break;
+case 69:
+#line	181	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makeoattr(yypt[-1].yyv.i, yypt[-0].yyv.o); } break;
+case 70:
+#line	182	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makeoattr(yypt[-1].yyv.i, yypt[-0].yyv.o); } break;
+case 71:
+#line	183	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makeoattr(yypt[-1].yyv.i, yypt[-0].yyv.o); } break;
+case 72:
+#line	184	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makeiattr(WITH, yypt[-0].yyv.i); } break;
+case 73:
+#line	185	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makeoattr(PLACE, getblock(getlast(1,BLOCK), yypt[-0].yyv.p)); } break;
+case 74:
+#line	187	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makeoattr(PLACE, getpos(getblock(getlast(1,BLOCK), yypt[-1].yyv.p), yypt[-0].yyv.i)); } break;
+case 75:
+#line	188	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makeoattr(PLACE, yypt[-0].yyv.o); } break;
+case 76:
+#line	189	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makeiattr(SAME, yypt[-0].yyv.i); } break;
+case 77:
+#line	190	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ maketattr(yypt[-0].yyv.i, (char *) 0); } break;
+case 78:
+#line	191	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makeiattr(HEAD, yypt[-0].yyv.i); } break;
+case 79:
+#line	192	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(DOT, !DEFAULT, yypt[-0].yyv.f); } break;
+case 80:
+#line	193	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(DOT, DEFAULT, 0.0); } break;
+case 81:
+#line	194	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(DASH, !DEFAULT, yypt[-0].yyv.f); } break;
+case 82:
+#line	195	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(DASH, DEFAULT, 0.0); } break;
+case 83:
+#line	196	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(CHOP, !DEFAULT, yypt[-0].yyv.f); } break;
+case 84:
+#line	197	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(CHOP, DEFAULT, 0.0); } break;
+case 85:
+#line	198	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(FILL, !DEFAULT, yypt[-0].yyv.f); } break;
+case 86:
+#line	199	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ makefattr(FILL, DEFAULT, 0.0); } break;
+case 90:
+#line	208	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ maketattr(CENTER, yypt[-0].yyv.p); } break;
+case 91:
+#line	209	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ maketattr(yypt[-0].yyv.i, yypt[-1].yyv.p); } break;
+case 92:
+#line	210	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ addtattr(yypt[-0].yyv.i); } break;
+case 94:
+#line	214	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.p = sprintgen(yypt[-1].yyv.p); } break;
+case 95:
+#line	215	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.p = sprintgen(yypt[-3].yyv.p); } break;
+case 96:
+#line	219	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ exprsave(yypt[-0].yyv.f); yyval.i = 0; } break;
+case 97:
+#line	220	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ exprsave(yypt[-0].yyv.f); } break;
+case 99:
+#line	225	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = yypt[-1].yyv.o; } break;
+case 100:
+#line	226	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = makepos(yypt[-2].yyv.f, yypt[-0].yyv.f); } break;
+case 101:
+#line	227	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = fixpos(yypt[-4].yyv.o, yypt[-2].yyv.f, yypt[-0].yyv.f); } break;
+case 102:
+#line	228	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = fixpos(yypt[-4].yyv.o, -yypt[-2].yyv.f, -yypt[-0].yyv.f); } break;
+case 103:
+#line	229	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = fixpos(yypt[-6].yyv.o, yypt[-3].yyv.f, yypt[-1].yyv.f); } break;
+case 104:
+#line	230	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = fixpos(yypt[-6].yyv.o, -yypt[-3].yyv.f, -yypt[-1].yyv.f); } break;
+case 105:
+#line	231	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = addpos(yypt[-2].yyv.o, yypt[-0].yyv.o); } break;
+case 106:
+#line	232	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = subpos(yypt[-2].yyv.o, yypt[-0].yyv.o); } break;
+case 107:
+#line	233	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = makepos(getcomp(yypt[-3].yyv.o,DOTX), getcomp(yypt[-1].yyv.o,DOTY)); } break;
+case 108:
+#line	234	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = makebetween(yypt[-5].yyv.f, yypt[-3].yyv.o, yypt[-1].yyv.o); } break;
+case 109:
+#line	235	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = makebetween(yypt[-4].yyv.f, yypt[-2].yyv.o, yypt[-0].yyv.o); } break;
+case 110:
+#line	239	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ y = getvar(yypt[-0].yyv.p); yyval.o = y.o; } break;
+case 111:
+#line	240	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ y = getvar(yypt[-1].yyv.p); yyval.o = getpos(y.o, yypt[-0].yyv.i); } break;
+case 112:
+#line	241	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ y = getvar(yypt[-0].yyv.p); yyval.o = getpos(y.o, yypt[-1].yyv.i); } break;
+case 113:
+#line	242	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = gethere(); } break;
+case 114:
+#line	243	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = getlast(yypt[-1].yyv.i, yypt[-0].yyv.i); } break;
+case 115:
+#line	244	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = getpos(getlast(yypt[-2].yyv.i, yypt[-1].yyv.i), yypt[-0].yyv.i); } break;
+case 116:
+#line	245	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = getpos(getlast(yypt[-1].yyv.i, yypt[-0].yyv.i), yypt[-2].yyv.i); } break;
+case 117:
+#line	246	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = getfirst(yypt[-1].yyv.i, yypt[-0].yyv.i); } break;
+case 118:
+#line	247	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = getpos(getfirst(yypt[-2].yyv.i, yypt[-1].yyv.i), yypt[-0].yyv.i); } break;
+case 119:
+#line	248	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = getpos(getfirst(yypt[-1].yyv.i, yypt[-0].yyv.i), yypt[-2].yyv.i); } break;
+case 121:
+#line	250	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = getpos(yypt[-1].yyv.o, yypt[-0].yyv.i); } break;
+case 122:
+#line	251	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = getpos(yypt[-0].yyv.o, yypt[-1].yyv.i); } break;
+case 123:
+#line	255	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = getblock(getlast(yypt[-3].yyv.i,yypt[-2].yyv.i), yypt[-0].yyv.p); } break;
+case 124:
+#line	256	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.o = getblock(getfirst(yypt[-3].yyv.i,yypt[-2].yyv.i), yypt[-0].yyv.p); } break;
+case 125:
+#line	257	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ y = getvar(yypt[-2].yyv.p); yyval.o = getblock(y.o, yypt[-0].yyv.p); } break;
+case 126:
+#line	261	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.i = yypt[-1].yyv.i + 1; } break;
+case 127:
+#line	262	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.i = yypt[-1].yyv.i; } break;
+case 128:
+#line	263	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.i = 1; } break;
+case 138:
+#line	279	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = getfval(yypt[-0].yyv.p); } break;
+case 140:
+#line	281	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-2].yyv.f + yypt[-0].yyv.f; } break;
+case 141:
+#line	282	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-2].yyv.f - yypt[-0].yyv.f; } break;
+case 142:
+#line	283	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-2].yyv.f * yypt[-0].yyv.f; } break;
+case 143:
+#line	284	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ if (yypt[-0].yyv.f == 0.0) {
+					ERROR "division by 0" WARNING; yypt[-0].yyv.f = 1; }
+				  yyval.f = yypt[-2].yyv.f / yypt[-0].yyv.f; } break;
+case 144:
+#line	287	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ if ((long)yypt[-0].yyv.f == 0) {
+					ERROR "mod division by 0" WARNING; yypt[-0].yyv.f = 1; }
+				  yyval.f = (long)yypt[-2].yyv.f % (long)yypt[-0].yyv.f; } break;
+case 145:
+#line	290	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = -yypt[-0].yyv.f; } break;
+case 146:
+#line	291	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-1].yyv.f; } break;
+case 147:
+#line	292	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = getcomp(yypt[-1].yyv.o, yypt[-0].yyv.i); } break;
+case 148:
+#line	293	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = getcomp(yypt[-1].yyv.o, yypt[-0].yyv.i); } break;
+case 149:
+#line	294	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = getcomp(yypt[-1].yyv.o, yypt[-0].yyv.i); } break;
+case 150:
+#line	295	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = getcomp(yypt[-1].yyv.o, yypt[-0].yyv.i); } break;
+case 151:
+#line	296	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = getcomp(yypt[-1].yyv.o, yypt[-0].yyv.i); } break;
+case 152:
+#line	297	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ y = getvar(yypt[-2].yyv.p); yyval.f = getblkvar(y.o, yypt[-0].yyv.p); } break;
+case 153:
+#line	298	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = getblkvar(getlast(yypt[-3].yyv.i,yypt[-2].yyv.i), yypt[-0].yyv.p); } break;
+case 154:
+#line	299	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = getblkvar(getfirst(yypt[-3].yyv.i,yypt[-2].yyv.i), yypt[-0].yyv.p); } break;
+case 155:
+#line	300	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-2].yyv.f > yypt[-0].yyv.f; } break;
+case 156:
+#line	301	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-2].yyv.f < yypt[-0].yyv.f; } break;
+case 157:
+#line	302	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-2].yyv.f <= yypt[-0].yyv.f; } break;
+case 158:
+#line	303	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-2].yyv.f >= yypt[-0].yyv.f; } break;
+case 159:
+#line	304	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-2].yyv.f == yypt[-0].yyv.f; } break;
+case 160:
+#line	305	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-2].yyv.f != yypt[-0].yyv.f; } break;
+case 161:
+#line	306	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-2].yyv.f && yypt[-0].yyv.f; } break;
+case 162:
+#line	307	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-2].yyv.f || yypt[-0].yyv.f; } break;
+case 163:
+#line	308	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = !(yypt[-0].yyv.f); } break;
+case 164:
+#line	309	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = Log10(yypt[-1].yyv.f); } break;
+case 165:
+#line	310	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = Exp(yypt[-1].yyv.f * log(10.0)); } break;
+case 166:
+#line	311	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = pow(yypt[-2].yyv.f, yypt[-0].yyv.f); } break;
+case 167:
+#line	312	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = sin(yypt[-1].yyv.f); } break;
+case 168:
+#line	313	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = cos(yypt[-1].yyv.f); } break;
+case 169:
+#line	314	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = atan2(yypt[-3].yyv.f, yypt[-1].yyv.f); } break;
+case 170:
+#line	315	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = Sqrt(yypt[-1].yyv.f); } break;
+case 171:
+#line	316	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = (float)rand() / 32767.0; /* might be 2^31-1 */ } break;
+case 172:
+#line	317	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-3].yyv.f >= yypt[-1].yyv.f ? yypt[-3].yyv.f : yypt[-1].yyv.f; } break;
+case 173:
+#line	318	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = yypt[-3].yyv.f <= yypt[-1].yyv.f ? yypt[-3].yyv.f : yypt[-1].yyv.f; } break;
+case 174:
+#line	319	"/usr/local/plan9/src/cmd/tpic/picy.y"
+{ yyval.f = (long) yypt[-1].yyv.f; } break;
+	}
+	goto yystack;  /* stack new state and value */
+}
blob - /dev/null
blob + 46b2b4da3db4d0815a098592a2c203e45b6592e5 (mode 644)
--- /dev/null
+++ src/cmd/tpic/picy.y
@@ -0,0 +1,320 @@
+%{
+#include <stdio.h>
+#include "pic.h"
+#include <math.h>
+YYSTYPE	y;
+int yylex(void);
+%}
+
+%token	<i>	BOX	1	/* DON'T CHANGE THESE! */
+%token	<i>	LINE	2
+%token	<i>	ARROW	3
+%token	<i>	CIRCLE	4
+%token	<i>	ELLIPSE	5
+%token	<i>	ARC	6
+%token	<i>	SPLINE	7
+%token	<i>	BLOCK	8
+%token	<p>	TEXT	9
+%token	<p>	TROFF	10
+%token	<i>	MOVE	11
+%token	<i>	BLOCKEND 12
+%token	<i>	PLACE	13
+%token	<i>	PRINT RESET THRU UNTIL
+%token	<o>	FOR IF COPY
+%token	<p>	THENSTR ELSESTR DOSTR PLACENAME VARNAME SPRINTF
+%token	<st>	DEFNAME
+%token	<i>	ATTR TEXTATTR
+%token	<i>	LEFT RIGHT UP DOWN FROM TO AT BY WITH HEAD CW CCW THEN
+%token	<i>	HEIGHT WIDTH RADIUS DIAMETER LENGTH SIZE
+%token	<i>	CORNER HERE LAST NTH SAME BETWEEN AND
+%token	<i>	EAST WEST NORTH SOUTH NE NW SE SW START END
+%token	<i>	DOTX DOTY DOTHT DOTWID DOTRAD
+%token	<f>	NUMBER
+%token	<f>	LOG EXP SIN COS ATAN2 SQRT RAND MIN MAX INT
+%token	<i>	DIR
+%token	<i>	DOT DASH CHOP FILL
+%token	<o>	ST	/* statement terminator */
+
+%right	<f>	'='
+%left	<f>	OROR
+%left	<f>	ANDAND
+%nonassoc <f>	GT LT LE GE EQ NEQ
+%left	<f>	'+' '-'
+%left	<f>	'*' '/' '%'
+%right	<f>	UMINUS NOT
+%right	<f>	'^'
+
+%type	<f>	expr if_expr asgn
+%type	<p>	name text
+%type	<i>	optop exprlist
+%type	<o>	if for copy
+
+/* this is a lie:  picture and position are really the whole union */
+%type	<o>	leftbrace picture piclist position lbracket
+%type	<o>	prim place blockname
+%type	<i>	textlist textattr	/* not a sensible value */
+%type	<i>	last type
+
+%%
+
+top:
+	  piclist
+	| /* empty */
+	| error		{ ERROR "syntax error" WARNING; }
+	;
+
+piclist:
+	  picture
+	| piclist picture
+	;
+
+picture:
+	  prim ST			{ codegen = 1; makeiattr(0, 0); }
+	| leftbrace piclist '}'		{ rightthing($1, '}'); $$ = $2; }
+	| PLACENAME ':' picture		{ y.o=$3; makevar($1,PLACENAME,y); $$ = $3; }
+	| PLACENAME ':' ST picture	{ y.o=$4; makevar($1,PLACENAME,y); $$ = $4; }
+	| PLACENAME ':' position ST	{ y.o=$3; makevar($1,PLACENAME,y); $$ = $3; }
+	| asgn ST			{ y.f = $1; $$ = y.o; $$ = makenode(PLACE, 0); }
+	| DIR				{ setdir($1); $$ = makenode(PLACE, 0); }
+	| PRINT expr ST			{ printexpr($2); $$ = makenode(PLACE, 0); }
+	| PRINT position ST		{ printpos($2); $$ = makenode(PLACE, 0); }
+	| PRINT text ST			{ printf("%s\n", $2); free($2); $$ = makenode(PLACE, 0); }
+	| RESET varlist ST		{ resetvar(); makeiattr(0, 0); $$ = makenode(PLACE, 0); }
+	| copy
+	| for
+	| if
+	| ST
+	;
+
+varlist:
+	  /* empty */
+	| VARNAME		{ makevattr($1); }
+	| varlist VARNAME	{ makevattr($2); }
+	| varlist ',' VARNAME	{ makevattr($3); }
+	;
+
+asgn:
+	  VARNAME '=' expr	{ $$=y.f=$3; makevar($1,VARNAME,y); checkscale($1); }
+	;
+
+copy:
+	  COPY copylist		{ copy(); }
+	;
+copylist:
+	  copyattr
+	| copylist copyattr
+	;
+copyattr:
+	  text			{ copyfile($1); }
+	| THRU DEFNAME		{ copydef($2); }
+	| UNTIL text		{ copyuntil($2); }
+	;
+
+for:
+	  FOR name FROM expr TO expr BY optop expr DOSTR
+		{ forloop($2, $4, $6, $8, $9, $10); }
+	| FOR name FROM expr TO expr DOSTR
+		{ forloop($2, $4, $6, '+', 1.0, $7); }
+	| FOR name '=' expr TO expr BY optop expr DOSTR
+		{ forloop($2, $4, $6, $8, $9, $10); }
+	| FOR name '=' expr TO expr DOSTR
+		{ forloop($2, $4, $6, '+', 1.0, $7); }
+	;
+
+if:
+	  IF if_expr THENSTR ELSESTR	{ ifstat($2, $3, $4); }
+	| IF if_expr THENSTR		{ ifstat($2, $3, (char *) 0); }
+	;
+if_expr:
+	  expr
+	| text EQ text		{ $$ = strcmp($1,$3) == 0; free($1); free($3); }
+	| text NEQ text		{ $$ = strcmp($1,$3) != 0; free($1); free($3); }
+	;
+
+name:
+	  VARNAME	{ y.f = 0; makevar($1, VARNAME, y); }
+	;
+optop:
+	  '+'		{ $$ = '+'; }
+	| '-'		{ $$ = '-'; }
+	| '*'		{ $$ = '*'; }
+	| '/'		{ $$ = '/'; }
+	| /* empty */	{ $$ = ' '; }
+	;
+
+
+leftbrace:
+	  '{'			{ $$ = leftthing('{'); }
+	;
+
+prim:
+	  BOX attrlist		{ $$ = boxgen(); }
+	| CIRCLE attrlist	{ $$ = circgen($1); }
+	| ELLIPSE attrlist	{ $$ = circgen($1); }
+	| ARC attrlist		{ $$ = arcgen($1); }
+	| LINE attrlist		{ $$ = linegen($1); }
+	| ARROW attrlist	{ $$ = linegen($1); }
+	| SPLINE attrlist	{ $$ = linegen($1); }
+	| MOVE attrlist		{ $$ = movegen(); }
+	| textlist attrlist	{ $$ = textgen(); }
+	| TROFF			{ $$ = troffgen($1); }
+	| lbracket piclist ']' { $<o>$=rightthing($1,']'); } attrlist
+				{ $$ = blockgen($1, $<o>4); }
+	;
+
+lbracket:
+	  '['			{ $$ = leftthing('['); }
+	;
+
+attrlist:
+	  attrlist attr
+	| /* empty */
+	;
+
+attr:
+	  ATTR expr		{ makefattr($1, !DEFAULT, $2); }
+	| ATTR			{ makefattr($1, DEFAULT, 0.0); }
+	| expr			{ makefattr(curdir(), !DEFAULT, $1); }
+	| DIR expr		{ makefattr($1, !DEFAULT, $2); }
+	| DIR			{ makefattr($1, DEFAULT, 0.0); }
+	| FROM position		{ makeoattr($1, $2); }
+	| TO position		{ makeoattr($1, $2); }
+	| AT position		{ makeoattr($1, $2); }
+	| BY position		{ makeoattr($1, $2); }
+	| WITH CORNER		{ makeiattr(WITH, $2); }
+	| WITH '.' PLACENAME	{ makeoattr(PLACE, getblock(getlast(1,BLOCK), $3)); }
+	| WITH '.' PLACENAME CORNER
+		{ makeoattr(PLACE, getpos(getblock(getlast(1,BLOCK), $3), $4)); }
+	| WITH position		{ makeoattr(PLACE, $2); }
+	| SAME			{ makeiattr(SAME, $1); }
+	| TEXTATTR		{ maketattr($1, (char *) 0); }
+	| HEAD			{ makeiattr(HEAD, $1); }
+	| DOT expr		{ makefattr(DOT, !DEFAULT, $2); }
+	| DOT			{ makefattr(DOT, DEFAULT, 0.0); }
+	| DASH expr		{ makefattr(DASH, !DEFAULT, $2); }
+	| DASH			{ makefattr(DASH, DEFAULT, 0.0); }
+	| CHOP expr		{ makefattr(CHOP, !DEFAULT, $2); }
+	| CHOP			{ makefattr(CHOP, DEFAULT, 0.0); }
+	| FILL expr		{ makefattr(FILL, !DEFAULT, $2); }
+	| FILL			{ makefattr(FILL, DEFAULT, 0.0); }
+	| textlist
+	;
+
+textlist:
+	  textattr
+	| textlist textattr
+	;
+textattr:
+	  text			{ maketattr(CENTER, $1); }
+	| text TEXTATTR		{ maketattr($2, $1); }
+	| textattr TEXTATTR	{ addtattr($2); }
+	;
+text:
+	  TEXT
+	| SPRINTF '(' text ')'			{ $$ = sprintgen($3); }
+	| SPRINTF '(' text ',' exprlist ')'	{ $$ = sprintgen($3); }
+	;
+
+exprlist:
+	  expr			{ exprsave($1); $$ = 0; }
+	| exprlist ',' expr	{ exprsave($3); }
+	;
+
+position:		/* absolute, not relative */
+	  place
+	| '(' position ')'			{ $$ = $2; }
+	| expr ',' expr				{ $$ = makepos($1, $3); }
+	| position '+' expr ',' expr		{ $$ = fixpos($1, $3, $5); }
+	| position '-' expr ',' expr		{ $$ = fixpos($1, -$3, -$5); }
+	| position '+' '(' expr ',' expr ')'	{ $$ = fixpos($1, $4, $6); }
+	| position '-' '(' expr ',' expr ')'	{ $$ = fixpos($1, -$4, -$6); }
+	| position '+' place			{ $$ = addpos($1, $3); }
+	| position '-' place			{ $$ = subpos($1, $3); }
+	| '(' place ',' place ')'	{ $$ = makepos(getcomp($2,DOTX), getcomp($4,DOTY)); }
+	| expr LT position ',' position GT	{ $$ = makebetween($1, $3, $5); }
+	| expr BETWEEN position AND position	{ $$ = makebetween($1, $3, $5); }
+	;
+
+place:
+	  PLACENAME		{ y = getvar($1); $$ = y.o; }
+	| PLACENAME CORNER	{ y = getvar($1); $$ = getpos(y.o, $2); }
+	| CORNER PLACENAME	{ y = getvar($2); $$ = getpos(y.o, $1); }
+	| HERE			{ $$ = gethere(); }
+	| last type		{ $$ = getlast($1, $2); }
+	| last type CORNER	{ $$ = getpos(getlast($1, $2), $3); }
+	| CORNER last type	{ $$ = getpos(getlast($2, $3), $1); }
+	| NTH type		{ $$ = getfirst($1, $2); }
+	| NTH type CORNER	{ $$ = getpos(getfirst($1, $2), $3); }
+	| CORNER NTH type	{ $$ = getpos(getfirst($2, $3), $1); }
+	| blockname
+	| blockname CORNER	{ $$ = getpos($1, $2); }
+	| CORNER blockname	{ $$ = getpos($2, $1); }
+	;
+
+blockname:
+	  last BLOCK '.' PLACENAME	{ $$ = getblock(getlast($1,$2), $4); }
+	| NTH BLOCK '.' PLACENAME	{ $$ = getblock(getfirst($1,$2), $4); }
+	| PLACENAME '.' PLACENAME	{ y = getvar($1); $$ = getblock(y.o, $3); }
+	;
+
+last:
+	  last LAST		{ $$ = $1 + 1; }
+	| NTH LAST		{ $$ = $1; }
+	| LAST			{ $$ = 1; }
+	;
+
+type:
+	  BOX
+	| CIRCLE
+	| ELLIPSE
+	| ARC
+	| LINE
+	| ARROW
+	| SPLINE
+	| BLOCK
+	;
+
+expr:
+	  NUMBER
+	| VARNAME		{ $$ = getfval($1); }
+	| asgn
+	| expr '+' expr		{ $$ = $1 + $3; }
+	| expr '-' expr		{ $$ = $1 - $3; }
+	| expr '*' expr		{ $$ = $1 * $3; }
+	| expr '/' expr		{ if ($3 == 0.0) {
+					ERROR "division by 0" WARNING; $3 = 1; }
+				  $$ = $1 / $3; }
+	| expr '%' expr		{ if ((long)$3 == 0) {
+					ERROR "mod division by 0" WARNING; $3 = 1; }
+				  $$ = (long)$1 % (long)$3; }
+	| '-' expr %prec UMINUS	{ $$ = -$2; }
+	| '(' expr ')'		{ $$ = $2; }
+	| place DOTX		{ $$ = getcomp($1, $2); }
+	| place DOTY		{ $$ = getcomp($1, $2); }
+	| place DOTHT		{ $$ = getcomp($1, $2); }
+	| place DOTWID		{ $$ = getcomp($1, $2); }
+	| place DOTRAD		{ $$ = getcomp($1, $2); }
+	| PLACENAME '.' VARNAME	{ y = getvar($1); $$ = getblkvar(y.o, $3); }
+	| last BLOCK '.' VARNAME { $$ = getblkvar(getlast($1,$2), $4); }
+	| NTH BLOCK '.' VARNAME	{ $$ = getblkvar(getfirst($1,$2), $4); }
+	| expr GT expr		{ $$ = $1 > $3; }
+	| expr LT expr		{ $$ = $1 < $3; }
+	| expr LE expr		{ $$ = $1 <= $3; }
+	| expr GE expr		{ $$ = $1 >= $3; }
+	| expr EQ expr		{ $$ = $1 == $3; }
+	| expr NEQ expr		{ $$ = $1 != $3; }
+	| expr ANDAND expr	{ $$ = $1 && $3; }
+	| expr OROR expr	{ $$ = $1 || $3; }
+	| NOT expr		{ $$ = !($2); }
+	| LOG '(' expr ')'		{ $$ = Log10($3); }
+	| EXP '(' expr ')'		{ $$ = Exp($3 * log(10.0)); }
+	| expr '^' expr			{ $$ = pow($1, $3); }
+	| SIN '(' expr ')'		{ $$ = sin($3); }
+	| COS '(' expr ')'		{ $$ = cos($3); }
+	| ATAN2 '(' expr ',' expr ')'	{ $$ = atan2($3, $5); }
+	| SQRT '(' expr ')'		{ $$ = Sqrt($3); }
+	| RAND '(' ')'			{ $$ = (float)rand() / 32767.0; /* might be 2^31-1 */ }
+	| MAX '(' expr ',' expr ')'	{ $$ = $3 >= $5 ? $3 : $5; }
+	| MIN '(' expr ',' expr ')'	{ $$ = $3 <= $5 ? $3 : $5; }
+	| INT '(' expr ')'		{ $$ = (long) $3; }
+	;
blob - /dev/null
blob + e757f1954d24b21a61cd2b5bce992951f7f498a4 (mode 644)
--- /dev/null
+++ src/cmd/tpic/pltex.c
@@ -0,0 +1,149 @@
+/* replacement for pltroff.c to produce a TeX file that makes a box */
+
+#include <stdio.h>
+#include <math.h>
+#include "pic.h"
+
+double rangex, rangey;  /* probably already available inside pic somewhere */
+extern int dbg;
+int frameno;
+
+/*-----------copied from old version----------*/
+
+void
+arrow(double x0, double y0, double x1, double y1, double w, double h, double ang, int nhead) 	/* draw arrow (without shaft) */
+	/* head wid w, len h, rotated ang */
+	/* and drawn with nhead lines */
+{
+	double alpha, rot, drot, hyp;
+	float dx, dy;
+	int i;
+
+	rot = atan2(w / 2, h);
+	hyp = sqrt(w/2 * w/2 + h * h);
+	alpha = atan2(y1-y0, x1-x0) + ang;
+	if (nhead < 2)
+		nhead = 2;
+	for (i = nhead-1; i >= 0; i--) {
+		drot = 2 * rot / (double) (nhead-1) * (double) i;
+		dx = hyp * cos(alpha + PI - rot + drot);
+		dy = hyp * sin(alpha + PI - rot + drot);
+		line(x1+dx, y1+dy, x1, y1);
+	}
+}
+
+
+/*-----------new code----------*/
+
+void
+printlf(int line, char *name)
+{
+}
+
+void
+fillstart(double v)	/* only choose black, light grey (.75), or white, for now */
+{
+	if (v<.05)
+		fprintf(TEXFILE, "    \\special{bk}%%\n");
+	else if (v>.95)
+		fprintf(TEXFILE, "    \\special{wh}%%\n");
+	else
+		fprintf(TEXFILE, "    \\special{sh}%%\n");
+}
+
+void
+fillend(void)
+{
+}
+
+void
+troff(char *s)
+{
+	int size;
+
+	if (strncmp(s, ".ps", 3) == 0) {
+	    if (sscanf(&s[3], " %d ", &size) > 0) {
+		fprintf(TEXFILE, "    \\special{pn %d}%%\n", size);
+		e1->pdiam = size;
+	    } else fprintf(stderr, "Malformed .ps command: %s\n", s);
+	}
+}
+
+
+void
+space(double x0, double y0, double x1, double y1)	/* set limits of page */
+{
+	e0->sidex = e1->sidex = deltx*1000;
+	e0->sidey = e1->sidey = e0->bottom = e1->bottom = delty*1000;
+	range(x0, y0, x1, y1);
+}
+
+void
+dot(void)
+{
+	/* use .005" radius at nominal 9pt pen size */
+	disc(e1->copyx,e1->copyy,(e1->pdiam/9.0)*(4.3/e1->scalex));
+}
+
+void
+label(char *s, int t, int nh)	/* text s of type t nh half-lines up */
+{
+	double nem;
+
+	if (t & ABOVE)
+		nh++;
+	else if (t & BELOW)
+		nh--;
+	nem = .2 - nh*.6;
+	fprintf(TEXFILE,"    \\rlap{\\kern %6.3fin\\lower%6.3fin\\hbox{\\lower%5.2fem\\hbox to 0pt{",
+			INCHES(DTRX(e1->copyx)), INCHES(DTRY(e1->copyy)), nem);
+	fprintf(TEXFILE,t&LJUST?"%s\\hss":(t&RJUST?"\\hss %s":"\\hss %s\\hss"),s);
+	fprintf(TEXFILE,"}}}%%\n");
+}
+
+void
+spline(double x, double y, double/*sic*/ n, float *p, int dashed, double ddval)
+{
+	int k, j;
+
+	fprintf(TEXFILE,"    \\special{pa %d %d}%%\n",TRX(x),TRY(y));
+	for(k=0, j=0; k<n; k++, j+=2){
+		x += p[j];
+		y += p[j+1];
+		fprintf(TEXFILE,"    \\special{pa %d %d}%%\n",TRX(x),TRY(y));
+	}
+	fprintf(TEXFILE,"    \\special{sp}%%\n");
+}
+
+void
+ellipse(double x, double y, double r1, double r2)
+{
+	fprintf(TEXFILE, "    \\special{ar %d %d %d %d 0.0 6.2832}%%\n",
+		TRX(x), TRY(y), SCX(r1), -SCY(r2));
+}
+
+void
+arc(double xc, double yc, double x0, double y0, double x1, double y1)	/* draw arc with center xc,yc */
+{
+	devarc(x0, y0, x1, y1, xc, yc, 1 );   /* radius=1 means counterclockwise */
+}
+
+/* If NOEXPANDDASH is defined, use this instead of the normal dotline
+ * in print().  This dotline relies on vec() noticing that e1->pen
+ * is not SOLIDPEN, and putting out a call to a different postscript
+ * routine.
+ */
+#ifdef NOEXPANDDASH
+
+void
+dotline(double x0, double y0, double x1, double y1, int ddtype, double ddval)
+{
+	if (ddval != 0)
+		e1->dashlen = ddval;
+	e1->pen = (ddtype&DOTBIT)? DOTPEN : DASHPEN;
+	move(x0, y0);
+	vec(x1, y1);
+	e1->pen = SOLIDPEN;
+	e1->dashlen = e0->dashlen;
+}
+#endif
blob - /dev/null
blob + a5b6b280c9d3941cd0ede9364a333e3f9333455f (mode 644)
--- /dev/null
+++ src/cmd/tpic/print.c
@@ -0,0 +1,210 @@
+#include	<stdio.h>
+#include	<math.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+void
+print(void)
+{
+	obj *p;
+	int i, j, k, m;
+	double x0, y0, x1, y1, ox, oy, dx, dy, ndx, ndy;
+
+	for (i = 0; i < nobj; i++) {
+		p = objlist[i];
+		ox = p->o_x;
+		oy = p->o_y;
+		x1 = 0;
+		if (p->o_count >= 1)
+			x1 = p->o_val[0];
+		y1 = 0;
+		if (p->o_count >= 2)
+			y1 = p->o_val[1];
+		m = p->o_mode;
+		switch (p->o_type) {
+		case TROFF:
+			troff(text[p->o_nt1].t_val);
+			break;
+		case BOX:
+		case BLOCK:
+			x0 = ox - x1 / 2;
+			y0 = oy - y1 / 2;
+			x1 = ox + x1 / 2;
+			y1 = oy + y1 / 2;
+			if (p->o_attr & FILLBIT) {
+				move(x0, y0);
+				fillstart(p->o_fillval);
+			}
+			if (p->o_attr & INVIS || p->o_type == BLOCK)
+				;	/* nothing at all */
+			else if (p->o_attr & (DOTBIT|DASHBIT))
+				dotbox(x0, y0, x1, y1, p->o_attr, p->o_ddval);
+			else
+				box(x0, y0, x1, y1);
+			if (p->o_attr & FILLBIT)
+				fillend();
+			move(ox, oy);
+			dotext(p);	/* if there are any text strings */
+			if (ishor(m))
+				move(isright(m) ? x1 : x0, oy);	/* right side */
+			else
+				move(ox, isdown(m) ? y0 : y1);	/* bottom */
+			break;
+		case BLOCKEND:
+			break;
+		case CIRCLE:
+			if (p->o_attr & FILLBIT)
+				fillstart(p->o_fillval);
+			if ((p->o_attr & INVIS) == 0)
+				circle(ox, oy, x1);
+			if (p->o_attr & FILLBIT)
+				fillend();
+			move(ox, oy);
+			dotext(p);
+			if (ishor(m))
+				move(ox + isright(m) ? x1 : -x1, oy);
+			else
+				move(ox, oy + isup(m) ? x1 : -x1);
+			break;
+		case ELLIPSE:
+			if (p->o_attr & FILLBIT)
+				fillstart(p->o_fillval);
+			if ((p->o_attr & INVIS) == 0)
+				ellipse(ox, oy, x1, y1);
+			if (p->o_attr & FILLBIT)
+				fillend();
+			move(ox, oy);
+			dotext(p);
+			if (ishor(m))
+				move(ox + isright(m) ? x1 : -x1, oy);
+			else
+				move(ox, oy - isdown(m) ? y1 : -y1);
+			break;
+		case ARC:
+			move(ox, oy);
+			dotext(p);
+			if (p->o_attr & HEAD1)
+				arrow(x1 - (y1 - oy), y1 + (x1 - ox),
+				      x1, y1, p->o_val[4], p->o_val[5], p->o_val[5]/p->o_val[6]/2, p->o_nhead);
+                        if (p->o_attr & INVIS)
+                                /* probably wrong when it's cw */
+                                move(x1, y1);
+                        else
+				arc(ox, oy, x1, y1, p->o_val[2], p->o_val[3]);
+			if (p->o_attr & HEAD2)
+				arrow(p->o_val[2] + p->o_val[3] - oy, p->o_val[3] - (p->o_val[2] - ox),
+				      p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5], -p->o_val[5]/p->o_val[6]/2, p->o_nhead);
+			if (p->o_attr & CW_ARC)
+				move(x1, y1);	/* because drawn backwards */
+			break;
+		case LINE:
+		case ARROW:
+		case SPLINE:
+			move((ox + x1)/2, (oy + y1)/2);	/* center */
+			dotext(p);
+			if (p->o_attr & HEAD1)
+				arrow(ox + p->o_val[5], oy + p->o_val[6], ox, oy, p->o_val[2], p->o_val[3], 0.0, p->o_nhead);
+                        if (p->o_attr & INVIS)
+                                move(x1, y1);
+			else if (p->o_type == SPLINE)
+				spline(ox, oy, p->o_val[4], &p->o_val[5], p->o_attr & (DOTBIT|DASHBIT), p->o_ddval);
+			else {
+				dx = ox;
+				dy = oy;
+				for (k=0, j=5; k < p->o_val[4]; k++, j += 2) {
+					ndx = dx + p->o_val[j];
+					ndy = dy + p->o_val[j+1];
+					if (p->o_attr & (DOTBIT|DASHBIT))
+						dotline(dx, dy, ndx, ndy, p->o_attr, p->o_ddval);
+					else
+						line(dx, dy, ndx, ndy);
+					dx = ndx;
+					dy = ndy;
+				}
+			}
+			if (p->o_attr & HEAD2) {
+				dx = ox;
+				dy = oy;
+				for (k = 0, j = 5; k < p->o_val[4] - 1; k++, j += 2) {
+					dx += p->o_val[j];
+					dy += p->o_val[j+1];
+				}
+				arrow(dx, dy, x1, y1, p->o_val[2], p->o_val[3], 0.0, p->o_nhead);
+			}
+			break;
+		case MOVE:
+		case TEXT:
+			move(ox, oy);
+			dotext(p);
+			break;
+		}
+	}
+}
+
+#ifndef NOEXPANDDASH
+void
+dotline(double x0, double y0, double x1, double y1, int ddtype, double ddval) /* dotted line */
+{
+	static double prevval = 0.05;	/* 20 per inch by default */
+	int i, numdots;
+	double a, b, dx, dy;
+
+	if (ddval == 0)
+		ddval = prevval;
+	prevval = ddval;
+	/* don't save dot/dash value */
+	dx = x1 - x0;
+	dy = y1 - y0;
+	if (ddtype & DOTBIT) {
+		numdots = sqrt(dx*dx + dy*dy) / prevval + 0.5;
+		if (numdots > 0)
+			for (i = 0; i <= numdots; i++) {
+				a = (double) i / (double) numdots;
+				move(x0 + (a * dx), y0 + (a * dy));
+				dot();
+			}
+	} else if (ddtype & DASHBIT) {
+		double d, dashsize, spacesize;
+		d = sqrt(dx*dx + dy*dy);
+		if (d <= 2 * prevval) {
+			line(x0, y0, x1, y1);
+			return;
+		}
+		numdots = d / (2 * prevval) + 1;	/* ceiling */
+		dashsize = prevval;
+		spacesize = (d - numdots * dashsize) / (numdots - 1);
+		b = 0;
+		for (i = 0; i < numdots-1; i++) {
+			a = i * (dashsize + spacesize) / d;
+			b = a + dashsize / d;
+			line(x0 + (a*dx), y0 + (a*dy), x0 + (b*dx), y0 + (b*dy));
+			a = b;
+			b = a + spacesize / d;
+			move(x0 + (a*dx), y0 + (a*dy));
+		}
+		line(x0 + (b * dx), y0 + (b * dy), x1, y1);
+	}
+	prevval = 0.05;
+}
+#endif
+
+void
+dotbox(double x0, double y0, double x1, double y1, int ddtype, double ddval)	/* dotted or dashed box */
+{
+	dotline(x0, y0, x1, y0, ddtype, ddval);
+	dotline(x1, y0, x1, y1, ddtype, ddval);
+	dotline(x1, y1, x0, y1, ddtype, ddval);
+	dotline(x0, y1, x0, y0, ddtype, ddval);
+}
+
+void
+dotext(obj *p)	/* print text strings of p in proper vertical spacing */
+{
+	int i, nhalf;
+
+	nhalf = p->o_nt2 - p->o_nt1 - 1;
+	for (i = p->o_nt1; i < p->o_nt2; i++) {
+		label(text[i].t_val, text[i].t_type, nhalf);
+		nhalf -= 2;
+	}
+}
blob - /dev/null
blob + 32e3bf0f1707d7986e054c15854e47b53e056d69 (mode 644)
--- /dev/null
+++ src/cmd/tpic/symtab.c
@@ -0,0 +1,109 @@
+#include	<stdio.h>
+#include	<ctype.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+YYSTYPE
+getvar(char *s)	/* return value of variable s (usually pointer) */
+{
+	struct symtab *p;
+	static YYSTYPE bug;
+
+	p = lookup(s);
+	if (p == NULL) {
+		if (islower(s[0]))
+			ERROR "no such variable as %s", s WARNING;
+		else
+			ERROR "no such place as %s", s WARNING;
+		return(bug);
+	}
+	return(p->s_val);
+}
+
+double
+getfval(char *s)	/* return float value of variable s */
+{
+	YYSTYPE y;
+
+	y = getvar(s);
+	return y.f;
+}
+
+void
+setfval(char *s, double f)	/* set variable s to f */
+{
+	struct symtab *p;
+
+	if ((p = lookup(s)) != NULL)
+		p->s_val.f = f;
+}
+
+struct symtab*
+makevar(char *s, int t, YYSTYPE v)	/* make variable named s in table */
+		/* assumes s is static or from tostring */
+{
+	struct symtab *p;
+
+	for (p = stack[nstack].p_symtab; p != NULL; p = p->s_next)
+		if (strcmp(s, p->s_name) == 0)
+			break;
+	if (p == NULL) {	/* it's a new one */
+		p = (struct symtab *) malloc(sizeof(struct symtab));
+		if (p == NULL)
+			ERROR "out of symtab space with %s", s FATAL;
+		p->s_next = stack[nstack].p_symtab;
+		stack[nstack].p_symtab = p;	/* stick it at front */
+	}
+	p->s_name = s;
+	p->s_type = t;
+	p->s_val = v;
+	return(p);
+}
+
+struct symtab*
+lookup(char *s)	/* find s in symtab */
+{
+	int i;
+	struct symtab *p;
+
+	for (i = nstack; i >= 0; i--)	/* look in each active symtab */
+		for (p = stack[i].p_symtab; p != NULL; p = p->s_next)
+			if (strcmp(s, p->s_name) == 0)
+				return(p);
+	return(NULL);
+}
+
+void
+freesymtab(struct symtab *p)	/* free space used by symtab at p */
+{
+	struct symtab *q;
+
+	for ( ; p != NULL; p = q) {
+		q = p->s_next;
+		free(p->s_name);	/* assumes done with tostring */
+		free((char *)p);
+	}
+}
+
+void
+freedef(char *s)	/* free definition for string s */
+{
+	struct symtab *p, *q, *op;
+
+	for (p = op = q = stack[nstack].p_symtab; p != NULL; p = p->s_next) {
+		if (strcmp(s, p->s_name) == 0) { 	/* got it */
+			if (p->s_type != DEFNAME)
+				break;
+			if (p == op)	/* 1st elem */
+				stack[nstack].p_symtab = p->s_next;
+			else
+				q->s_next = p->s_next;
+			free(p->s_name);
+			free(p->s_val.p);
+			free((char *)p);
+			return;
+		}
+		q = p;
+	}
+	/* ERROR "%s is not defined at this point", s WARNING; */
+}
blob - /dev/null
blob + ade5df6b526715e839bc9e585b8274b3e8b86537 (mode 644)
--- /dev/null
+++ src/cmd/tpic/tex.c
@@ -0,0 +1,203 @@
+#include <math.h>
+#include <stdio.h>
+#include "tex.h"
+
+void
+devarc(double x1, double y1, double x2, double y2, double xc, double yc, int r)
+{
+	double t, start, stop;
+	int rad;
+
+	/* tpic arcs go clockwise, and angles are measured clockwise */
+	start = atan2(y2-yc, x2-xc);
+	stop = atan2(y1-yc, x1-xc);
+	if (r<0) {
+		t = start; start = stop; stop = t;
+	}
+	rad = SCX(sqrt((x1-xc)*(x1-xc)+(y1-yc)*(y1-yc)));
+	fprintf(TEXFILE, "    \\special{ar %d %d %d %d %6.3f %6.3f}%%\n",
+		TRX(xc), TRY(yc), rad, rad, -start, -stop);
+}
+
+void
+box(double x0, double y0, double x1, double y1) 
+{
+	fprintf(TEXFILE,"    \\special{pa %d %d}",TRX(x0),TRY(y0));
+	fprintf(TEXFILE,"\\special{pa %d %d}",TRX(x1),TRY(y0));
+	fprintf(TEXFILE,"\\special{pa %d %d}",TRX(x1),TRY(y1));
+	fprintf(TEXFILE,"\\special{pa %d %d}",TRX(x0),TRY(y1));
+	fprintf(TEXFILE,"\\special{pa %d %d}",TRX(x0),TRY(y0));
+	switch(e1->pen){
+	case DASHPEN:
+		fprintf(TEXFILE,"\\special{da %6.3f}%%\n", e1->dashlen); break;
+	case DOTPEN:
+		fprintf(TEXFILE,"\\special{dt %6.3f}%%\n", e1->dashlen); break;
+	case SOLIDPEN:
+	default:
+		fprintf(TEXFILE,"\\special{fp}%%\n"); break;
+	}
+}
+
+void
+circle(double xc, double yc, double r)
+{
+	int rad = SCX(r);
+
+	fprintf(TEXFILE, "    \\special{ar %d %d %d %d 0.0 6.2832}%%\n",
+		TRX(xc), TRY(yc), rad, rad);
+}
+
+void
+closepl(void)
+{
+	fprintf(TEXFILE, "    \\kern %6.3fin\n  }\\vss}%%\n", INCHES(e1->sidex));
+	fprintf(TEXFILE, "  \\kern %6.3fin\n}\n", INCHES(e1->sidey));
+}
+
+void
+disc(double xc, double yc, double r)
+{
+	fprintf(TEXFILE, "    \\special{bk}%%\n");
+	circle(xc, yc, r);
+}
+
+void
+erase(void)
+{
+}
+
+void
+fill(int num[], double *ff[])
+{
+	double *xp, *yp, **fp, x0, y0;
+	int i, *n;
+	n = num;
+	fp = ff;
+	while((i = *n++)){
+		xp = *fp++;
+		yp = xp+1;
+		x0 = *xp;
+		y0 = *yp;
+		move(x0, y0);
+		while(--i){
+			xp += 2;
+			yp += 2;
+			vec(*xp, *yp);
+		}
+		if (*(xp-2) != x0 || *(yp-2) != y0)
+			vec(x0, y0);
+	}
+}
+
+void
+frame(double xs, double ys, double xf, double yf)
+{
+	double	osidex, osidey;
+	osidex = e1->sidex;
+	osidey = e1->sidey;
+	e1->left = xs * (e0->left + e0->sidex);
+	e1->bottom = ys* (e0->bottom +  e0->sidey);
+	e1->sidex = (xf-xs) * e0->sidex;
+	e1->sidey = (yf-ys) * e0->sidey;
+	e1->scalex *= (e1->sidex / osidex);
+	e1->scaley *= (e1->sidey / osidey);
+}
+
+void
+line(double x0, double y0, double x1, double y1) 
+{
+	move(x0, y0);
+	vec(x1, y1);
+}
+
+void
+move(double xx, double yy) 
+{
+	e1->copyx = xx; 
+	e1->copyy = yy;
+}
+
+extern	double	xmin, ymin, xmax, ymax;
+
+/* tpic TeX coord system uses millinches, printer's points for pensize */
+/* positive y downward, origin at upper left */
+
+#define pHEIGHT 5000.
+#define pWIDTH  5000.
+#define pPENSIZE 9
+#define pPSIZE 10
+#define pDLEN .05
+struct penvir E[2] = {
+{0.,pHEIGHT,0.,0.,1.,-1.,pWIDTH,pHEIGHT,0.,0.,0,pPSIZE,SOLIDPEN,pPENSIZE,pDLEN},
+{0.,pHEIGHT,0.,0.,1.,-1.,pWIDTH,pHEIGHT,0.,0.,0,pPSIZE,SOLIDPEN,pPENSIZE,pDLEN}
+};
+struct penvir *e0 = E, *e1 = &E[1];
+FILE *TEXFILE;
+
+void
+openpl(void)
+{ 
+	TEXFILE = stdout;
+
+	space(xmin, ymin, xmax, ymax);
+	fprintf(TEXFILE,"\\catcode`@=11\n");
+	fprintf(TEXFILE, "\\expandafter\\ifx\\csname graph\\endcsname\\relax");
+	fprintf(TEXFILE, " \\alloc@4\\box\\chardef\\insc@unt\\graph\\fi\n");
+	fprintf(TEXFILE, "\\catcode`@=12\n");
+	fprintf(TEXFILE, "\\setbox\\graph=\\vtop{%%\n");
+	fprintf(TEXFILE, "  \\baselineskip=0pt \\lineskip=0pt ");
+	fprintf(TEXFILE, "\\lineskiplimit=0pt\n");
+	fprintf(TEXFILE, "  \\vbox to0pt{\\hbox{%%\n");
+	fprintf(TEXFILE, "    \\special{pn %d}%%\n", e1->pdiam);
+}
+
+void
+range(double x0, double y0, double x1, double y1) 
+{
+	e1->xmin = x0;
+	e1->ymin = y0;
+	if (x1-x0 < .0000001*e1->sidex)
+		x1=x0+.0000001;
+	if (y1-y0 < .0000001*e1->sidey)
+		y1=y0+.0000001;
+	e1->scalex = e0->scalex*e1->sidex / (x1 - x0);
+	e1->scaley = e0->scaley*e1->sidey / (y1 - y0);
+}
+
+void
+rmove(double xx, double yy) 
+{
+	e1->copyx += xx;
+	e1->copyy += yy;
+}
+
+void
+rvec(double xx, double yy)  
+{
+	vec(xx+e1->copyx, yy+e1->copyy);
+}
+
+void
+sbox(double x0, double y0, double x1, double y1) 
+{
+	fprintf(TEXFILE,"    \\special{bk}%%\n");
+	box(x0, y0, x1, y1);
+}
+
+void
+vec(double xx, double yy) 
+{
+	fprintf(TEXFILE,"    \\special{pa %d %d}",TRX(e1->copyx),TRY(e1->copyy));
+	e1->copyx = xx; 
+	e1->copyy = yy;
+	fprintf(TEXFILE,"\\special{pa %d %d}",TRX(xx),TRY(yy));
+	switch(e1->pen){
+	case DASHPEN:
+		fprintf(TEXFILE,"\\special{da %6.3f}%%\n", e1->dashlen); break;
+	case DOTPEN:
+		fprintf(TEXFILE,"\\special{dt %6.3f}%%\n", e1->dashlen); break;
+	case SOLIDPEN:
+	default:
+		fprintf(TEXFILE,"\\special{fp}%%\n"); break;
+	}
+}
blob - /dev/null
blob + 873616a05080b7d23aabc3b00a3dd66c2578e992 (mode 644)
--- /dev/null
+++ src/cmd/tpic/tex.h
@@ -0,0 +1,50 @@
+#ifndef BUFSIZE
+#include <stdio.h>
+#endif
+#define SCX(A) (int)((A)*e1->scalex+0.5)
+#define SCY(A) (int)((A)*e1->scaley+0.5)
+#define TRX(A) (int)(((A) - e1->xmin)*e1->scalex  + e1->left)
+#define TRY(A) (int)(((A) - e1->ymin)*e1->scaley + e1->bottom)
+#define DTRX(A) (((A) - e1->xmin)*e1->scalex  + e1->left)
+#define DTRY(A) (((A) - e1->ymin)*e1->scaley + e1->bottom)
+#define INCHES(A) ((A)/1000.)
+extern struct penvir {
+	double left, bottom;
+	double xmin, ymin;
+	double scalex, scaley;
+	double sidex, sidey;
+	double copyx, copyy;
+	char *font;
+	int psize;
+	int pen;
+	int pdiam;
+	double dashlen;
+	} *e0, *e1, *e2, *esave;
+enum {
+	SOLIDPEN, DASHPEN, DOTPEN
+};
+extern FILE *TEXFILE;
+
+#define round texround
+
+extern int round();
+
+void		box(double x0, double y0, double x1, double y1) ;
+void		circle(double xc, double yc, double r);
+void		closepl(void);
+void		devarc(double x1, double y1, double x2, double y2, double xc, double yc, int r);
+void		disc(double xc, double yc, double r);
+void		erase(void);
+void		fill(int num[], double *ff[]);
+void		frame(double xs, double ys, double xf, double yf);
+void		line(double x0, double y0, double x1, double y1) ;
+void		move(double xx, double yy) ;
+void		openpl(void);
+void		pen(char *s) ;
+void		poly(int num[], double *ff[]);
+void		range(double x0, double y0, double x1, double y1) ;
+void		rmove(double xx, double yy) ;
+void		rvec(double xx, double yy)  ;
+void		sbox(double x0, double y0, double x1, double y1) ;
+void		vec(double xx, double yy) ;
+void	space(double x0, double y0, double x1, double y1);
blob - /dev/null
blob + e9ba803406cebe1e9cf333fcc4874b6100f7d71b (mode 644)
--- /dev/null
+++ src/cmd/tpic/textgen.c
@@ -0,0 +1,114 @@
+#include	<stdio.h>
+#include	"pic.h"
+#include	"y.tab.h"
+
+obj*
+textgen(void)
+{
+	int i, sub, nstr, at, with, hset;
+	double xwith, ywith, h, w, x0, y0, x1, y1;
+	obj *p, *ppos;
+	static double prevh = 0;
+	static double prevw = 0;
+	Attr *ap;
+
+	at = with = nstr = hset = 0;
+	h = getfval("textht");
+	w = getfval("textwid");
+	for (i = 0; i < nattr; i++) {
+		ap = &attr[i];
+		switch (ap->a_type) {
+		case HEIGHT:
+			h = ap->a_val.f;
+			hset++;
+			break;
+		case WIDTH:
+			w = ap->a_val.f;
+			break;
+		case WITH:
+			with = ap->a_val.i;
+			break;
+		case AT:
+			ppos = ap->a_val.o;
+			curx = ppos->o_x;
+			cury = ppos->o_y;
+			at++;
+			break;
+		case TEXTATTR:
+			sub = ap->a_sub;
+			if (ap->a_val.p == NULL)	/* an isolated modifier */
+				text[ntext-1].t_type = sub;
+			else {
+				savetext(sub, ap->a_val.p);
+				nstr++;
+			}
+			break;
+		}
+	}
+	if (hset == 0)		/* no explicit ht cmd */
+		h *= nstr;
+	if (with) {
+		xwith = ywith = 0.0;
+		switch (with) {
+		case NORTH:	ywith = -h / 2; break;
+		case SOUTH:	ywith = h / 2; break;
+		case EAST:	xwith = -w / 2; break;
+		case WEST:	xwith = w / 2; break;
+		case NE:	xwith = -w / 2; ywith = -h / 2; break;
+		case SE:	xwith = -w / 2; ywith = h / 2; break;
+		case NW:	xwith = w / 2; ywith = -h / 2; break;
+		case SW:	xwith = w / 2; ywith = h / 2; break;
+		}
+		curx += xwith;
+		cury += ywith;
+	}
+	if (!at) {
+		if (isright(hvmode))
+			curx += w / 2;
+		else if (isleft(hvmode))
+			curx -= w / 2;
+		else if (isup(hvmode))
+			cury += h / 2;
+		else
+			cury -= h / 2;
+	}
+	x0 = curx - w / 2;
+	y0 = cury - h / 2;
+	x1 = curx + w / 2;
+	y1 = cury + h / 2;
+	extreme(x0, y0);
+	extreme(x1, y1);
+	dprintf("Text h %g w %g at %g,%g\n", h, w, curx, cury);
+	p = makenode(TEXT, 2);
+	p->o_val[0] = w;
+	p->o_val[1] = h;
+	if (isright(hvmode))
+		curx = x1;
+	else if (isleft(hvmode))
+		curx = x0;
+	else if (isup(hvmode))
+		cury = y1;
+	else
+		cury = y0;
+	prevh = h;
+	prevw = w;
+	return(p);
+}
+
+obj*
+troffgen(char *s)	/* save away a string of troff commands */
+{
+	savetext(CENTER, s);	/* use the existing text mechanism */
+	return makenode(TROFF, 0);
+}
+
+void
+savetext(int t, char *s)	/* record text elements for current object */
+{
+	if (ntext >= ntextlist)
+		text = (Text *) grow((char *) text, "text", ntextlist += 200, sizeof(Text));
+	text[ntext].t_type = t;
+	text[ntext].t_val = s;
+	dprintf("saving %d text %s at %d\n", t, s, ntext);
+	ntext++;
+}