diff options
author | rsc <devnull@localhost> | 2006-04-14 00:04:03 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2006-04-14 00:04:03 +0000 |
commit | b6d98463b416e9d95bc88f948b4abdff6b24aede (patch) | |
tree | 6ae4dabb948c5b3c42a48b34964bdde7b0afa5c2 /src/cmd/tpic | |
parent | 434d1b41b61a9771f4cec2ca6c0a00b067a50fa0 (diff) | |
download | plan9port-b6d98463b416e9d95bc88f948b4abdff6b24aede.tar.gz plan9port-b6d98463b416e9d95bc88f948b4abdff6b24aede.tar.bz2 plan9port-b6d98463b416e9d95bc88f948b4abdff6b24aede.zip |
tpic
Diffstat (limited to 'src/cmd/tpic')
-rw-r--r-- | src/cmd/tpic/Changes | 24 | ||||
-rw-r--r-- | src/cmd/tpic/arcgen.c | 214 | ||||
-rw-r--r-- | src/cmd/tpic/blockgen.c | 223 | ||||
-rw-r--r-- | src/cmd/tpic/boxgen.c | 113 | ||||
-rw-r--r-- | src/cmd/tpic/circgen.c | 127 | ||||
-rw-r--r-- | src/cmd/tpic/for.c | 94 | ||||
-rw-r--r-- | src/cmd/tpic/input.c | 608 | ||||
-rw-r--r-- | src/cmd/tpic/linegen.c | 210 | ||||
-rw-r--r-- | src/cmd/tpic/main.c | 277 | ||||
-rw-r--r-- | src/cmd/tpic/misc.c | 463 | ||||
-rw-r--r-- | src/cmd/tpic/mkfile | 39 | ||||
-rw-r--r-- | src/cmd/tpic/movegen.c | 87 | ||||
-rw-r--r-- | src/cmd/tpic/pic.h | 285 | ||||
-rw-r--r-- | src/cmd/tpic/picl.l | 261 | ||||
-rw-r--r-- | src/cmd/tpic/picy.c | 1239 | ||||
-rw-r--r-- | src/cmd/tpic/picy.y | 320 | ||||
-rw-r--r-- | src/cmd/tpic/pltex.c | 149 | ||||
-rw-r--r-- | src/cmd/tpic/print.c | 210 | ||||
-rw-r--r-- | src/cmd/tpic/symtab.c | 109 | ||||
-rw-r--r-- | src/cmd/tpic/tex.c | 203 | ||||
-rw-r--r-- | src/cmd/tpic/tex.h | 50 | ||||
-rw-r--r-- | src/cmd/tpic/textgen.c | 114 |
22 files changed, 5419 insertions, 0 deletions
diff --git a/src/cmd/tpic/Changes b/src/cmd/tpic/Changes new file mode 100644 index 00000000..1e0a12d4 --- /dev/null +++ b/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. diff --git a/src/cmd/tpic/arcgen.c b/src/cmd/tpic/arcgen.c new file mode 100644 index 00000000..9c98d197 --- /dev/null +++ b/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 */ +} + diff --git a/src/cmd/tpic/blockgen.c b/src/cmd/tpic/blockgen.c new file mode 100644 index 00000000..4b4bfe98 --- /dev/null +++ b/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; + } + } +} diff --git a/src/cmd/tpic/boxgen.c b/src/cmd/tpic/boxgen.c new file mode 100644 index 00000000..95d4046d --- /dev/null +++ b/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); +} diff --git a/src/cmd/tpic/circgen.c b/src/cmd/tpic/circgen.c new file mode 100644 index 00000000..a1dbc937 --- /dev/null +++ b/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); +} diff --git a/src/cmd/tpic/for.c b/src/cmd/tpic/for.c new file mode 100644 index 00000000..6990314e --- /dev/null +++ b/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; + } +} diff --git a/src/cmd/tpic/input.c b/src/cmd/tpic/input.c new file mode 100644 index 00000000..817488c8 --- /dev/null +++ b/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); +} diff --git a/src/cmd/tpic/linegen.c b/src/cmd/tpic/linegen.c new file mode 100644 index 00000000..a5394232 --- /dev/null +++ b/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); +} diff --git a/src/cmd/tpic/main.c b/src/cmd/tpic/main.c new file mode 100644 index 00000000..ed310d5d --- /dev/null +++ b/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; +} diff --git a/src/cmd/tpic/misc.c b/src/cmd/tpic/misc.c new file mode 100644 index 00000000..72e83303 --- /dev/null +++ b/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; +} diff --git a/src/cmd/tpic/mkfile b/src/cmd/tpic/mkfile new file mode 100644 index 00000000..76bdcb36 --- /dev/null +++ b/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 + diff --git a/src/cmd/tpic/movegen.c b/src/cmd/tpic/movegen.c new file mode 100644 index 00000000..3a7e2021 --- /dev/null +++ b/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); +} diff --git a/src/cmd/tpic/pic.h b/src/cmd/tpic/pic.h new file mode 100644 index 00000000..50e58009 --- /dev/null +++ b/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" + diff --git a/src/cmd/tpic/picl.l b/src/cmd/tpic/picl.l new file mode 100644 index 00000000..8a706dc5 --- /dev/null +++ b/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]); + +%% diff --git a/src/cmd/tpic/picy.c b/src/cmd/tpic/picy.c new file mode 100644 index 00000000..25ffd4f9 --- /dev/null +++ b/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 */ +} diff --git a/src/cmd/tpic/picy.y b/src/cmd/tpic/picy.y new file mode 100644 index 00000000..46b2b4da --- /dev/null +++ b/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; } + ; diff --git a/src/cmd/tpic/pltex.c b/src/cmd/tpic/pltex.c new file mode 100644 index 00000000..e757f195 --- /dev/null +++ b/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 diff --git a/src/cmd/tpic/print.c b/src/cmd/tpic/print.c new file mode 100644 index 00000000..a5b6b280 --- /dev/null +++ b/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; + } +} diff --git a/src/cmd/tpic/symtab.c b/src/cmd/tpic/symtab.c new file mode 100644 index 00000000..32e3bf0f --- /dev/null +++ b/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; */ +} diff --git a/src/cmd/tpic/tex.c b/src/cmd/tpic/tex.c new file mode 100644 index 00000000..ade5df6b --- /dev/null +++ b/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; + } +} diff --git a/src/cmd/tpic/tex.h b/src/cmd/tpic/tex.h new file mode 100644 index 00000000..873616a0 --- /dev/null +++ b/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); diff --git a/src/cmd/tpic/textgen.c b/src/cmd/tpic/textgen.c new file mode 100644 index 00000000..e9ba8034 --- /dev/null +++ b/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++; +} |