Let's try this.  It's BUGGERED.
diff --git a/src/cmd/grap/ticks.c b/src/cmd/grap/ticks.c
new file mode 100644
index 0000000..72fc06f
--- /dev/null
+++ b/src/cmd/grap/ticks.c
@@ -0,0 +1,492 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "grap.h"
+#include "y.tab.h"
+
+#define	MAXTICK	200
+int	ntick	= 0;
+double	tickval[MAXTICK];	/* tick values (one axis at a time */
+char	*tickstr[MAXTICK];	/* and labels */
+
+int	tside	= 0;
+int	tlist	= 0;		/* 1 => explicit values given */
+int	toffside = 0;		/* no ticks on these sides */
+int	goffside = 0;		/* no ticks on grid on these sides */
+int	tick_dir = OUT;
+double	ticklen	= TICKLEN;	/* default tick length */
+int	autoticks = LEFT|BOT;
+int	autodir = 0;		/* set LEFT, etc. if automatic ticks go in */
+
+void savetick(double f, char *s)	/* remember tick location and label */
+{
+	if (ntick >= MAXTICK)
+		ERROR "too many ticks (%d)", MAXTICK FATAL;
+	tickval[ntick] = f;
+	tickstr[ntick] = s;
+	ntick++;
+}
+
+void dflt_tick(double f)
+{
+	if (f >= 0.0)
+		savetick(f, tostring("%g"));
+	else
+		savetick(f, tostring("\\%g"));
+}
+
+void tickside(int n)	/* remember which side these ticks/gridlines go on */
+{
+	tside |= n;
+}
+
+void tickoff(int side)	/* remember explicit sides */
+{
+	toffside |= side;
+}
+
+void gridtickoff(void)	/* turn grid ticks off on the side previously specified (ugh) */
+{
+	goffside = tside;
+}
+
+void setlist(void)	/* remember that there was an explicit list */
+{
+	tlist = 1;
+}
+
+void tickdir(int dir, double val, int explicit)	/* remember in/out [expr] */
+{
+	tick_dir = dir;
+	if (explicit)
+		ticklen = val;
+}
+
+void ticks(void)		/* set autoticks after ticks statement */
+{
+	/* was there an explicit "ticks [side] off"? */
+	if (toffside)
+		autoticks &= ~toffside;
+	/* was there an explicit list? (eg "ticks at ..." or "ticks from ...") */
+	if (tlist) {
+		if (tside & (BOT|TOP))
+			autoticks &= ~(BOT|TOP);
+		if (tside & (LEFT|RIGHT))
+			autoticks &= ~(LEFT|RIGHT);
+	}
+	/* was there a side without a list? (eg "ticks left in") */
+	if (tside && !tlist) {
+		if (tick_dir == IN)
+			autodir |= tside;
+		if (tside & (BOT|TOP))
+			autoticks = (autoticks & ~(BOT|TOP)) | (tside & (BOT|TOP));
+		if (tside & (LEFT|RIGHT))
+			autoticks = (autoticks & ~(LEFT|RIGHT)) | (tside & (LEFT|RIGHT));
+	}
+	tlist = tside = toffside = goffside = 0;
+	tick_dir = OUT;
+}
+
+double modfloor(double f, double t)
+{
+	t = fabs(t);
+	return floor(f/t) * t;
+}
+
+double modceil(double f, double t)
+{
+	t = fabs(t);
+	return ceil(f/t) * t;
+}
+
+double	xtmin, xtmax;	/* range of ticks */
+double	ytmin, ytmax;
+double	xquant, xmult;	/* quantization & scale for auto x ticks */
+double	yquant, ymult;
+double	lograt = 5;
+
+void do_autoticks(Obj *p)	/* make set of ticks for default coord only */
+{
+	double x, xl, xu, q;
+
+	if (p == NULL)
+		return;
+	fprintf(tfd, "Autoticks:\t# x %g..%g, y %g..%g",
+		p->pt.x, p->pt1.x, p->pt.y, p->pt1.y);
+	fprintf(tfd, ";   xt %g,%g, yt %g,%g, xq,xm = %g,%g, yq,ym = %g,%g\n",
+		xtmin, xtmax, ytmin, ytmax, xquant, xmult, yquant, ymult);
+	if ((autoticks & (BOT|TOP)) && p->pt1.x >= p->pt.x) {	/* make x ticks */
+		q = xquant;
+		xl = p->pt.x;
+		xu = p->pt1.x;
+		if (xl >= xu)
+			dflt_tick(xl);
+		else if ((p->log & XFLAG) && xu/xl >= lograt) {
+			for (x = q; x < xu; x *= 10) {
+				logtick(x, xl, xu);
+				if (xu/xl <= 100) {
+					logtick(2*x, xl, xu);
+					logtick(5*x, xl, xu);
+				}
+			}
+		} else {
+			xl = modceil(xtmin - q/100, q);
+			xu = modfloor(xtmax + q/100, q) + q/2;
+			for (x = xl; x <= xu; x += q)
+				dflt_tick(x);
+		}
+		tside = autoticks & (BOT|TOP);
+		ticklist(p, 0);
+	}
+	if ((autoticks & (LEFT|RIGHT)) && p->pt1.y >= p->pt.y) {	/* make y ticks */
+		q = yquant;
+		xl = p->pt.y;
+		xu = p->pt1.y;
+		if (xl >= xu)
+			dflt_tick(xl);
+		else if ((p->log & YFLAG) && xu/xl >= lograt) {
+			for (x = q; x < xu; x *= 10) {
+				logtick(x, xl, xu);
+				if (xu/xl <= 100) {
+					logtick(2*x, xl, xu);
+					logtick(5*x, xl, xu);
+				}
+			}
+		} else {
+			xl = modceil(ytmin - q/100, q);
+			xu = modfloor(ytmax + q/100, q) + q/2;
+			for (x = xl; x <= xu; x += q)
+				dflt_tick(x);
+		}
+		tside = autoticks & (LEFT|RIGHT);
+		ticklist(p, 0);
+	}
+}
+
+void logtick(double v, double lb, double ub)
+{
+	float slop = 1.0;	/* was 1.001 */
+
+	if (slop * lb <= v && ub >= slop * v)
+		dflt_tick(v);
+}
+
+Obj *setauto(void)	/* compute new min,max, and quant & mult */
+{
+	Obj *p, *q;
+
+	if ((q = lookup("lograt",0)) != NULL)
+		lograt = q->fval;
+	for (p = objlist; p; p = p->next)
+		if (p->type == NAME && strcmp(p->name,dflt_coord) == 0)
+			break;
+	if (p) {
+		if ((p->log & XFLAG) && p->pt1.x/p->pt.x >= lograt)
+			autolog(p, 'x');
+		else
+			autoside(p, 'x');
+		if ((p->log & YFLAG) && p->pt1.y/p->pt.y >= lograt)
+			autolog(p, 'y');
+		else
+			autoside(p, 'y');
+	}
+	return p;
+}
+
+void autoside(Obj *p, int side)
+{
+	double r, s, d, ub, lb;
+
+	if (side == 'x') {
+		xtmin = lb = p->pt.x;
+		xtmax = ub = p->pt1.x;
+	} else {
+		ytmin = lb = p->pt.y;
+		ytmax = ub = p->pt1.y;
+	}
+	if (ub <= lb)
+		return;	/* cop out on little ranges */
+	d = ub - lb;
+	r = s = 1;
+	while (d * s < 10)
+		s *= 10;
+	d *= s;
+	while (10 * r < d)
+		r *= 10;
+	if (r > d/3)
+		r /= 2;
+	else if (r <= d/6)
+		r *= 2;
+	if (side == 'x') {
+		xquant = r / s;
+	} else {
+		yquant = r / s;
+	}
+}
+
+void autolog(Obj *p, int side)
+{
+	double r, s, t, ub, lb;
+	int flg;
+
+	if (side == 'x') {
+		xtmin = lb = p->pt.x;
+		xtmax = ub = p->pt1.x;
+		flg = p->coord & XFLAG;
+	} else {
+		ytmin = lb = p->pt.y;
+		ytmax = ub = p->pt1.y;
+		flg = p->coord & YFLAG;
+	}
+	for (s = 1; lb * s < 1; s *= 10)
+		;
+	lb *= s;
+	ub *= s;
+	for (r = 1; 10 * r < lb; r *= 10)
+		;
+	for (t = 1; t < ub; t *= 10)
+		;
+	if (side == 'x')
+		xquant = r / s;
+	else
+		yquant = r / s;
+	if (flg)
+		return;
+	if (ub / lb < 100) {
+		if (lb >= 5 * r)
+			r *= 5;
+		else if (lb >= 2 * r)
+			r *= 2;
+		if (ub * 5 <= t)
+			t /= 5;
+		else if (ub * 2 <= t)
+			t /= 2;
+		if (side == 'x') {
+			xtmin = r / s;
+			xtmax = t / s;
+		} else {
+			ytmin = r / s;
+			ytmax = t / s;
+		}
+	}
+}
+
+void iterator(double from, double to, int op, double by, char *fmt)	/* create an iterator */
+{
+	double x;
+
+	/* should validate limits, etc. */
+	/* punt for now */
+
+	dprintf("iterate from %g to %g by %g, op = %c, fmt=%s\n",
+		from, to, by, op, fmt ? fmt : "");
+	switch (op) {
+	case '+':
+	case ' ':
+		for (x = from; x <= to + (SLOP-1) * by; x += by)
+			if (fmt)
+				savetick(x, tostring(fmt));
+			else
+				dflt_tick(x);
+		break;
+	case '-':
+		for (x = from; x >= to; x -= by)
+			if (fmt)
+				savetick(x, tostring(fmt));
+			else
+				dflt_tick(x);
+		break;
+	case '*':
+		for (x = from; x <= SLOP * to; x *= by)
+			if (fmt)
+				savetick(x, tostring(fmt));
+			else
+				dflt_tick(x);
+		break;
+	case '/':
+		for (x = from; x >= to; x /= by)
+			if (fmt)
+				savetick(x, tostring(fmt));
+			else
+				dflt_tick(x);
+		break;
+	}
+	if (fmt)
+		free(fmt);
+}
+
+void ticklist(Obj *p, int explicit)	/* fire out the accumulated ticks */
+					/* 1 => list, 0 => auto */
+{
+	if (p == NULL)
+		return;
+	fprintf(tfd, "Ticks_%s:\n\tticklen = %g\n", p->name, ticklen);
+	print_ticks(TICKS, explicit, p, "ticklen", "");
+}
+
+void print_ticks(int type, int explicit, Obj *p, char *lenstr, char *descstr)
+{
+	int i, logflag, inside;
+	char buf[100];
+	double tv;
+
+	for (i = 0; i < ntick; i++)	/* any ticks given explicitly? */
+		if (tickstr[i] != NULL)
+			break;
+	if (i >= ntick && type == TICKS)	/* no, so use values */
+		for (i = 0; i < ntick; i++) {
+			if (tickval[i] >= 0.0)
+				sprintf(buf, "%g", tickval[i]);
+			else
+				sprintf(buf, "\\-%g", -tickval[i]);
+			tickstr[i] = tostring(buf);
+		}
+	else
+		for (i = 0; i < ntick; i++) {
+			if (tickstr[i] != NULL) {
+				sprintf(buf, tickstr[i], tickval[i]);
+				free(tickstr[i]);
+				tickstr[i] = tostring(buf);
+			}
+		}
+	logflag = sidelog(p->log, tside);
+	for (i = 0; i < ntick; i++) {
+		tv = tickval[i];
+		halfrange(p, tside, tv);
+		if (logflag) {
+			if (tv <= 0.0)
+				ERROR "can't take log of tick value %g", tv FATAL;
+			logit(tv);
+		}
+		if (type == GRID)
+			inside = LEFT|RIGHT|TOP|BOT;
+		else if (explicit)
+			inside = (tick_dir == IN) ? tside : 0;
+		else
+			inside = autodir;
+		if (tside & BOT)
+			maketick(type, p->name, BOT, inside, tv, tickstr[i], lenstr, descstr);
+		if (tside & TOP)
+			maketick(type, p->name, TOP, inside, tv, tickstr[i], lenstr, descstr);
+		if (tside & LEFT)
+			maketick(type, p->name, LEFT, inside, tv, tickstr[i], lenstr, descstr);
+		if (tside & RIGHT)
+			maketick(type, p->name, RIGHT, inside, tv, tickstr[i], lenstr, descstr);
+		if (tickstr[i]) {
+			free(tickstr[i]);
+			tickstr[i] = NULL;
+		}
+	}
+	ntick = 0;
+}
+
+void maketick(int type, char *name, int side, int inflag, double val, char *lab, char *lenstr, char *descstr)
+{
+	char *sidestr, *td;
+
+	fprintf(tfd, "\tline %s ", descstr);
+	inflag &= side;
+	switch (side) {
+	case BOT:
+	case 0:
+		td = inflag ? "up" : "down";
+		fprintf(tfd, "%s %s from (x_%s(%g),0)", td, lenstr, name, val);
+		break;
+	case TOP:
+		td = inflag ? "down" : "up";
+		fprintf(tfd, "%s %s from (x_%s(%g),frameht)", td, lenstr, name, val);
+		break;
+	case LEFT:
+		td = inflag ? "right" : "left";
+		fprintf(tfd, "%s %s from (0,y_%s(%g))", td, lenstr, name, val);
+		break;
+	case RIGHT:
+		td = inflag ? "left" : "right";
+		fprintf(tfd, "%s %s from (framewid,y_%s(%g))", td, lenstr, name, val);
+		break;
+	}
+	fprintf(tfd, "\n");
+	if (type == GRID && (side & goffside))	/* wanted no ticks on grid */
+		return;
+	sidestr = tick_dir == IN ? "start" : "end";
+	if (lab != NULL) {
+		/* BUG: should fix size of lab here */
+		double wid = strlen(lab)/7.5 + (tick_dir == IN ? 0 : 0.1);	/* estimate width at 15 chars/inch */
+		switch (side) {
+		case BOT: case 0:
+			/* can drop "box invis" with new pic */
+			fprintf(tfd, "\tbox invis \"%s\" ht .25 wid 0 with .n at last line.%s",
+				lab, sidestr);
+			break;
+		case TOP:
+			fprintf(tfd, "\tbox invis \"%s\" ht .2 wid 0 with .s at last line.%s",
+				lab, sidestr);
+			break;
+		case LEFT:
+			fprintf(tfd, "\t\"%s \" wid %.2f rjust at last line.%s",
+				lab, wid, sidestr);
+			break;
+		case RIGHT:
+			fprintf(tfd, "\t\" %s\" wid %.2f ljust at last line.%s",
+				lab, wid, sidestr);
+			break;
+		}
+		/* BUG: works only if "down x" comes before "at wherever" */
+		lab_adjust();
+		fprintf(tfd, "\n");
+	}
+}
+
+Attr	*grid_desc	= 0;
+
+void griddesc(Attr *a)
+{
+	grid_desc = a;
+}
+
+void gridlist(Obj *p)
+{
+	char *framestr;
+
+	if ((tside & (BOT|TOP)) || tside == 0)
+		framestr = "frameht";
+	else
+		framestr = "framewid";
+	fprintf(tfd, "Grid_%s:\n", p->name);
+	tick_dir = IN;
+	print_ticks(GRID, 0, p, framestr, desc_str(grid_desc));
+	if (grid_desc) {
+		freeattr(grid_desc);
+		grid_desc = 0;
+	}
+}
+
+char *desc_str(Attr *a)	/* convert DOT to "dotted", etc. */
+{
+	static char buf[50], *p;
+
+	if (a == NULL)
+		return p = "";
+	switch (a->type) {
+	case DOT:	p = "dotted"; break;
+	case DASH:	p = "dashed"; break;
+	case INVIS:	p = "invis"; break;
+	default:	p = "";
+	}
+	if (a->fval != 0.0) {
+		sprintf(buf, "%s %g", p, a->fval);
+		return buf;
+	} else
+		return p;
+}
+
+sidelog(int logflag, int side)	/* figure out whether to scale a side */
+{
+	if ((logflag & XFLAG) && ((side & (BOT|TOP)) || side == 0))
+		return 1;
+	else if ((logflag & YFLAG) && (side & (LEFT|RIGHT)))
+		return 1;
+	else
+		return 0;
+}