aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/eqn
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-05-15 23:24:00 +0000
committerrsc <devnull@localhost>2004-05-15 23:24:00 +0000
commit5cedca1b69d020c32466f70843a11767773d7e3b (patch)
treea15a3d84e92aa262543b0010763a5e6920c9ba24 /src/cmd/eqn
parent76e6aca867e3e48ea04fbcf7284c45369a69829e (diff)
downloadplan9port-5cedca1b69d020c32466f70843a11767773d7e3b.tar.gz
plan9port-5cedca1b69d020c32466f70843a11767773d7e3b.tar.bz2
plan9port-5cedca1b69d020c32466f70843a11767773d7e3b.zip
Let's try this. It's BUGGERED.
Diffstat (limited to 'src/cmd/eqn')
-rw-r--r--src/cmd/eqn/diacrit.c75
-rw-r--r--src/cmd/eqn/e.h166
-rw-r--r--src/cmd/eqn/eqn.c741
-rw-r--r--src/cmd/eqn/eqn.y140
-rw-r--r--src/cmd/eqn/eqnbox.c24
-rw-r--r--src/cmd/eqn/font.c70
-rw-r--r--src/cmd/eqn/fromto.c52
-rw-r--r--src/cmd/eqn/funny.c30
-rw-r--r--src/cmd/eqn/glob.c35
-rw-r--r--src/cmd/eqn/input.c289
-rw-r--r--src/cmd/eqn/integral.c30
-rw-r--r--src/cmd/eqn/lex.c265
-rw-r--r--src/cmd/eqn/lookup.c219
-rw-r--r--src/cmd/eqn/main.c333
-rw-r--r--src/cmd/eqn/mark.c19
-rw-r--r--src/cmd/eqn/matrix.c78
-rw-r--r--src/cmd/eqn/mkfile42
-rw-r--r--src/cmd/eqn/move.c19
-rwxr-xr-xsrc/cmd/eqn/o.eqnbin0 -> 224764 bytes
-rw-r--r--src/cmd/eqn/over.c35
-rw-r--r--src/cmd/eqn/paren.c135
-rw-r--r--src/cmd/eqn/pile.c76
-rw-r--r--src/cmd/eqn/prevy.tab.h57
-rw-r--r--src/cmd/eqn/shift.c116
-rw-r--r--src/cmd/eqn/size.c70
-rw-r--r--src/cmd/eqn/sqrt.c35
-rw-r--r--src/cmd/eqn/text.c318
-rw-r--r--src/cmd/eqn/tuning.c153
-rw-r--r--src/cmd/eqn/y.tab.h57
29 files changed, 3679 insertions, 0 deletions
diff --git a/src/cmd/eqn/diacrit.c b/src/cmd/eqn/diacrit.c
new file mode 100644
index 00000000..10dc8c75
--- /dev/null
+++ b/src/cmd/eqn/diacrit.c
@@ -0,0 +1,75 @@
+#include "e.h"
+#include "y.tab.h"
+
+extern double Dvshift, Dhshift, Dh2shift, Dheight, Barv, Barh, Ubarv, Ubarh;
+
+void diacrit(int p1, int type)
+{
+ int c, t;
+
+ c = salloc();
+ t = salloc();
+ nrwid(p1, ps, p1);
+ printf(".nr 10 %gm\n", max(REL(eht[p1]-ebase[p1]-1,ps), 0)); /* vert shift if high */
+ if (type == HIGHBAR)
+ printf(".nr 10 \\n(10+%gm\n", Dvshift);
+ else if (type == LOWBAR)
+ printf(".nr 10 0\n");
+ else
+ printf(".if \\n(ct>1 .nr 10 \\n(10+%gm\n", Dvshift);
+ printf(".nr %d %gm\n", t, Dhshift); /* horiz shift if high */
+ printf(".if \\n(ct>1 .nr %d %gm\n", t, Dh2shift); /* was .1 and .15 */
+ switch (type) {
+ case VEC:
+ printf(".ds %d %s\n", c, lookup(deftbl, "vec_def")->cval);
+ break;
+ case DYAD:
+ printf(".ds %d %s\n", c, lookup(deftbl, "dyad_def")->cval);
+ break;
+ case HAT:
+ printf(".ds %d %s\n", c, lookup(deftbl, "hat_def")->cval);
+ break;
+ case TILDE:
+ printf(".ds %d %s\n", c, lookup(deftbl, "tilde_def")->cval);
+ break;
+ case DOT:
+ printf(".ds %d %s\n", c, lookup(deftbl, "dot_def")->cval);
+ break;
+ case DOTDOT:
+ printf(".ds %d %s\n", c, lookup(deftbl, "dotdot_def")->cval);
+ break;
+ case BAR:
+ case LOWBAR:
+ case HIGHBAR:
+ printf(".ds %d \\v'%gm'\\h'%gm'\\l'\\n(%du-%gm'\\h'%gm'\\v'%gm'\n",
+ c, -Barv, Barh, p1, 2*Barh, Barh, Barv);
+ break;
+ case UNDER:
+ printf(".ds %d \\v'%gm'\\l'\\n(%du-%gm\\(ul'\\h'%gm'\\v'%gm'\n",
+ c, -Ubarv, p1, Ubarh, Ubarh, Ubarv);
+ /* printf(".ds %d \\v'-%gm'\\l'\\n(%du\\(ul'\\v'%gm'\n",
+ c, Ubarv, p1, Ubarv);
+ */
+ printf(".nr %d 0\n", t);
+ printf(".nr 10 0-.1m-%gm\n", REL(ebase[p1],ps));
+ printf(".if \\n(ct%%2=1 .nr 10 0\\n(10-.1m\n");
+ break;
+ case UTILDE:
+ printf(".ds %d %s\n", c, lookup(deftbl, "utilde_def")->cval);
+ printf(".nr %d 0\n", t);
+ printf(".nr 10 0-%gm\n", REL(ebase[p1],ps));
+ printf(".if \\n(ct%%2=1 .nr 10 0\\n(10-%gm\n", 0.1);
+ break;
+ }
+ nrwid(c, ps, c);
+ if (lfont[p1] != ITAL)
+ printf(".nr %d 0\n", t);
+ printf(".as %d \\h'-\\n(%du-\\n(%du/2u+\\n(%du'\\v'0-\\n(10u'\\*(%d",
+ p1, p1, c, t, c);
+ printf("\\v'\\n(10u'\\h'-\\n(%du+\\n(%du/2u-\\n(%du'\n", c, p1, t);
+ if (type != UNDER && type != UTILDE)
+ eht[p1] += EM(Dheight, ps); /* was .15 */
+ dprintf(".\tdiacrit: %c over S%d, lf=%c, rf=%c, h=%g, b=%g\n",
+ type, p1, lfont[p1], rfont[p1], eht[p1], ebase[p1]);
+ sfree(c); sfree(t);
+}
diff --git a/src/cmd/eqn/e.h b/src/cmd/eqn/e.h
new file mode 100644
index 00000000..70c47023
--- /dev/null
+++ b/src/cmd/eqn/e.h
@@ -0,0 +1,166 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+enum charclass {
+ OTHER, OLET, ILET, DIG, LPAR, RPAR, SLASH, PLUS, ILETF, ILETJ, VBAR,
+ NONE, LAST
+};
+extern int class[LAST][LAST];
+
+#define dprintf if (dbg) printf
+#define max(x,y) (((x) >= (y)) ? (x) : (y)) /* beware of side effects */
+#define min(x,y) (((x) <= (y)) ? (x) : (y))
+
+extern char errbuf[200];
+extern char *cmdname;
+#define ERROR sprintf(errbuf,
+#define FATAL ), error(1, errbuf)
+#define WARNING ), error(0, errbuf)
+#define SYNTAX ), yyerror(errbuf)
+
+#define ROM '1'
+#define ITAL '2'
+#define BLD '3'
+#define BDIT '4'
+
+#define DEFGAP -999 /* default gap in piles */
+
+extern int dbg;
+extern int ct;
+extern int lp[];
+extern int used[]; /* available registers */
+extern int ps; /* dflt init pt size */
+extern int deltaps; /* default change in ps */
+extern int dps_set; /* 1 => -p option used */
+extern int gsize; /* global size */
+extern int ft; /* default font */
+extern int display; /* 1 => inline, 0 => .EQ/.EN */
+extern int synerr; /* 1 if syntax error in this eqn */
+
+extern char *typesetter; /* typesetter name for -T... */
+extern int minsize; /* min size it can print */
+extern int ttype; /* actual type of typesetter: */
+
+#define DEVCAT 1
+#define DEV202 2
+#define DEVAPS 3
+#define DEVPOST 4
+
+extern double eht[];
+extern double ebase[];
+extern int lfont[];
+extern int rfont[];
+extern int lclass[];
+extern int rclass[];
+extern int yyval;
+extern int yylval;
+extern int eqnreg;
+extern double eqnht;
+extern int lefteq, righteq;
+extern int markline; /* 1 if this EQ/EN contains mark or lineup */
+
+#define TBLSIZE 100
+
+typedef struct s_tbl {
+ char *name; /* e.g., "max" or "sum" */
+ char *cval; /* e.g., "\\f1max\\fP" */
+ int ival; /* or SUM */
+ struct s_tbl *next;
+} tbl;
+
+extern char *spaceval; /* use in place of normal \x (for pic) */
+
+#define String 01
+#define Macro 02
+#define File 04
+#define Char 010
+#define Free 040
+
+typedef struct infile {
+ FILE *fin;
+ char *fname;
+ int lineno;
+} Infile;
+
+typedef struct { /* input source */
+ int type; /* Macro, String, File */
+ char *sp; /* if String or Macro */
+} Src;
+
+extern Src src[], *srcp; /* input source stack */
+
+#define MAXARGS 20
+typedef struct { /* argument stack */
+ char *argstk[MAXARGS]; /* pointers to args */
+ char *argval; /* points to space containing args */
+} Arg;
+
+typedef struct { /* font number and name */
+ int ft;
+ char name[10];
+} Font;
+
+extern Font ftstack[];
+extern Font *ftp;
+
+extern int szstack[];
+extern int nszstack;
+
+extern Infile infile[10];
+extern Infile *curfile;
+
+extern tbl *lookup(tbl **tblp, char *name);
+extern void install(tbl **tblp, char *name, char *cval, int ival);
+extern tbl *keytbl[], *deftbl[], *restbl[], *ftunetbl[];
+
+extern int salloc(void);
+extern void sfree(int);
+extern void nrwid(int, int, int);
+extern char *ABSPS(int);
+extern char *DPS(int, int);
+extern int EFFPS(int);
+extern double EM(double, int);
+extern double REL(double, int);
+extern char *pad(int);
+extern void getstr(char *, int);
+extern char *strsave(char *);
+
+extern int input(void);
+extern int unput(int);
+extern void pbstr(char *);
+extern void error(int, char *);
+extern void yyerror(char *);
+
+extern void diacrit(int, int);
+extern void eqnbox(int, int, int);
+extern void setfont(char *);
+extern void font(int, int);
+extern void globfont(void);
+extern void fatbox(int);
+extern void fromto(int, int, int);
+extern void funny(int);
+extern void integral(int, int, int);
+extern void setintegral(void);
+extern void pushsrc(int, char *);
+extern void popsrc(void);
+extern void putout(int);
+extern void text(int, char *);
+extern void subsup(int, int, int);
+extern void bshiftb(int, int, int);
+extern void shift2(int, int, int);
+extern void setsize(char *);
+extern void size(int, int);
+extern void globsize(void);
+#define sqrt esqrt
+extern void sqrt(int);
+extern void text(int, char *);
+extern void boverb(int, int);
+extern void lineup(int);
+extern void mark(int);
+extern void paren(int, int, int);
+extern void move(int, int, int);
+extern void pile(int);
+extern int startcol(int);
+extern void column(int, int);
+extern void matrix(int);
diff --git a/src/cmd/eqn/eqn.c b/src/cmd/eqn/eqn.c
new file mode 100644
index 00000000..527e5e08
--- /dev/null
+++ b/src/cmd/eqn/eqn.c
@@ -0,0 +1,741 @@
+#define CONTIG 57346
+#define QTEXT 57347
+#define SPACE 57348
+#define THIN 57349
+#define TAB 57350
+#define MATRIX 57351
+#define LCOL 57352
+#define CCOL 57353
+#define RCOL 57354
+#define COL 57355
+#define ABOVE 57356
+#define MARK 57357
+#define LINEUP 57358
+#define SUM 57359
+#define INT 57360
+#define PROD 57361
+#define UNION 57362
+#define INTER 57363
+#define DEFINE 57364
+#define TDEFINE 57365
+#define NDEFINE 57366
+#define DELIM 57367
+#define GSIZE 57368
+#define GFONT 57369
+#define INCLUDE 57370
+#define IFDEF 57371
+#define DOTEQ 57372
+#define DOTEN 57373
+#define FROM 57374
+#define TO 57375
+#define OVER 57376
+#define SQRT 57377
+#define SUP 57378
+#define SUB 57379
+#define SIZE 57380
+#define FONT 57381
+#define ROMAN 57382
+#define ITALIC 57383
+#define BOLD 57384
+#define FAT 57385
+#define UP 57386
+#define DOWN 57387
+#define BACK 57388
+#define FWD 57389
+#define LEFT 57390
+#define RIGHT 57391
+#define DOT 57392
+#define DOTDOT 57393
+#define HAT 57394
+#define TILDE 57395
+#define BAR 57396
+#define LOWBAR 57397
+#define HIGHBAR 57398
+#define UNDER 57399
+#define VEC 57400
+#define DYAD 57401
+#define UTILDE 57402
+
+#line 17 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+#include "e.h"
+
+int yylex(void);
+extern int yyerrflag;
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 150
+#endif
+#ifndef YYSTYPE
+#define YYSTYPE int
+#endif
+YYSTYPE yylval;
+YYSTYPE yyval;
+#define YYEOFCODE 1
+#define YYERRCODE 2
+
+#line 140 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+
+short yyexca[] =
+{-1, 0,
+ 1, 3,
+ -2, 0,
+-1, 1,
+ 1, -1,
+ -2, 0,
+};
+#define YYNPROD 90
+#define YYPRIVATE 57344
+#define YYLAST 469
+short yyact[] =
+{
+ 4, 103, 119, 45, 27, 118, 104, 2, 102, 41,
+ 42, 43, 44, 65, 80, 81, 79, 66, 67, 68,
+ 69, 70, 50, 49, 74, 75, 76, 77, 105, 73,
+ 40, 80, 81, 80, 81, 114, 61, 64, 54, 62,
+ 57, 58, 59, 60, 55, 56, 63, 78, 91, 92,
+ 82, 26, 83, 85, 86, 87, 88, 90, 51, 52,
+ 48, 124, 50, 49, 117, 25, 45, 117, 72, 71,
+ 80, 81, 113, 24, 45, 23, 61, 64, 54, 62,
+ 57, 58, 59, 60, 55, 56, 63, 53, 89, 100,
+ 84, 22, 96, 95, 106, 107, 108, 109, 99, 110,
+ 111, 41, 42, 43, 44, 45, 98, 115, 21, 94,
+ 93, 18, 130, 123, 17, 116, 121, 46, 112, 125,
+ 127, 128, 1, 129, 126, 0, 0, 45, 8, 7,
+ 9, 10, 11, 28, 41, 42, 43, 44, 0, 16,
+ 47, 12, 34, 13, 14, 15, 61, 64, 54, 62,
+ 57, 58, 59, 60, 55, 56, 63, 0, 0, 20,
+ 0, 0, 29, 33, 30, 31, 32, 19, 37, 39,
+ 38, 36, 35, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 6, 97, 8, 7, 9,
+ 10, 11, 28, 41, 42, 43, 44, 0, 16, 47,
+ 12, 34, 13, 14, 15, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 20, 0,
+ 0, 29, 33, 30, 31, 32, 19, 37, 39, 38,
+ 36, 35, 101, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 3, 6, 8, 7, 9, 10, 11,
+ 28, 41, 42, 43, 44, 0, 16, 5, 12, 34,
+ 13, 14, 15, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 20, 0, 0, 29,
+ 33, 30, 31, 32, 19, 37, 39, 38, 36, 35,
+ 0, 0, 8, 7, 9, 10, 11, 28, 41, 42,
+ 43, 44, 6, 16, 47, 12, 34, 13, 14, 15,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 20, 0, 0, 29, 33, 30, 31,
+ 32, 19, 37, 39, 38, 36, 35, 0, 0, 8,
+ 7, 9, 10, 11, 28, 41, 42, 43, 44, 6,
+ 16, 5, 12, 34, 13, 14, 15, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 20, 0, 0, 29, 33, 30, 31, 32, 19, 37,
+ 39, 38, 36, 35, 8, 7, 9, 10, 11, 28,
+ 41, 42, 43, 44, 0, 16, 6, 12, 34, 13,
+ 14, 15, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 20, 0, 0, 29, 33,
+ 30, 31, 32, 19, 37, 39, 38, 36, 35, 51,
+ 122, 48, 0, 50, 49, 0, 0, 0, 0, 0,
+ 0, 6, 0, 0, 120, 49, 0, 61, 64, 54,
+ 62, 57, 58, 59, 60, 55, 56, 63, 61, 64,
+ 54, 62, 57, 58, 59, 60, 55, 56, 63
+};
+short yypact[] =
+{
+ 241,-1000, 288,-1000, 26,-1000, 335,-1000,-1000,-1000,
+-1000,-1000,-1000,-1000,-1000,-1000, 380, 380, 380, 380,
+ 380, 32, 335, 380, 380, 380, 380,-1000,-1000, 66,
+-1000,-1000,-1000, 66,-1000, 29, 66, 66, 66, 66,
+ 27,-1000,-1000,-1000,-1000, 26,-1000, 380, 380,-1000,
+-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,
+-1000,-1000,-1000,-1000,-1000, 124, 26, 96, 96, 96,
+ -14,-1000,-1000, 183, 96, 96, 96, 96, -53,-1000,
+-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000, 335,
+-1000, 26, -14, 380, 380, 380, 380,-1000, 380, 380,
+-1000, 10, 91, 53, 288, -56, 408, -14, 397, 26,
+ 408, -14,-1000,-1000, -1,-1000,-1000, 335, 335,-1000,
+ 380,-1000, 380,-1000,-1000,-1000, 288, 50, -14, 26,
+-1000
+};
+short yypgo[] =
+{
+ 0, 122, 6, 0, 117, 2, 116, 114, 111, 110,
+ 109, 108, 106, 98, 93, 92, 91, 89, 87, 75,
+ 73, 65, 51, 4, 47, 35, 16, 30, 1, 28
+};
+short yyr1[] =
+{
+ 0, 1, 1, 1, 2, 2, 2, 2, 4, 5,
+ 5, 6, 6, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 9,
+ 3, 10, 3, 12, 3, 13, 3, 3, 14, 3,
+ 15, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 24, 3, 11, 19, 20, 21, 22, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 16, 16,
+ 17, 17, 25, 25, 23, 29, 23, 27, 27, 27,
+ 27, 28, 28, 7, 8, 8, 8, 8, 26, 26
+};
+short yyr2[] =
+{
+ 0, 1, 1, 0, 1, 2, 2, 1, 2, 2,
+ 0, 2, 0, 3, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 3, 2, 2, 2, 2, 2, 0,
+ 5, 0, 4, 0, 5, 0, 4, 1, 0, 5,
+ 0, 4, 3, 2, 2, 2, 2, 2, 2, 1,
+ 0, 5, 1, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2, 1, 2, 4, 0, 6, 1, 1, 1,
+ 1, 1, 3, 2, 1, 1, 1, 2, 1, 1
+};
+short yychk[] =
+{
+-1000, -1, -2, 2, -3, 16, 61, 5, 4, 6,
+ 7, 8, 17, 19, 20, 21, 15, -7, -8, 43,
+ 35, -11, -16, -19, -20, -21, -22, -23, 9, 38,
+ 40, 41, 42, 39, 18, 48, 47, 44, 46, 45,
+ -27, 10, 11, 12, 13, -3, -4, 16, 34, 37,
+ 36, 32, 33, -18, 52, 58, 59, 54, 55, 56,
+ 57, 50, 53, 60, 51, -2, -3, -3, -3, -3,
+ -3, 37, 36, -2, -3, -3, -3, -3, -24, -26,
+ 4, 5, -26, -26, 61, -26, -26, -26, -26, 61,
+ -26, -3, -3, -9, -10, -14, -15, 62, -12, -13,
+ -17, 49, 61, -28, -2, -29, -3, -3, -3, -3,
+ -3, -3, -26, 62, -25, -23, 62, 14, 61, -5,
+ 36, -6, 33, -5, 62, -23, -2, -28, -3, -3,
+ 62
+};
+short yydef[] =
+{
+ -2, -2, 1, 2, 4, 7, 0, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 0, 0, 0, 0,
+ 0, 37, 0, 0, 0, 0, 0, 49, 50, 0,
+ 84, 85, 86, 0, 52, 0, 0, 0, 0, 0,
+ 0, 77, 78, 79, 80, 5, 6, 0, 0, 29,
+ 31, 38, 40, 44, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 67, 0, 24, 25, 26, 27,
+ 28, 33, 35, 43, 45, 46, 47, 48, 0, 83,
+ 88, 89, 87, 68, 69, 53, 54, 55, 56, 0,
+ 75, 8, 23, 0, 0, 0, 0, 13, 0, 0,
+ 42, 0, 0, 0, 81, 0, 10, 32, 12, 41,
+ 10, 36, 70, 71, 0, 72, 74, 0, 0, 30,
+ 0, 39, 0, 34, 51, 73, 82, 0, 9, 11,
+ 76
+};
+short yytok1[] =
+{
+ 1, 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,
+ 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, 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, 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, 0, 0, 0,
+ 0, 0, 0, 61, 0, 62
+};
+short yytok2[] =
+{
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 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
+};
+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
+char* yytoknames[1]; /* for debugging */
+char* yystates[1]; /* for debugging */
+#endif
+
+/* parser for yacc output */
+
+int yynerrs = 0; /* number of errors */
+int yyerrflag = 0; /* error recovery flag */
+
+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;
+}
+
+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;
+}
+
+long
+yylex1(void)
+{
+ long yychar;
+ long *t3p;
+ int c;
+
+ yychar = yylex();
+ 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
+yyparse(void)
+{
+ struct
+ {
+ YYSTYPE yyv;
+ int yys;
+ } yys[YYMAXDEPTH], *yyp, *yypt;
+ short *yyxi;
+ int yyj, yym, yystate, yyn, yyg;
+ YYSTYPE save1, save2;
+ int save3, save4;
+ long yychar;
+
+ save1 = yylval;
+ save2 = yyval;
+ save3 = yynerrs;
+ save4 = yyerrflag;
+
+ yystate = 0;
+ yychar = -1;
+ yynerrs = 0;
+ yyerrflag = 0;
+ yyp = &yys[-1];
+ goto yystack;
+
+ret0:
+ yyn = 0;
+ goto ret;
+
+ret1:
+ yyn = 1;
+ goto ret;
+
+ret:
+ yylval = save1;
+ yyval = save2;
+ yynerrs = save3;
+ yyerrflag = save4;
+ 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)
+ yychar = yylex1();
+ 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)
+ yychar = yylex1();
+
+ /* 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));
+ }
+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 1:
+#line 24 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ putout(yypt[-0].yyv); } break;
+case 2:
+#line 25 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ ERROR "syntax error" WARNING; } break;
+case 3:
+#line 26 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ eqnreg = 0; } break;
+case 5:
+#line 30 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ eqnbox(yypt[-1].yyv, yypt[-0].yyv, 0); } break;
+case 6:
+#line 31 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ eqnbox(yypt[-1].yyv, yypt[-0].yyv, 1); } break;
+case 7:
+#line 32 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ lineup(0); } break;
+case 8:
+#line 35 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = yypt[-0].yyv; lineup(1); } break;
+case 9:
+#line 38 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = yypt[-0].yyv; } break;
+case 10:
+#line 39 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = 0; } break;
+case 11:
+#line 42 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = yypt[-0].yyv; } break;
+case 12:
+#line 43 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = 0; } break;
+case 13:
+#line 46 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = yypt[-1].yyv; } break;
+case 14:
+#line 47 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ text(QTEXT, (char *) yypt[-0].yyv); } break;
+case 15:
+#line 48 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ text(CONTIG, (char *) yypt[-0].yyv); } break;
+case 16:
+#line 49 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ text(SPACE, (char *) 0); } break;
+case 17:
+#line 50 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ text(THIN, (char *) 0); } break;
+case 18:
+#line 51 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ text(TAB, (char *) 0); } break;
+case 19:
+#line 52 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ funny(SUM); } break;
+case 20:
+#line 53 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ funny(PROD); } break;
+case 21:
+#line 54 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ funny(UNION); } break;
+case 22:
+#line 55 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ funny(INTER); } break;
+case 23:
+#line 56 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ boverb(yypt[-2].yyv, yypt[-0].yyv); } break;
+case 24:
+#line 57 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ mark(yypt[-0].yyv); } break;
+case 25:
+#line 58 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ size(yypt[-1].yyv, yypt[-0].yyv); } break;
+case 26:
+#line 59 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ font(yypt[-1].yyv, yypt[-0].yyv); } break;
+case 27:
+#line 60 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ fatbox(yypt[-0].yyv); } break;
+case 28:
+#line 61 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ sqrt(yypt[-0].yyv); } break;
+case 29:
+#line 62 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ps -= deltaps;} break;
+case 30:
+#line 62 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ subsup(yypt[-4].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 31:
+#line 63 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ps -= deltaps;} break;
+case 32:
+#line 63 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ subsup(yypt[-3].yyv, 0, yypt[-0].yyv); } break;
+case 33:
+#line 64 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ps -= deltaps;} break;
+case 34:
+#line 64 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ integral(yypt[-4].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 35:
+#line 65 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ps -= deltaps;} break;
+case 36:
+#line 65 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ integral(yypt[-3].yyv, 0, yypt[-0].yyv); } break;
+case 37:
+#line 66 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ integral(yypt[-0].yyv, 0, 0); } break;
+case 38:
+#line 67 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ps -= deltaps;} break;
+case 39:
+#line 67 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ fromto(yypt[-4].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 40:
+#line 68 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ps -= deltaps;} break;
+case 41:
+#line 68 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ fromto(yypt[-3].yyv, 0, yypt[-0].yyv); } break;
+case 42:
+#line 69 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ paren(yypt[-2].yyv, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 43:
+#line 70 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ paren(yypt[-1].yyv, yypt[-0].yyv, 0); } break;
+case 44:
+#line 71 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ diacrit(yypt[-1].yyv, yypt[-0].yyv); } break;
+case 45:
+#line 72 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ move(FWD, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 46:
+#line 73 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ move(UP, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 47:
+#line 74 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ move(BACK, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 48:
+#line 75 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ move(DOWN, yypt[-1].yyv, yypt[-0].yyv); } break;
+case 49:
+#line 76 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ pile(yypt[-0].yyv); ct = yypt[-0].yyv; } break;
+case 50:
+#line 77 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{yyval=ct;} break;
+case 51:
+#line 77 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ matrix(yypt[-3].yyv); ct = yypt[-3].yyv; } break;
+case 52:
+#line 80 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ setintegral(); } break;
+case 53:
+#line 83 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = atoi((char *) yypt[-1].yyv); } break;
+case 54:
+#line 84 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = atoi((char *) yypt[-1].yyv); } break;
+case 55:
+#line 85 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = atoi((char *) yypt[-1].yyv); } break;
+case 56:
+#line 86 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = atoi((char *) yypt[-1].yyv); } break;
+case 57:
+#line 88 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = HAT; } break;
+case 58:
+#line 89 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = VEC; } break;
+case 59:
+#line 90 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = DYAD; } break;
+case 60:
+#line 91 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = BAR; } break;
+case 61:
+#line 92 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = LOWBAR; } break;
+case 62:
+#line 93 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = HIGHBAR; } break;
+case 63:
+#line 94 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = UNDER; } break;
+case 64:
+#line 95 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = DOT; } break;
+case 65:
+#line 96 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = TILDE; } break;
+case 66:
+#line 97 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = UTILDE; } break;
+case 67:
+#line 98 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = DOTDOT; } break;
+case 68:
+#line 101 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = ((char *)yypt[-0].yyv)[0]; } break;
+case 69:
+#line 102 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = '{'; } break;
+case 70:
+#line 105 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = ((char *)yypt[-0].yyv)[0]; } break;
+case 71:
+#line 106 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = '}'; } break;
+case 74:
+#line 113 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ column(yypt[-3].yyv, DEFGAP); } break;
+case 75:
+#line 114 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{yyval=atoi((char*)yypt[-0].yyv);} break;
+case 76:
+#line 114 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ column(yypt[-5].yyv, yypt[-3].yyv); } break;
+case 77:
+#line 117 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = startcol(LCOL); } break;
+case 78:
+#line 118 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = startcol(CCOL); } break;
+case 79:
+#line 119 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = startcol(RCOL); } break;
+case 80:
+#line 120 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = startcol(COL); } break;
+case 81:
+#line 123 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ lp[ct++] = yypt[-0].yyv; } break;
+case 82:
+#line 124 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ lp[ct++] = yypt[-0].yyv; } break;
+case 83:
+#line 127 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ yyval = ps; setsize((char *) yypt[-0].yyv); } break;
+case 84:
+#line 130 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ static char R[]="R"; setfont(R); } break;
+case 85:
+#line 131 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ static char I[]="I"; setfont(I); } break;
+case 86:
+#line 132 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ static char B[]="B"; setfont(B); } break;
+case 87:
+#line 133 "/usr/local/plan9/src/cmd/eqn/eqn.y"
+{ setfont((char *)yypt[-0].yyv); } break;
+ }
+ goto yystack; /* stack new state and value */
+}
diff --git a/src/cmd/eqn/eqn.y b/src/cmd/eqn/eqn.y
new file mode 100644
index 00000000..74796d7f
--- /dev/null
+++ b/src/cmd/eqn/eqn.y
@@ -0,0 +1,140 @@
+%term CONTIG QTEXT SPACE THIN TAB
+%term MATRIX LCOL CCOL RCOL COL ABOVE
+%term MARK LINEUP
+%term SUM INT PROD UNION INTER
+%term DEFINE TDEFINE NDEFINE DELIM GSIZE GFONT INCLUDE SPACE IFDEF
+%term DOTEQ DOTEN
+
+%right FROM TO
+%left OVER SQRT
+%right SUP SUB
+%right SIZE FONT ROMAN ITALIC BOLD FAT
+%right UP DOWN BACK FWD
+%left LEFT RIGHT
+%right DOT DOTDOT HAT TILDE BAR LOWBAR HIGHBAR UNDER VEC DYAD UTILDE
+
+%{
+#include "e.h"
+
+int yylex(void);
+%}
+
+%%
+
+stuff : eqn { putout($1); }
+ | error { ERROR "syntax error" WARNING; } /* should be SYNTAX */
+ | { eqnreg = 0; }
+ ;
+
+eqn : box
+ | eqn box { eqnbox($1, $2, 0); }
+ | eqn lineupbox { eqnbox($1, $2, 1); }
+ | LINEUP { lineup(0); }
+ ;
+
+lineupbox: LINEUP box { $$ = $2; lineup(1); }
+ ;
+
+sbox : SUP box %prec SUP { $$ = $2; }
+ | %prec SUP { $$ = 0; }
+ ;
+
+tbox : TO box %prec TO { $$ = $2; }
+ | %prec FROM { $$ = 0; }
+ ;
+
+box : '{' eqn '}' { $$ = $2; }
+ | QTEXT { text(QTEXT, (char *) $1); }
+ | CONTIG { text(CONTIG, (char *) $1); }
+ | SPACE { text(SPACE, (char *) 0); }
+ | THIN { text(THIN, (char *) 0); }
+ | TAB { text(TAB, (char *) 0); }
+ | SUM { funny(SUM); }
+ | PROD { funny(PROD); }
+ | UNION { funny(UNION); }
+ | INTER { funny(INTER); }
+ | box OVER box { boverb($1, $3); }
+ | MARK box { mark($2); }
+ | size box %prec SIZE { size($1, $2); }
+ | font box %prec FONT { font($1, $2); }
+ | FAT box { fatbox($2); }
+ | SQRT box { sqrt($2); }
+ | box SUB {ps -= deltaps;} box sbox %prec SUB { subsup($1, $4, $5); }
+ | box SUP {ps -= deltaps;} box %prec SUP { subsup($1, 0, $4); }
+ | int SUB {ps -= deltaps;} box sbox %prec SUB { integral($1, $4, $5); }
+ | int SUP {ps -= deltaps;} box %prec SUP { integral($1, 0, $4); }
+ | int { integral($1, 0, 0); }
+ | box FROM {ps -= deltaps;} box tbox %prec FROM { fromto($1, $4, $5); }
+ | box TO {ps -= deltaps;} box %prec TO { fromto($1, 0, $4); }
+ | left eqn right { paren($1, $2, $3); }
+ | left eqn { paren($1, $2, 0); }
+ | box diacrit { diacrit($1, $2); }
+ | fwd box %prec UP { move(FWD, $1, $2); }
+ | up box %prec UP { move(UP, $1, $2); }
+ | back box %prec UP { move(BACK, $1, $2); }
+ | down box %prec UP { move(DOWN, $1, $2); }
+ | column { pile($1); ct = $1; }
+ | MATRIX {$$=ct;} '{' collist '}' { matrix($2); ct = $2; }
+ ;
+
+int : INT { setintegral(); }
+ ;
+
+fwd : FWD text { $$ = atoi((char *) $1); } ;
+up : UP text { $$ = atoi((char *) $1); } ;
+back : BACK text { $$ = atoi((char *) $1); } ;
+down : DOWN text { $$ = atoi((char *) $1); } ;
+
+diacrit : HAT { $$ = HAT; }
+ | VEC { $$ = VEC; }
+ | DYAD { $$ = DYAD; }
+ | BAR { $$ = BAR; }
+ | LOWBAR { $$ = LOWBAR; }
+ | HIGHBAR { $$ = HIGHBAR; }
+ | UNDER { $$ = UNDER; } /* underbar */
+ | DOT { $$ = DOT; }
+ | TILDE { $$ = TILDE; }
+ | UTILDE { $$ = UTILDE; }
+ | DOTDOT { $$ = DOTDOT; } /* umlaut = double dot */
+ ;
+
+left : LEFT text { $$ = ((char *)$2)[0]; }
+ | LEFT '{' { $$ = '{'; }
+ ;
+
+right : RIGHT text { $$ = ((char *)$2)[0]; }
+ | RIGHT '}' { $$ = '}'; }
+ ;
+
+collist : column
+ | collist column
+ ;
+
+column : col '{' list '}' { column($1, DEFGAP); }
+ | col text {$$=atoi((char*)$2);} '{' list '}' { column($1, $3); }
+ ;
+
+col : LCOL { $$ = startcol(LCOL); }
+ | CCOL { $$ = startcol(CCOL); }
+ | RCOL { $$ = startcol(RCOL); }
+ | COL { $$ = startcol(COL); }
+ ;
+
+list : eqn { lp[ct++] = $1; }
+ | list ABOVE eqn { lp[ct++] = $3; }
+ ;
+
+size : SIZE text { $$ = ps; setsize((char *) $2); }
+ ;
+
+font : ROMAN { static char R[]="R"; setfont(R); }
+ | ITALIC { static char I[]="I"; setfont(I); }
+ | BOLD { static char B[]="B"; setfont(B); }
+ | FONT text { setfont((char *)$2); }
+ ;
+
+text : CONTIG
+ | QTEXT
+ ;
+
+%%
diff --git a/src/cmd/eqn/eqnbox.c b/src/cmd/eqn/eqnbox.c
new file mode 100644
index 00000000..7dd0b867
--- /dev/null
+++ b/src/cmd/eqn/eqnbox.c
@@ -0,0 +1,24 @@
+#include "e.h"
+
+void eqnbox(int p1, int p2, int lu)
+{
+ double b, h;
+ char *sh;
+ extern char *IRspace;
+
+ yyval = p1;
+ b = max(ebase[p1], ebase[p2]);
+ eht[yyval] = h = b + max(eht[p1]-ebase[p1],
+ eht[p2]-ebase[p2]);
+ ebase[yyval] = b;
+ dprintf(".\tS%d <- %d %d; b=%g, h=%g\n", yyval, p1, p2, b, h);
+ sh = pad(class[rclass[p1]][lclass[p2]]);
+ if (lu) {
+ printf(".nr %d \\w'\\*(%d%s'\n", p1, p1, sh);
+ printf(".ds %d \\h'|\\n(09u-\\n(%du'\\*(%d\n", p1, p1, p1);
+ }
+ printf(".as %d \"%s\\*(%d\n", yyval, sh, p2);
+ rfont[p1] = rfont[p2];
+ rclass[p1] = rclass[p2];
+ sfree(p2);
+}
diff --git a/src/cmd/eqn/font.c b/src/cmd/eqn/font.c
new file mode 100644
index 00000000..3fb01119
--- /dev/null
+++ b/src/cmd/eqn/font.c
@@ -0,0 +1,70 @@
+# include "e.h"
+
+void setfont(char *ch1)
+{
+ yyval = ft;
+ if (strcmp(ch1, "I") == 0) { /* I and italic mean merely position 2 */
+ *ch1 = '2';
+ ft = ITAL;
+ } else if (strcmp(ch1, "B") == 0) { /* and similarly for B & bold */
+ *ch1 = '3';
+ ft = BLD;
+ } else if (strcmp(ch1, "R") == 0) { /* and R and roman */
+ *ch1 = '1';
+ ft = ROM;
+ } else {
+ ft = ROM; /* assume it's a roman style */
+ }
+ ftp++;
+ if (ftp >= &ftstack[10])
+ ERROR "font stack overflow (10)" FATAL;
+ ftp->ft = ft;
+ if (ch1[1] == 0) { /* 1-char name */
+ ftp->name[0] = *ch1;
+ ftp->name[1] = '\0';
+ } else
+ sprintf(ftp->name, "(%s", ch1);
+ dprintf(".\tsetfont %s %c\n", ch1, ft);
+}
+
+void font(int p1, int p2)
+{
+ /* old font in p1, new in ft */
+ yyval = p2;
+ lfont[yyval] = rfont[yyval] = ft==ITAL ? ITAL : ROM;
+ ftp--;
+ ft = p1;
+}
+
+void globfont(void)
+{
+ char temp[20];
+
+ getstr(temp, sizeof(temp));
+ yyval = eqnreg = 0;
+ if (strcmp(temp, "I") == 0 || strncmp(temp, "it", 2) == 0) {
+ ft = ITAL;
+ strcpy(temp, "2");
+ } else if (strcmp(temp, "B") == 0 || strncmp(temp, "bo", 2) == 0) {
+ ft = BLD;
+ strcpy(temp, "3");
+ } else if (strcmp(temp, "R") == 0 || strncmp(temp, "ro", 2) == 0) {
+ ft = ROM;
+ strcpy(temp, "1");
+ } else {
+ ft = ROM; /* assume it's a roman style */
+ }
+ ftstack[0].ft = ft;
+ if (temp[1] == 0) /* 1-char name */
+ strcpy(ftstack[0].name, temp);
+ else
+ sprintf(ftstack[0].name, "(%.2s", temp);
+}
+
+void fatbox(int p)
+{
+ extern double Fatshift;
+
+ yyval = p;
+ printf(".ds %d \\*(%d\\h'-\\w'\\*(%d'u+%gm'\\*(%d\n", p, p, p, Fatshift, p);
+}
diff --git a/src/cmd/eqn/fromto.c b/src/cmd/eqn/fromto.c
new file mode 100644
index 00000000..2d4d7f74
--- /dev/null
+++ b/src/cmd/eqn/fromto.c
@@ -0,0 +1,52 @@
+# include "e.h"
+
+void fromto(int p1, int p2, int p3)
+{
+ double b, h1, b1, t;
+ int subps;
+
+ yyval = salloc();
+ lfont[yyval] = rfont[yyval] = 0;
+ h1 = eht[yyval] = eht[p1];
+ b1 = ebase[p1];
+ b = 0;
+ subps = ps;
+ ps += deltaps;
+ nrwid(p1, ps, p1);
+ printf(".nr %d \\n(%d\n", yyval, p1);
+ if (p2 > 0) {
+ nrwid(p2, subps, p2);
+ printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", p2, yyval, yyval, p2);
+ eht[yyval] += eht[p2];
+ b = eht[p2];
+ }
+ if (p3 > 0) {
+ nrwid(p3, subps, p3);
+ printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", p3, yyval, yyval, p3);
+ eht[yyval] += eht[p3];
+ }
+ printf(".ds %d ", yyval); /* bottom of middle box */
+ if (p2 > 0) {
+ t = eht[p2]-ebase[p2]+b1;
+ printf("\\v'%gm'\\h'\\n(%du-\\n(%du/2u'%s\\*(%d%s",
+ REL(t,ps), yyval, p2, DPS(ps,subps), p2, DPS(subps,ps));
+ printf("\\h'-\\n(%du-\\n(%du/2u'\\v'%gm'\\\n",
+ yyval, p2, REL(-t,ps));
+ }
+ printf("\\h'\\n(%du-\\n(%du/2u'\\*(%d\\h'\\n(%du-\\n(%du/2u'\\\n",
+ yyval, p1, p1, yyval, p1);
+ if (p3 >0) {
+ t = h1-b1+ebase[p3];
+ printf("\\v'%gm'\\h'-\\n(%du-\\n(%du/2u'%s\\*(%d%s\\h'\\n(%du-\\n(%du/2u'\\v'%gm'\\\n",
+ REL(-t,ps), yyval, p3, DPS(ps,subps), p3, DPS(subps,ps), yyval, p3, REL(t,ps));
+ }
+ printf("\n");
+ ebase[yyval] = b + b1;
+ dprintf(".\tS%d <- %d from %d to %d; h=%g b=%g\n",
+ yyval, p1, p2, p3, eht[yyval], ebase[yyval]);
+ sfree(p1);
+ if (p2 > 0)
+ sfree(p2);
+ if (p3 > 0)
+ sfree(p3);
+}
diff --git a/src/cmd/eqn/funny.c b/src/cmd/eqn/funny.c
new file mode 100644
index 00000000..85955fce
--- /dev/null
+++ b/src/cmd/eqn/funny.c
@@ -0,0 +1,30 @@
+#include "e.h"
+#include "y.tab.h"
+
+extern int Funnyps;
+extern double Funnyht, Funnybase;
+
+void funny(int n)
+{
+ char *f = 0;
+
+ yyval = salloc();
+ switch (n) {
+ case SUM:
+ f = lookup(deftbl, "sum_def")->cval; break;
+ case UNION:
+ f = lookup(deftbl, "union_def")->cval; break;
+ case INTER: /* intersection */
+ f = lookup(deftbl, "inter_def")->cval; break;
+ case PROD:
+ f = lookup(deftbl, "prod_def")->cval; break;
+ default:
+ ERROR "funny type %d in funny", n FATAL;
+ }
+ printf(".ds %d %s\n", yyval, f);
+ eht[yyval] = EM(1.0, ps+Funnyps) - EM(Funnyht, ps);
+ ebase[yyval] = EM(Funnybase, ps);
+ dprintf(".\tS%d <- %s; h=%g b=%g\n",
+ yyval, f, eht[yyval], ebase[yyval]);
+ lfont[yyval] = rfont[yyval] = ROM;
+}
diff --git a/src/cmd/eqn/glob.c b/src/cmd/eqn/glob.c
new file mode 100644
index 00000000..6ca1a1da
--- /dev/null
+++ b/src/cmd/eqn/glob.c
@@ -0,0 +1,35 @@
+#include "e.h"
+
+ /* YOU MAY WANT TO CHANGE THIS */
+char *typesetter = "post"; /* type of typesetter today */
+int ttype = DEVPOST;
+int minsize = 4; /* min size it can handle */
+
+
+int dbg; /* debugging print if non-zero */
+int lp[200]; /* stack for things like piles and matrices */
+int ct; /* pointer to lp */
+int used[100]; /* available registers */
+int ps; /* default init point size */
+int deltaps = 3; /* default change in ps */
+int dps_set = 0; /* 1 => -p option used */
+int gsize = 10; /* default initial point size */
+int ft = '2';
+Font ftstack[10] = { '2', "2" }; /* bottom is global font */
+Font *ftp = ftstack;
+int szstack[10]; /* non-zero if absolute size set at this level */
+int nszstack = 0;
+int display = 0; /* 1=>display, 0=>.EQ/.EN */
+
+int synerr; /* 1 if syntax err in this eqn */
+double eht[100]; /* height in ems at gsize */
+double ebase[100]; /* base: where one enters above bottom */
+int lfont[100]; /* leftmost and rightmost font associated with this thing */
+int rfont[100];
+int lclass[100]; /* leftmost and rightmost class associated with this thing */
+int rclass[100];
+int eqnreg; /* register where final string appears */
+double eqnht; /* final height of equation */
+int lefteq = '\0'; /* left in-line delimiter */
+int righteq = '\0'; /* right in-line delimiter */
+int markline = 0; /* 1 if this EQ/EN contains mark; 2 if lineup */
diff --git a/src/cmd/eqn/input.c b/src/cmd/eqn/input.c
new file mode 100644
index 00000000..3b865671
--- /dev/null
+++ b/src/cmd/eqn/input.c
@@ -0,0 +1,289 @@
+#include "e.h"
+#include "y.tab.h"
+#include <ctype.h>
+#include <errno.h>
+
+Infile infile[10];
+Infile *curfile = infile;
+
+#define MAXSRC 50
+Src src[MAXSRC]; /* input source stack */
+Src *srcp = src;
+
+extern int getarg(char *);
+extern void eprint(void);
+
+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 String:
+ printf("push string <%s>\n", ptr);
+ break;
+ case Free:
+ printf("push free <%s>\n", ptr);
+ break;
+ default:
+ ERROR "pushed bad type %d\n", 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 String:
+ printf("pop string\n");
+ break;
+ case Free:
+ printf("pop free\n");
+ break;
+ default:
+ ERROR "pop weird input %d\n", srcp->type FATAL;
+ }
+ }
+ srcp--;
+}
+
+Arg args[10]; /* argument frames */
+Arg *argfp = args; /* frame pointer */
+int argcnt; /* number of arguments seen so far */
+
+void dodef(tbl *stp) /* collect args and switch input to defn */
+{
+ int i, len;
+ char *p;
+ Arg *ap;
+
+ ap = argfp+1;
+ if (ap >= args+10)
+ ERROR "more than arguments\n" FATAL;
+ argcnt = 0;
+ if (input() != '(')
+ ERROR "disaster in dodef\n"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->cval);
+}
+
+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!\n" 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;
+
+input(void)
+{
+ register int c = 0;
+
+ loop:
+ switch (srcp->type) {
+ case File:
+ c = getc(curfile->fin);
+ if (c == EOF) {
+ if (curfile == infile)
+ break;
+ if (curfile->fin != stdin) {
+ fclose(curfile->fin);
+ free(curfile->fname); /* assumes allocated */
+ }
+ curfile--;
+ printf(".lf %d %s\n", curfile->lineno, curfile->fname);
+ popsrc();
+ goto loop;
+ }
+ if (c == '\n')
+ curfile->lineno++;
+ 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 Free: /* free string */
+ free(srcp->sp);
+ popsrc();
+ goto loop;
+ }
+ if (ep >= ebuf + sizeof ebuf)
+ ep = ebuf;
+ *ep++ = c;
+ return c;
+}
+
+
+unput(int c)
+{
+ if (++pb >= pbuf + sizeof pbuf)
+ ERROR "pushback overflow\n"FATAL;
+ if (--ep < ebuf)
+ ep = ebuf + sizeof(ebuf) - 1;
+ *pb = c;
+ pushsrc(Char, pb);
+ return c;
+}
+
+void pbstr(char *s)
+{
+ pushsrc(String, s);
+}
+
+void error(int die, char *s)
+{
+ extern char *cmdname;
+
+ if (synerr)
+ return;
+ fprintf(stderr, "%s: ", cmdname);
+ fprintf(stderr, s);
+ if (errno > 0)
+ perror("???");
+ if (curfile->fin)
+ fprintf(stderr, " near %s:%d",
+ curfile->fname, curfile->lineno+1);
+ fprintf(stderr, "\n");
+ eprint();
+ synerr = 1;
+ errno = 0;
+ if (die) {
+ if (dbg)
+ abort();
+ else
+ exit(1);
+ }
+}
+
+void yyerror(char *s)
+{
+ error(0, s); /* temporary */
+}
+
+char errbuf[200];
+
+void eprint(void) /* try to print context around error */
+{
+ char *p, *q;
+
+ if (ep == ebuf)
+ return; /* no context */
+ 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);
+ if (curfile->fin)
+ fgets(ebuf, sizeof ebuf, curfile->fin);
+ fprintf(stderr, "%s", ebuf);
+ pbstr("\n.EN\n"); /* safety first */
+ ep = ebuf;
+}
diff --git a/src/cmd/eqn/integral.c b/src/cmd/eqn/integral.c
new file mode 100644
index 00000000..2b1c9e3f
--- /dev/null
+++ b/src/cmd/eqn/integral.c
@@ -0,0 +1,30 @@
+#include "e.h"
+#include "y.tab.h"
+
+extern int Intps;
+extern double Intht, Intbase, Int1h, Int1v, Int2h, Int2v;
+
+void integral(int p, int p1, int p2)
+{
+ if (p1 != 0)
+ printf(".ds %d \\h'%gm'\\v'%gm'\\*(%d\\v'%gm'\n", p1, -Int1h, Int1v, p1, -Int1v);
+ if (p2 != 0)
+ printf(".ds %d \\v'%gm'\\h'%gm'\\*(%d\\v'%gm'\n", p2, -Int2v, Int2h, p2, Int2v);
+ if (p1 != 0 && p2 != 0)
+ shift2(p, p1, p2);
+ else if (p1 != 0)
+ bshiftb(p, SUB, p1);
+ else if (p2 != 0)
+ bshiftb(p, SUP, p2);
+ dprintf(".\tintegral: S%d; h=%g b=%g\n", p, eht[p], ebase[p]);
+ lfont[p] = ROM;
+}
+
+void setintegral(void)
+{
+ yyval = salloc();
+ printf(".ds %d %s\n", yyval, lookup(deftbl, "int_def")->cval);
+ eht[yyval] = EM(Intht, ps+Intps);
+ ebase[yyval] = EM(Intbase, ps);
+ lfont[yyval] = rfont[yyval] = ROM;
+}
diff --git a/src/cmd/eqn/lex.c b/src/cmd/eqn/lex.c
new file mode 100644
index 00000000..e535b869
--- /dev/null
+++ b/src/cmd/eqn/lex.c
@@ -0,0 +1,265 @@
+#include "e.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+#define SSIZE 1000
+char token[SSIZE];
+int sp;
+
+void space(void);
+void dodef(tbl *);
+void define(int);
+void ifdef(void);
+void include(void);
+void delim(void);
+
+yylex(void)
+{
+ register int c;
+ tbl *tp;
+
+ begin:
+ while ((c = input()) == ' ' || c == '\n' || c == '\t')
+ ;
+ yylval = c;
+ switch (c) {
+ case EOF:
+ ERROR "unexpected end of input inside equation" WARNING;
+ return(EOF);
+ case '~':
+ return(SPACE);
+ case '^':
+ return(THIN);
+ /* case '\t':
+ return(TAB);
+ */
+ case '{':
+ return('{');
+ case '}':
+ return('}');
+ case '"':
+ for (sp = 0; (c=input())!='"' && c != '\n'; ) {
+ if (c == '\\')
+ if ((c = input()) != '"')
+ token[sp++] = '\\';
+ token[sp++] = c;
+ if (sp >= SSIZE)
+ ERROR "quoted string %.20s... too long", token FATAL;
+ }
+ token[sp] = '\0';
+ yylval = (int) &token[0];
+ if (c == '\n')
+ ERROR "missing \" in %.20s", token WARNING;
+ return(QTEXT);
+ }
+ if (!display && c == righteq)
+ return(EOF);
+
+ unput(c);
+ getstr(token, SSIZE);
+ dprintf(".\tlex token = |%s|\n", token);
+ if ((tp = lookup(deftbl, token)) != NULL) { /* defined term */
+ c = input();
+ unput(c);
+ if (c == '(') /* macro with args */
+ dodef(tp);
+ else { /* no args */
+ unput(' ');
+ pbstr(tp->cval);
+ dprintf(".\tfound %s|=%s|\n", token, tp->cval);
+ }
+ goto begin;
+ }
+
+ if ((tp = lookup(keytbl, token)) == NULL) /* not a keyword */
+ return CONTIG;
+
+ switch (tp->ival) { /* some kind of keyword */
+ case DEFINE: case TDEFINE: case NDEFINE:
+ define(tp->ival);
+ break;
+ case IFDEF:
+ ifdef();
+ break;
+ case DELIM:
+ delim();
+ break;
+ case GSIZE:
+ globsize();
+ break;
+ case GFONT:
+ globfont();
+ break;
+ case INCLUDE:
+ include();
+ break;
+ case SPACE:
+ space();
+ break;
+ case DOTEQ:
+ /* .EQ inside equation -- should warn if at bottom level */
+ break;
+ case DOTEN:
+ if (curfile == infile)
+ return EOF;
+ /* else ignore nested .EN */
+ break;
+ default:
+ return tp->ival;
+ }
+ goto begin;
+}
+
+void getstr(char *s, int n)
+{
+ register int c;
+ register char *p;
+
+ p = s;
+ while ((c = input()) == ' ' || c == '\n')
+ ;
+ if (c == EOF) {
+ *s = 0;
+ return;
+ }
+ while (c != ' ' && c != '\t' && c != '\n' && c != '{' && c != '}'
+ && c != '"' && c != '~' && c != '^') {
+ if (!display && c == righteq)
+ break;
+ if (c == '(' && p > s) { /* might be defined(...) */
+ *p = '\0';
+ if (lookup(deftbl, s) != NULL)
+ break;
+ }
+ if (c == '\\')
+ if ((c = input()) != '"')
+ *p++ = '\\';
+ *p++ = c;
+ if (--n <= 0)
+ ERROR "token %.20s... too long", s FATAL;
+ c = input();
+ }
+ unput(c);
+ *p = '\0';
+ yylval = (int) s;
+}
+
+cstr(char *s, int quote, int maxs)
+{
+ int del, c, i;
+
+ s[0] = 0;
+ while ((del=input()) == ' ' || del == '\t')
+ ;
+ if (quote)
+ for (i=0; (c=input()) != del && c != EOF;) {
+ s[i++] = c;
+ if (i >= maxs)
+ return(1); /* disaster */
+ }
+ else {
+ if (del == '\n')
+ return(1);
+ s[0] = del;
+ for (i=1; (c=input())!=' ' && c!= '\t' && c!='\n' && c!=EOF;) {
+ s[i++] = c;
+ if (i >= maxs)
+ return(1); /* disaster */
+ }
+ }
+ s[i] = '\0';
+ if (c == EOF)
+ ERROR "Unexpected end of input at %.20s", s FATAL;
+ return(0);
+}
+
+void define(int type)
+{
+ char *p1, *p2;
+ extern int ftune(char *, char *);
+
+ getstr(token, SSIZE); /* get name */
+ if (type != DEFINE) {
+ cstr(token, 1, SSIZE); /* skip the definition too */
+ return;
+ }
+ p1 = strsave(token);
+ if (cstr(token, 1, SSIZE))
+ ERROR "Unterminated definition at %.20s", token FATAL;
+ if (lookup(ftunetbl, p1) != NULL) { /* double tuning param */
+ dprintf(".\ttune %s %s\n", p1, token);
+ ftune(p1, token);
+ } else {
+ p2 = strsave(token);
+ install(deftbl, p1, p2, 0);
+ dprintf(".\tname %s defined as %s\n", p1, p2);
+ }
+}
+
+void ifdef(void) /* do body if name is defined */
+{
+ char name[100], *p;
+
+ getstr(name, sizeof(name)); /* get name */
+ cstr(token, 1, SSIZE); /* and body */
+ if (lookup(deftbl, name) != NULL) { /* found it */
+ p = strsave(token);
+ pushsrc(Free, p);
+ pushsrc(String, p);
+ }
+}
+
+char *spaceval = NULL;
+
+void space(void) /* collect line of form "space amt" to replace \x in output */
+{
+ getstr(token, SSIZE);
+ spaceval = strsave(token);
+ dprintf(".\tsetting spaceval to %s\n", token);
+}
+
+char *strsave(char *s)
+{
+ register char *q;
+
+ q = malloc(strlen(s)+1);
+ if (q == NULL)
+ ERROR "out of space in strsave on %s", s FATAL;
+ strcpy(q, s);
+ return(q);
+}
+
+void include(void)
+{
+ char name[100];
+ FILE *fin;
+ int c;
+ extern int errno;
+
+ while ((c = input()) == ' ')
+ ;
+ unput(c);
+ cstr(name, c == '"', sizeof(name)); /* gets it quoted or not */
+ if ((fin = fopen(name, "r")) == NULL)
+ ERROR "can't open file %s", name FATAL;
+ errno = 0;
+ curfile++;
+ curfile->fin = fin;
+ curfile->fname = strsave(name);
+ curfile->lineno = 0;
+ printf(".lf 1 %s\n", curfile->fname);
+ pushsrc(File, curfile->fname);
+}
+
+void delim(void)
+{
+ yyval = eqnreg = 0;
+ if (cstr(token, 0, SSIZE))
+ ERROR "Bizarre delimiters" FATAL;
+ lefteq = token[0];
+ righteq = token[1];
+ if (!isprint(lefteq) || !isprint(righteq))
+ ERROR "Bizarre delimiters" FATAL;
+ if (lefteq == 'o' && righteq == 'f')
+ lefteq = righteq = '\0';
+}
diff --git a/src/cmd/eqn/lookup.c b/src/cmd/eqn/lookup.c
new file mode 100644
index 00000000..4eb94373
--- /dev/null
+++ b/src/cmd/eqn/lookup.c
@@ -0,0 +1,219 @@
+#include "e.h"
+#include "y.tab.h"
+
+tbl *keytbl[TBLSIZE]; /* key words */
+tbl *restbl[TBLSIZE]; /* reserved words */
+tbl *deftbl[TBLSIZE]; /* user-defined names */
+
+struct keyword {
+ char *key;
+ int keyval;
+} keyword[] ={
+ "sub", SUB,
+ "sup", SUP,
+ ".EN", DOTEN,
+ ".EQ", DOTEQ,
+ "from", FROM,
+ "to", TO,
+ "sum", SUM,
+ "hat", HAT,
+ "vec", VEC,
+ "dyad", DYAD,
+ "dot", DOT,
+ "dotdot", DOTDOT,
+ "bar", BAR,
+ "lowbar", LOWBAR,
+ "highbar", HIGHBAR,
+ "tilde", TILDE,
+ "utilde", UTILDE,
+ "under", UNDER,
+ "prod", PROD,
+ "int", INT,
+ "integral", INT,
+ "union", UNION,
+ "inter", INTER,
+ "matrix", MATRIX,
+ "col", COL,
+ "lcol", LCOL,
+ "ccol", CCOL,
+ "rcol", RCOL,
+ "pile", COL, /* synonyms ... */
+ "lpile", LCOL,
+ "cpile", CCOL,
+ "rpile", RCOL,
+ "over", OVER,
+ "sqrt", SQRT,
+ "above", ABOVE,
+ "size", SIZE,
+ "font", FONT,
+ "fat", FAT,
+ "roman", ROMAN,
+ "italic", ITALIC,
+ "bold", BOLD,
+ "left", LEFT,
+ "right", RIGHT,
+ "delim", DELIM,
+ "define", DEFINE,
+ "tdefine", DEFINE,
+ "ndefine", NDEFINE,
+ "ifdef", IFDEF,
+ "gsize", GSIZE,
+ ".gsize", GSIZE,
+ "gfont", GFONT,
+ "include", INCLUDE,
+ "copy", INCLUDE,
+ "space", SPACE,
+ "up", UP,
+ "down", DOWN,
+ "fwd", FWD,
+ "back", BACK,
+ "mark", MARK,
+ "lineup", LINEUP,
+ 0, 0
+};
+
+struct resword {
+ char *res;
+ char *resval;
+} resword[] ={
+ ">=", "\\(>=",
+ "<=", "\\(<=",
+ "==", "\\(==",
+ "!=", "\\(!=",
+ "+-", "\\(+-",
+ "->", "\\(->",
+ "<-", "\\(<-",
+ "inf", "\\(if",
+ "infinity", "\\(if",
+ "partial", "\\(pd",
+ "half", "\\f1\\(12\\fP",
+ "prime", "\\f1\\v'.5m'\\s+3\\(fm\\s-3\\v'-.5m'\\fP",
+ "dollar", "\\f1$\\fP",
+ "nothing", "",
+ "times", "\\(mu",
+ "del", "\\(gr",
+ "grad", "\\(gr",
+ "approx", "\\v'-.2m'\\z\\(ap\\v'.25m'\\(ap\\v'-.05m'",
+ "cdot", "\\v'-.3m'.\\v'.3m'",
+ "...", "\\v'-.25m'\\ .\\ .\\ .\\ \\v'.25m'",
+ ",...,", "\\f1,\\fP\\ .\\ .\\ .\\ \\f1,\\fP\\|",
+ "alpha", "α",
+ "ALPHA", "Α",
+ "beta", "β",
+ "BETA", "Β",
+ "gamma", "γ",
+ "GAMMA", "Γ",
+ "delta", "δ",
+ "DELTA", "Δ",
+ "epsilon", "ε",
+ "EPSILON", "Ε",
+ "omega", "ω",
+ "OMEGA", "Ω",
+ "lambda", "λ",
+ "LAMBDA", "Λ",
+ "mu", "μ",
+ "MU", "Μ",
+ "nu", "ν",
+ "NU", "Ν",
+ "theta", "θ",
+ "THETA", "Θ",
+ "phi", "φ",
+ "PHI", "Φ",
+ "pi", "π",
+ "PI", "Π",
+ "sigma", "σ",
+ "SIGMA", "Σ",
+ "xi", "ξ",
+ "XI", "Ξ",
+ "zeta", "ζ",
+ "ZETA", "Ζ",
+ "iota", "ι",
+ "IOTA", "Ι",
+ "eta", "η",
+ "ETA", "Η",
+ "kappa", "κ",
+ "KAPPA", "Κ",
+ "rho", "ρ",
+ "RHO", "Ρ",
+ "tau", "τ",
+ "TAU", "Τ",
+ "omicron", "ο",
+ "OMICRON", "Ο",
+ "upsilon", "υ",
+ "UPSILON", "Υ",
+ "psi", "ψ",
+ "PSI", "Ψ",
+ "chi", "χ",
+ "CHI", "Χ",
+ "and", "\\f1and\\fP",
+ "for", "\\f1for\\fP",
+ "if", "\\f1if\\fP",
+ "Re", "\\f1Re\\fP",
+ "Im", "\\f1Im\\fP",
+ "sin", "\\f1sin\\fP",
+ "cos", "\\f1cos\\fP",
+ "tan", "\\f1tan\\fP",
+ "arc", "\\f1arc\\fP",
+ "sinh", "\\f1sinh\\fP",
+ "coth", "\\f1coth\\fP",
+ "tanh", "\\f1tanh\\fP",
+ "cosh", "\\f1cosh\\fP",
+ "lim", "\\f1lim\\fP",
+ "log", "\\f1log\\fP",
+ "ln", "\\f1ln\\fP",
+ "max", "\\f1max\\fP",
+ "min", "\\f1min\\fP",
+ "exp", "\\f1exp\\fP",
+ "det", "\\f1det\\fP",
+ 0, 0
+};
+
+int hash(char *s)
+{
+ register unsigned int h;
+
+ for (h = 0; *s != '\0'; )
+ h += *s++;
+ h %= TBLSIZE;
+ return h;
+}
+
+tbl *lookup(tbl **tblp, char *name) /* find name in tbl */
+{
+ register tbl *p;
+
+ for (p = tblp[hash(name)]; p != NULL; p = p->next)
+ if (strcmp(name, p->name) == 0)
+ return(p);
+ return(NULL);
+}
+
+void install(tbl **tblp, char *name, char *cval, int ival) /* install name, vals in tblp */
+{
+ register tbl *p;
+ int h;
+
+ if ((p = lookup(tblp, name)) == NULL) {
+ p = (tbl *) malloc(sizeof(tbl));
+ if (p == NULL)
+ ERROR "out of space in install" FATAL;
+ h = hash(name); /* bad visibility here */
+ p->name = name;
+ p->next = tblp[h];
+ tblp[h] = p;
+ }
+ p->cval = cval;
+ p->ival = ival;
+}
+
+void init_tbl(void) /* initialize tables */
+{
+ int i;
+ extern int init_tune(void);
+
+ for (i = 0; keyword[i].key != NULL; i++)
+ install(keytbl, keyword[i].key, (char *) 0, keyword[i].keyval);
+ for (i = 0; resword[i].res != NULL; i++)
+ install(restbl, resword[i].res, resword[i].resval, 0);
+ init_tune(); /* tuning table done in tuning.c */
+}
diff --git a/src/cmd/eqn/main.c b/src/cmd/eqn/main.c
new file mode 100644
index 00000000..a06fd165
--- /dev/null
+++ b/src/cmd/eqn/main.c
@@ -0,0 +1,333 @@
+#include "e.h"
+
+#define MAXLINE 3600 /* maximum input line */
+
+char *version = "version Oct 24, 1991";
+
+char in[MAXLINE]; /* input buffer */
+int noeqn;
+char *cmdname;
+
+int yyparse(void);
+void settype(char *);
+int getdata(void);
+int getline(char *);
+#define inline einline
+void inline(void);
+void init(void);
+void init_tbl(void);
+
+void
+main(int argc, char *argv[])
+{
+ char *p, buf[20];
+
+ cmdname = argv[0];
+ if (p = getenv("TYPESETTER"))
+ typesetter = p;
+ while (argc > 1 && argv[1][0] == '-') {
+ switch (argv[1][1]) {
+
+ case 'd':
+ if (argv[1][2] == '\0') {
+ dbg++;
+ printf("...\teqn %s\n", version);
+ } else {
+ lefteq = argv[1][2];
+ righteq = argv[1][3];
+ }
+ break;
+ case 's': szstack[0] = gsize = atoi(&argv[1][2]); break;
+ case 'p': deltaps = atoi(&argv[1][2]); dps_set = 1; break;
+ case 'm': minsize = atoi(&argv[1][2]); break;
+ case 'f': strcpy(ftstack[0].name,&argv[1][2]); break;
+ case 'e': noeqn++; break;
+ case 'T': typesetter = &argv[1][2]; break;
+ default:
+ fprintf(stderr, "%s: unknown option %s\n", cmdname, argv[1]);
+ break;
+ }
+ argc--;
+ argv++;
+ }
+ settype(typesetter);
+ sprintf(buf, "\"%s\"", typesetter);
+ install(deftbl, strsave(typesetter), strsave(buf), 0);
+ init_tbl(); /* install other keywords in tables */
+ curfile = infile;
+ pushsrc(File, curfile->fname);
+ if (argc <= 1) {
+ curfile->fin = stdin;
+ curfile->fname = strsave("-");
+ getdata();
+ } else
+ while (argc-- > 1) {
+ if (strcmp(*++argv, "-") == 0)
+ curfile->fin = stdin;
+ else if ((curfile->fin = fopen(*argv, "r")) == NULL)
+ ERROR "can't open file %s", *argv FATAL;
+ curfile->fname = strsave(*argv);
+ getdata();
+ if (curfile->fin != stdin)
+ fclose(curfile->fin);
+ }
+ exit(0);
+}
+
+void settype(char *s) /* initialize data for particular typesetter */
+ /* the minsize could profitably come from the */
+{ /* troff description file /usr/lib/font/dev.../DESC.out */
+ if (strcmp(s, "202") == 0)
+ { minsize = 5; ttype = DEV202; }
+ else if (strcmp(s, "aps") == 0)
+ { minsize = 5; ttype = DEVAPS; }
+ else if (strcmp(s, "cat") == 0)
+ { minsize = 6; ttype = DEVCAT; }
+ else if (strcmp(s, "post") == 0)
+ { minsize = 4; ttype = DEVPOST; }
+ else
+ { minsize = 5; ttype = DEV202; }
+}
+
+getdata(void)
+{
+ int i, type, ln;
+ char fname[100];
+ extern int errno;
+
+ errno = 0;
+ curfile->lineno = 0;
+ printf(".lf 1 %s\n", curfile->fname);
+ while ((type = getline(in)) != EOF) {
+ if (in[0] == '.' && in[1] == 'E' && in[2] == 'Q') {
+ for (i = 11; i < 100; i++)
+ used[i] = 0;
+ printf("%s", in);
+ if (markline) { /* turn off from last time */
+ printf(".nr MK 0\n");
+ markline = 0;
+ }
+ display = 1;
+ init();
+ yyparse();
+ if (eqnreg > 0) {
+ if (markline)
+ printf(".nr MK %d\n", markline); /* for -ms macros */
+ printf(".if %gm>\\n(.v .ne %gm\n", eqnht, eqnht);
+ printf(".rn %d 10\n", eqnreg);
+ if (!noeqn)
+ printf("\\&\\*(10\n");
+ }
+ printf(".EN");
+ while (putchar(input()) != '\n')
+ ;
+ printf(".lf %d\n", curfile->lineno+1);
+ }
+ else if (type == lefteq)
+ inline();
+ else if (in[0] == '.' && in[1] == 'l' && in[2] == 'f') {
+ if (sscanf(in+3, "%d %s", &ln, fname) == 2) {
+ free(curfile->fname);
+ printf(".lf %d %s\n", curfile->lineno = ln, curfile->fname = strsave(fname));
+ } else
+ printf(".lf %d\n", curfile->lineno = ln);
+ } else
+ printf("%s", in);
+ }
+ return(0);
+}
+
+getline(char *s)
+{
+ register c;
+
+ while ((c=input()) != '\n' && c != EOF && c != lefteq) {
+ if (s >= in+MAXLINE) {
+ ERROR "input line too long: %.20s\n", in WARNING;
+ in[MAXLINE] = '\0';
+ break;
+ }
+ *s++ = c;
+ }
+ if (c != lefteq)
+ *s++ = c;
+ *s = '\0';
+ return(c);
+}
+
+void inline(void)
+{
+ int ds, n, sz1 = 0;
+
+ n = curfile->lineno;
+ if (szstack[0] != 0)
+ printf(".nr %d \\n(.s\n", sz1 = salloc());
+ ds = salloc();
+ printf(".rm %d \n", ds);
+ display = 0;
+ do {
+ if (*in)
+ printf(".as %d \"%s\n", ds, in);
+ init();
+ yyparse();
+ if (eqnreg > 0) {
+ printf(".as %d \\*(%d\n", ds, eqnreg);
+ sfree(eqnreg);
+ printf(".lf %d\n", curfile->lineno+1);
+ }
+ } while (getline(in) == lefteq);
+ if (*in)
+ printf(".as %d \"%s", ds, in);
+ if (sz1)
+ printf("\\s\\n(%d", sz1);
+ printf("\\*(%d\n", ds);
+ printf(".lf %d\n", curfile->lineno+1);
+ if (curfile->lineno > n+3)
+ fprintf(stderr, "eqn warning: multi-line %c...%c, file %s:%d,%d\n",
+ lefteq, righteq, curfile->fname, n, curfile->lineno);
+ sfree(ds);
+ if (sz1) sfree(sz1);
+}
+
+void putout(int p1)
+{
+ double before, after;
+ extern double BeforeSub, AfterSub;
+
+ dprintf(".\tanswer <- S%d, h=%g,b=%g\n",p1, eht[p1], ebase[p1]);
+ eqnht = eht[p1];
+ before = eht[p1] - ebase[p1] - BeforeSub; /* leave room for sub or superscript */
+ after = ebase[p1] - AfterSub;
+ if (spaceval || before > 0.01 || after > 0.01) {
+ printf(".ds %d ", p1); /* used to be \\x'0' here: why? */
+ if (spaceval != NULL)
+ printf("\\x'0-%s'", spaceval);
+ else if (before > 0.01)
+ printf("\\x'0-%gm'", before);
+ printf("\\*(%d", p1);
+ if (spaceval == NULL && after > 0.01)
+ printf("\\x'%gm'", after);
+ putchar('\n');
+ }
+ if (szstack[0] != 0)
+ printf(".ds %d %s\\*(%d\\s\\n(99\n", p1, DPS(gsize,gsize), p1);
+ eqnreg = p1;
+ if (spaceval != NULL) {
+ free(spaceval);
+ spaceval = NULL;
+ }
+}
+
+void init(void)
+{
+ synerr = 0;
+ ct = 0;
+ ps = gsize;
+ ftp = ftstack;
+ ft = ftp->ft;
+ nszstack = 0;
+ if (szstack[0] != 0) /* absolute gsize in effect */
+ printf(".nr 99 \\n(.s\n");
+}
+
+salloc(void)
+{
+ int i;
+
+ for (i = 11; i < 100; i++)
+ if (used[i] == 0) {
+ used[i]++;
+ return(i);
+ }
+ ERROR "no eqn strings left (%d)", i FATAL;
+ return(0);
+}
+
+void sfree(int n)
+{
+ used[n] = 0;
+}
+
+void nrwid(int n1, int p, int n2)
+{
+ printf(".nr %d 0\\w'%s\\*(%d'\n", n1, DPS(gsize,p), n2); /* 0 defends against - width */
+}
+
+char *ABSPS(int dn) /* absolute size dn in printable form \sd or \s(dd (dd >= 40) */
+{
+ static char buf[100], *lb = buf;
+ char *p;
+
+ if (lb > buf + sizeof(buf) - 10)
+ lb = buf;
+ p = lb;
+ *lb++ = '\\';
+ *lb++ = 's';
+ if (dn >= 10) { /* \s(dd only works in new troff */
+ if (dn >= 40)
+ *lb++ = '(';
+ *lb++ = dn/10 + '0';
+ *lb++ = dn%10 + '0';
+ } else {
+ *lb++ = dn + '0';
+ }
+ *lb++ = '\0';
+ return p;
+}
+
+char *DPS(int f, int t) /* delta ps (t-f) in printable form \s+d or \s-d or \s+-(dd */
+{
+ static char buf[100], *lb = buf;
+ char *p;
+ int dn;
+
+ if (lb > buf + sizeof(buf) - 10)
+ lb = buf;
+ p = lb;
+ *lb++ = '\\';
+ *lb++ = 's';
+ dn = EFFPS(t) - EFFPS(f);
+ if (szstack[nszstack] != 0) /* absolute */
+ dn = EFFPS(t); /* should do proper \s(dd */
+ else if (dn >= 0)
+ *lb++ = '+';
+ else {
+ *lb++ = '-';
+ dn = -dn;
+ }
+ if (dn >= 10) { /* \s+(dd only works in new troff */
+ *lb++ = '(';
+ *lb++ = dn/10 + '0';
+ *lb++ = dn%10 + '0';
+ } else {
+ *lb++ = dn + '0';
+ }
+ *lb++ = '\0';
+ return p;
+}
+
+EFFPS(int n) /* effective value of n */
+{
+ if (n >= minsize)
+ return n;
+ else
+ return minsize;
+}
+
+double EM(double m, int ps) /* convert m to ems in gsize */
+{
+ m *= (double) EFFPS(ps) / gsize;
+ if (m <= 0.001 && m >= -0.001)
+ return 0;
+ else
+ return m;
+}
+
+double REL(double m, int ps) /* convert m to ems in ps */
+{
+ m *= (double) gsize / EFFPS(ps);
+ if (m <= 0.001 && m >= -0.001)
+ return 0;
+ else
+ return m;
+}
diff --git a/src/cmd/eqn/mark.c b/src/cmd/eqn/mark.c
new file mode 100644
index 00000000..f02e6779
--- /dev/null
+++ b/src/cmd/eqn/mark.c
@@ -0,0 +1,19 @@
+#include "e.h"
+
+void mark(int p1)
+{
+ markline = 1;
+ printf(".ds %d \\k(09\\*(%d\n", p1, p1);
+ yyval = p1;
+ dprintf(".\tmark %d\n", p1);
+}
+
+void lineup(int p1)
+{
+ markline = 2;
+ if (p1 == 0) {
+ yyval = salloc();
+ printf(".ds %d \\h'|\\n(09u'\n", yyval);
+ }
+ dprintf(".\tlineup %d\n", p1);
+}
diff --git a/src/cmd/eqn/matrix.c b/src/cmd/eqn/matrix.c
new file mode 100644
index 00000000..9df6cff2
--- /dev/null
+++ b/src/cmd/eqn/matrix.c
@@ -0,0 +1,78 @@
+#include "e.h"
+
+startcol(int type) /* mark start of column in lp[] array */
+{
+ int oct = ct;
+
+ lp[ct++] = type;
+ lp[ct++] = 0; /* count, to come */
+ lp[ct++] = 0; /* separation, to come */
+ return oct;
+}
+
+void column(int oct, int sep) /* remember end of column that started at lp[oct] */
+{
+ int i, type;
+
+ lp[oct+1] = ct - oct - 3;
+ lp[oct+2] = sep;
+ type = lp[oct];
+ if (dbg) {
+ printf(".\t%d column of", type);
+ for (i = oct+3; i < ct; i++ )
+ printf(" S%d", lp[i]);
+ printf(", rows=%d, sep=%d\n", lp[oct+1], lp[oct+2]);
+ }
+}
+
+void matrix(int oct) /* matrix is list of columns */
+{
+ int nrow, ncol, i, j, k, val[100];
+ double b, hb;
+ char *space;
+ extern char *Matspace;
+
+ space = Matspace; /* between columns of matrix */
+ nrow = lp[oct+1]; /* disaster if rows inconsistent */
+ /* also assumes just columns */
+ /* fix when add other things */
+ ncol = 0;
+ for (i = oct+1; i < ct; i += lp[i]+3 ) {
+ ncol++;
+ dprintf(".\tcolct=%d\n", lp[i]);
+ }
+ for (k=1; k <= nrow; k++) {
+ hb = b = 0;
+ j = oct + k + 2;
+ for (i=0; i < ncol; i++) {
+ hb = max(hb, eht[lp[j]]-ebase[lp[j]]);
+ b = max(b, ebase[lp[j]]);
+ j += nrow + 3;
+ }
+ dprintf(".\trow %d: b=%g, hb=%g\n", k, b, hb);
+ j = oct + k + 2;
+ for (i=0; i<ncol; i++) {
+ ebase[lp[j]] = b;
+ eht[lp[j]] = b + hb;
+ j += nrow + 3;
+ }
+ }
+ j = oct;
+ for (i=0; i<ncol; i++) {
+ pile(j);
+ val[i] = yyval;
+ j += nrow + 3;
+ }
+ yyval = salloc();
+ eht[yyval] = eht[val[0]];
+ ebase[yyval] = ebase[val[0]];
+ lfont[yyval] = rfont[yyval] = 0;
+ dprintf(".\tmatrix S%d: r=%d, c=%d, h=%g, b=%g\n",
+ yyval,nrow,ncol,eht[yyval],ebase[yyval]);
+ printf(".ds %d \"", yyval);
+ for( i=0; i<ncol; i++ ) {
+ printf("\\*(%d%s", val[i], i==ncol-1 ? "" : space);
+ sfree(val[i]);
+ }
+ printf("\n");
+}
diff --git a/src/cmd/eqn/mkfile b/src/cmd/eqn/mkfile
new file mode 100644
index 00000000..5f8e559c
--- /dev/null
+++ b/src/cmd/eqn/mkfile
@@ -0,0 +1,42 @@
+<$PLAN9/src/mkhdr
+
+TARG=eqn
+OFILES=main.$O\
+ tuning.$O\
+ diacrit.$O\
+ eqnbox.$O\
+ font.$O\
+ fromto.$O\
+ funny.$O\
+ glob.$O\
+ integral.$O\
+ input.$O\
+ lex.$O\
+ lookup.$O\
+ mark.$O\
+ matrix.$O\
+ move.$O\
+ over.$O\
+ paren.$O\
+ pile.$O\
+ shift.$O\
+ size.$O\
+ sqrt.$O\
+ text.$O\
+ eqn.$O\
+
+YFILES=eqn.y\
+
+HFILES=e.h\
+ y.tab.h\
+
+SHORTLIB=bio 9
+<$PLAN9/src/mkone
+
+YFLAGS=-d -S
+
+eqn.c: y.tab.c prevy.tab.h
+ mv y.tab.c $target
+
+prevy.tab.h: y.tab.h
+ sh -c 'cmp -s y.tab.h prevy.tab.h || cp y.tab.h prevy.tab.h'
diff --git a/src/cmd/eqn/move.c b/src/cmd/eqn/move.c
new file mode 100644
index 00000000..a622487c
--- /dev/null
+++ b/src/cmd/eqn/move.c
@@ -0,0 +1,19 @@
+# include "e.h"
+# include "y.tab.h"
+
+void move(int dir, int amt, int p)
+{
+ double a;
+
+ yyval = p;
+ a = EM(amt/100.0, ps);
+ printf(".ds %d ", yyval);
+ if (dir == FWD || dir == BACK)
+ printf("\\h'%s%gm'\\*(%d\n", (dir==BACK) ? "-" : "", a, p);
+ else if (dir == UP)
+ printf("\\v'-%gm'\\*(%d\\v'%gm'\n", a, p, a);
+ else if (dir == DOWN)
+ printf("\\v'%gm'\\*(%d\\v'-%gm'\n", a, p, a);
+ dprintf(".\tmove %d dir %d amt %g; h=%g b=%g\n",
+ p, dir, a, eht[yyval], ebase[yyval]);
+}
diff --git a/src/cmd/eqn/o.eqn b/src/cmd/eqn/o.eqn
new file mode 100755
index 00000000..61f93ddf
--- /dev/null
+++ b/src/cmd/eqn/o.eqn
Binary files differ
diff --git a/src/cmd/eqn/over.c b/src/cmd/eqn/over.c
new file mode 100644
index 00000000..2794a739
--- /dev/null
+++ b/src/cmd/eqn/over.c
@@ -0,0 +1,35 @@
+#include "e.h"
+
+void boverb(int p1, int p2)
+{
+ int treg;
+ double h, b, d, d1, d2;
+ extern double Overgap, Overwid, Overline;
+
+ treg = salloc();
+ yyval = p1;
+ d = EM(Overgap, ps);
+ h = eht[p1] + eht[p2] + d;
+ b = eht[p2] - d;
+ dprintf(".\tS%d <- %d over %d; b=%g, h=%g\n",
+ yyval, p1, p2, b, h);
+ nrwid(p1, ps, p1);
+ nrwid(p2, ps, p2);
+ printf(".nr %d \\n(%d\n", treg, p1);
+ printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", p2, treg, treg, p2);
+ printf(".nr %d \\n(%d+%gm\n", treg, treg, Overwid);
+ d2 = eht[p2]-ebase[p2]-d; /* denom */
+ printf(".ds %d \\v'%gm'\\h'\\n(%du-\\n(%du/2u'\\*(%d\\v'%gm'\\\n",
+ yyval, REL(d2,ps), treg, p2, p2, REL(-d2,ps));
+ d1 = 2 * d + ebase[p1]; /* num */
+ printf("\\h'-\\n(%du-\\n(%du/2u'\\v'%gm'\\*(%d\\v'%gm'\\\n",
+ p2, p1, REL(-d1,ps), p1, REL(d1,ps));
+ printf("\\h'-\\n(%du-\\n(%du/2u+%gm'\\v'%gm'\\l'\\n(%du-%gm'\\h'%gm'\\v'%gm'\n",
+ treg, p1, Overline, REL(-d,ps),
+ treg, 2*Overline, Overline, REL(d,ps));
+ ebase[yyval] = b;
+ eht[yyval] = h;
+ lfont[yyval] = rfont[yyval] = 0;
+ sfree(p2);
+ sfree(treg);
+}
diff --git a/src/cmd/eqn/paren.c b/src/cmd/eqn/paren.c
new file mode 100644
index 00000000..bb019bf7
--- /dev/null
+++ b/src/cmd/eqn/paren.c
@@ -0,0 +1,135 @@
+#include "e.h"
+
+#define abs(x) ((x) > 0 ? (x) : (-(x)))
+
+extern void brack(int, char *, char *, char *);
+
+void paren(int leftc, int p1, int rightc)
+{
+ int n, m, j;
+ double h1, b1;
+ double v, bv; /* v = shift of inside, bv = shift of brackets */
+ extern double Parenbase, Parenshift, Parenheight;
+
+ bv = ttype == DEVPOST ? Parenshift : 0; /* move brackets down this much */
+ h1 = eht[p1];
+ b1 = ebase[p1];
+ yyval = p1;
+ lfont[yyval] = rfont[yyval] = 0;
+ n = REL(h1,ps) + 0.99; /* ceiling */
+ if (n < 2)
+ n = 1;
+ m = n - 2;
+ if (leftc == '{' || rightc == '}') {
+ n = n%2 ? n : ++n;
+ if (n < 3)
+ n = 3;
+ m = n-3;
+ }
+ eht[yyval] = EM((double) n + Parenheight, ps);
+ ebase[yyval] = eht[yyval]/2 - EM(Parenbase, ps);
+
+ /* try to cope with things that are badly centered */
+ /* (top heavy or bottom heavy) */
+ if (abs(h1/2 - b1) >= EM(0.5, ps))
+ v = REL(-ebase[yyval] + (eht[yyval]-h1)/2 + b1, ps);
+ else
+ v = 0; /* don't shift it at all */
+
+ printf(".ds %d \\^", yyval); /* was \| */
+ if (bv)
+ printf("\\v'%gm'", bv);
+ switch (leftc) {
+ case 'n': /* nothing */
+ case '\0':
+ break;
+ case 'f': /* floor */
+ if (n <= 1)
+ printf("\\(lf");
+ else
+ brack(m, "\\(bv", "\\(bv", "\\(lf");
+ break;
+ case 'c': /* ceiling */
+ if (n <= 1)
+ printf("\\(lc");
+ else
+ brack(m, "\\(lc", "\\(bv", "\\(bv");
+ break;
+ case '{':
+ printf("\\b'\\(lt");
+ for(j = 0; j < m; j += 2) printf("\\(bv");
+ printf("\\(lk");
+ for(j = 0; j < m; j += 2) printf("\\(bv");
+ printf("\\(lb'");
+ break;
+ case '(':
+ brack(m, "\\(lt", "\\(bv", "\\(lb");
+ break;
+ case '[':
+ brack(m, "\\(lc", "\\(bv", "\\(lf");
+ break;
+ case '|':
+ brack(m, "|", "|", "|");
+ break;
+ default:
+ brack(m, (char *) &leftc, (char *) &leftc, (char *) &leftc);
+ break;
+ }
+ if (bv)
+ printf("\\v'%gm'", -bv);
+ if (v)
+ printf("\\v'%gm'\\*(%d\\v'%gm'", -v, p1, v);
+ else
+ printf("\\*(%d", p1);
+ if (rightc) {
+ if (bv)
+ printf("\\v'%gm'", bv);
+ switch (rightc) {
+ case 'f': /* floor */
+ if (n <= 1)
+ printf("\\(rf");
+ else
+ brack(m, "\\(bv", "\\(bv", "\\(rf");
+ break;
+ case 'c': /* ceiling */
+ if (n <= 1)
+ printf("\\(rc");
+ else
+ brack(m, "\\(rc", "\\(bv", "\\(bv");
+ break;
+ case '}':
+ printf("\\b'\\(rt");
+ for(j = 0; j < m; j += 2) printf("\\(bv");
+ printf("\\(rk");
+ for(j = 0; j < m; j += 2) printf("\\(bv");
+ printf("\\(rb'");
+ break;
+ case ']':
+ brack(m, "\\(rc", "\\(bv", "\\(rf");
+ break;
+ case ')':
+ brack(m, "\\(rt", "\\(bv", "\\(rb");
+ break;
+ case '|':
+ brack(m, "|", "|", "|");
+ break;
+ default:
+ brack(m, (char *) &rightc, (char *) &rightc, (char *) &rightc);
+ break;
+ }
+ if (bv)
+ printf("\\v'%gm'", -bv);
+ }
+ printf("\n");
+ dprintf(".\tcurly: h=%g b=%g n=%d v=%g l=%c, r=%c\n",
+ eht[yyval], ebase[yyval], n, v, leftc, rightc);
+}
+
+void brack(int m, char *t, char *c, char *b)
+{
+ int j;
+ printf("\\b'%s", t);
+ for( j=0; j < m; j++)
+ printf("%s", c);
+ printf("%s'", b);
+}
diff --git a/src/cmd/eqn/pile.c b/src/cmd/eqn/pile.c
new file mode 100644
index 00000000..a2d16239
--- /dev/null
+++ b/src/cmd/eqn/pile.c
@@ -0,0 +1,76 @@
+#include "e.h"
+#include "y.tab.h"
+
+void pile(int oct)
+{
+ int i, nlist, nlist2, mid;
+ double bi, h, b, gap, sb;
+ extern double Pilegap, Pilebase;
+ int type, p1, p2;
+
+ yyval = salloc();
+ type = lp[oct];
+ p1 = oct + 3; /* first entry */
+ p2 = p1 + lp[oct+1]; /* 1 after last */
+ gap = lp[oct+2];
+ if (gap != DEFGAP)
+ gap = EM(gap/100.0, ps);
+ else if (type == COL)
+ gap = 0;
+ else
+ gap = EM(Pilegap, ps); /* 0.4 m between LCOL, etc. */
+ nlist = p2 - p1;
+ nlist2 = (nlist+1)/2;
+ mid = p1 + nlist2 - 1;
+ h = 0;
+ for (i = p1; i < p2; i++)
+ h += eht[lp[i]];
+ eht[yyval] = h + (nlist-1)*gap;
+ b = 0;
+ for (i = p2-1; i > mid; i--)
+ b += eht[lp[i]] + gap;
+ ebase[yyval] = (nlist%2) ? b + ebase[lp[mid]]
+ : b - EM(Pilebase, ps) - gap;
+ if (dbg) {
+ printf(".\tS%d <- %d pile of:", yyval, type);
+ for (i = p1; i < p2; i++)
+ printf(" S%d", lp[i]);
+ printf("; h=%g b=%g\n", eht[yyval], ebase[yyval]);
+ }
+ nrwid(lp[p1], ps, lp[p1]);
+ printf(".nr %d \\n(%d\n", yyval, lp[p1]);
+ for (i = p1+1; i < p2; i++) {
+ nrwid(lp[i], ps, lp[i]);
+ printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n",
+ lp[i], yyval, yyval, lp[i]);
+ }
+ printf(".ds %d \\v'%gm'\\h'%du*\\n(%du'\\\n", yyval, REL(ebase[yyval],ps),
+ type==RCOL ? 1 : 0, yyval);
+ sb = 0; /* sum of box hts */
+ for (i = p2-1; i >= p1; i--) {
+ bi = sb + ebase[lp[i]];
+ switch (type) {
+ case LCOL:
+ printf("\\v'%gm'\\*(%d\\h'-\\n(%du'\\v'%gm'\\\n",
+ REL(-bi,ps), lp[i], lp[i], REL(bi,ps));
+ break;
+ case RCOL:
+ printf("\\v'%gm'\\h'-\\n(%du'\\*(%d\\v'%gm'\\\n",
+ REL(-bi,ps), lp[i], lp[i], REL(bi,ps));
+ break;
+ case CCOL:
+ case COL:
+ printf("\\v'%gm'\\h'\\n(%du-\\n(%du/2u'\\*(%d",
+ REL(-bi,ps), yyval, lp[i], lp[i]);
+ printf("\\h'-\\n(%du-\\n(%du/2u'\\v'%gm'\\\n",
+ yyval, lp[i], REL(bi,ps));
+ break;
+ }
+ sb += eht[lp[i]] + gap;
+ }
+ printf("\\v'%gm'\\h'%du*\\n(%du'\n", REL(-ebase[yyval],ps),
+ type!=RCOL ? 1 : 0, yyval);
+ for (i = p1; i < p2; i++)
+ sfree(lp[i]);
+ lfont[yyval] = rfont[yyval] = 0;
+}
diff --git a/src/cmd/eqn/prevy.tab.h b/src/cmd/eqn/prevy.tab.h
new file mode 100644
index 00000000..1f6d3c71
--- /dev/null
+++ b/src/cmd/eqn/prevy.tab.h
@@ -0,0 +1,57 @@
+#define CONTIG 57346
+#define QTEXT 57347
+#define SPACE 57348
+#define THIN 57349
+#define TAB 57350
+#define MATRIX 57351
+#define LCOL 57352
+#define CCOL 57353
+#define RCOL 57354
+#define COL 57355
+#define ABOVE 57356
+#define MARK 57357
+#define LINEUP 57358
+#define SUM 57359
+#define INT 57360
+#define PROD 57361
+#define UNION 57362
+#define INTER 57363
+#define DEFINE 57364
+#define TDEFINE 57365
+#define NDEFINE 57366
+#define DELIM 57367
+#define GSIZE 57368
+#define GFONT 57369
+#define INCLUDE 57370
+#define IFDEF 57371
+#define DOTEQ 57372
+#define DOTEN 57373
+#define FROM 57374
+#define TO 57375
+#define OVER 57376
+#define SQRT 57377
+#define SUP 57378
+#define SUB 57379
+#define SIZE 57380
+#define FONT 57381
+#define ROMAN 57382
+#define ITALIC 57383
+#define BOLD 57384
+#define FAT 57385
+#define UP 57386
+#define DOWN 57387
+#define BACK 57388
+#define FWD 57389
+#define LEFT 57390
+#define RIGHT 57391
+#define DOT 57392
+#define DOTDOT 57393
+#define HAT 57394
+#define TILDE 57395
+#define BAR 57396
+#define LOWBAR 57397
+#define HIGHBAR 57398
+#define UNDER 57399
+#define VEC 57400
+#define DYAD 57401
+#define UTILDE 57402
diff --git a/src/cmd/eqn/shift.c b/src/cmd/eqn/shift.c
new file mode 100644
index 00000000..dbac530b
--- /dev/null
+++ b/src/cmd/eqn/shift.c
@@ -0,0 +1,116 @@
+#include "e.h"
+#include "y.tab.h"
+
+void subsup(int p1, int p2, int p3)
+{
+ if (p2 != 0 && p3 != 0)
+ shift2(p1, p2, p3);
+ else if (p2 != 0)
+ bshiftb(p1, SUB, p2);
+ else if (p3 != 0)
+ bshiftb(p1, SUP, p3);
+}
+
+extern double Subbase, Supshift;
+extern char *Sub1space, *Sup1space, *Sub2space;
+extern char *SS1space, *SS2space;
+
+void bshiftb(int p1, int dir, int p2)
+{
+ int subps, n;
+ double shval, d1, h1, b1, h2, b2;
+ char *sh1, *sh2;
+
+ yyval = p1;
+ h1 = eht[p1];
+ b1 = ebase[p1];
+ h2 = eht[p2];
+ b2 = ebase[p2];
+ subps = ps;
+ ps += deltaps;
+ if (dir == SUB) {
+ /* base .2m below bottom of main box */
+ shval = b1 + EM(Subbase, ps);
+ ebase[yyval] = shval + b2;
+ eht[yyval] = max(h1-b1+shval+b2, h2);
+ if (rfont[p1] == ITAL && lfont[p2] == ROM)
+ n = 2; /* Sub1space */
+ else
+ n = max(2, class[rclass[p1]][lclass[p2]]);
+ sh1 = pad(n);
+ rclass[p1] = OTHER; /* OTHER leaves too much after sup */
+ } else { /* superscript */
+ /* 4/10 up main box */
+ d1 = EM(Subbase, subps);
+ ebase[yyval] = b1;
+ shval = -(Supshift * (h1-b1)) - b2;
+ if (Supshift*(h1-b1) + h2 < h1-b1) /* raise little super */
+ shval = -(h1-b1) + h2-b2 - d1;
+ eht[yyval] = h1 + max(0, h2 - (1-Supshift)*(h1-b1));
+ if (rclass[p1] == ILETF)
+ n = 4;
+ else if (rfont[p1] == ITAL)
+ n = 2; /* Sup1space */
+ else
+ n = max(1, class[rclass[p1]][lclass[p2]]);
+ sh1 = pad(n);
+ rclass[p1] = rclass[p2]; /* OTHER leaves too much after sup */
+ }
+ dprintf(".\tS%d <- %d shift %g %d; b=%g, h=%g, ps=%d, subps=%d\n",
+ yyval, p1, shval, p2, ebase[yyval], eht[yyval], ps, subps);
+ sh2 = Sub2space; /* was Sub2space; */
+ printf(".as %d \\v'%gm'%s%s\\*(%d%s%s\\v'%gm'\n",
+ yyval, REL(shval,ps), DPS(ps,subps), sh1, p2,
+ DPS(subps,ps), sh2, REL(-shval,ps));
+ rfont[p1] = 0;
+ sfree(p2);
+}
+
+void shift2(int p1, int p2, int p3)
+{
+ int subps;
+ double h1, h2, h3, b1, b2, b3, subsh, d2, supsh;
+ int treg;
+ char *sh2;
+
+ treg = salloc();
+ yyval = p1;
+ subps = ps; /* sub and sup at this size */
+ ps += deltaps; /* outer size */
+ h1 = eht[p1]; b1 = ebase[p1];
+ h2 = eht[p2]; b2 = ebase[p2];
+ h3 = eht[p3]; b3 = ebase[p3];
+ subsh = EM(Subbase, ps);
+ if (b1 > b2 + subsh) /* move little sub down */
+ subsh += b1;
+ eht[yyval] = max(subsh+b2-b1+h1, h2);
+ supsh = -Supshift*(h1-b1) - b3;
+ d2 = EM(Subbase, subps);
+ if (h3 < (1-Supshift)*(h1-b1))
+ supsh = -(h1-b1) + (h3-b3) - d2;
+ ebase[yyval] = subsh + b2 - b1;
+ eht[yyval] = h1 + subsh+b2-b1 + max(0, h3-(1-Supshift)*(h1-b1));
+ dprintf(".\tS%d <- %d sub %d sup %d, ps=%d, subps=%d, h=%g, b=%g\n",
+ yyval, p1, p2, p3, ps, subps, eht[yyval], ebase[yyval]);
+ if (rclass[p1] == ILETF)
+ sh2 = "\\|\\|";
+ else
+ sh2 = SS2space;
+ /*n = max(class[rclass[p1]][lclass[p2]], class[rclass[p1]][lclass[p3]]);
+ /*sh2 = pad(max(2, n));
+ */
+ printf(".ds %d %s\\*(%d\n", p2, SS1space, p2);
+ nrwid(p2, subps, p2);
+ printf(".ds %d %s\\*(%d\n", p3, sh2, p3);
+ nrwid(p3, subps, p3);
+ printf(".nr %d \\n(%d\n", treg, p3);
+ printf(".if \\n(%d>\\n(%d .nr %d \\n(%d\n", p2, treg, treg, p2);
+ printf(".as %d %s\\v'%gm'\\*(%d\\v'%gm'\\h'-\\n(%du'\\\n",
+ p1, DPS(ps,subps), REL(subsh,subps), p2, REL(-subsh,subps), p2);
+ printf("\\v'%gm'\\*(%d\\v'%gm'\\h'-\\n(%du+\\n(%du'%s%s\n",
+ REL(supsh,subps), p3, REL(-supsh,subps), p3, treg, DPS(subps,ps), Sub2space);
+ if (rfont[p2] == ITAL)
+ rfont[yyval] = 0; /* lie */
+ rclass[yyval] = rclass[p3]; /* was OTHER */
+ sfree(p2); sfree(p3); sfree(treg);
+}
diff --git a/src/cmd/eqn/size.c b/src/cmd/eqn/size.c
new file mode 100644
index 00000000..59bf3f20
--- /dev/null
+++ b/src/cmd/eqn/size.c
@@ -0,0 +1,70 @@
+#include "e.h"
+#include <ctype.h>
+
+void setsize(char *p) /* set size as found in p */
+{
+ nszstack++;
+ szstack[nszstack] = 0; /* assume relative */
+ if (*p == '+') {
+ ps += atoi(p+1);
+ if (szstack[nszstack-1] != 0) /* propagate absolute size */
+ szstack[nszstack] = ps;
+ } else if (*p == '-') {
+ ps -= atoi(p+1);
+ if (szstack[nszstack-1] != 0)
+ szstack[nszstack] = ps;
+ } else if (isdigit(*p)) {
+ if (szstack[nszstack-1] == 0)
+ printf(".nr %d \\n(.s\n", 99-nszstack);
+ else
+ printf(".nr %d %d\n", 99-nszstack, ps);
+ szstack[nszstack] = ps = atoi(p);
+ } else {
+ ERROR "illegal size %s ignored", p WARNING;
+ }
+ dprintf(".\tsetsize %s; ps = %d\n", p, ps);
+}
+
+void size(int p1, int p2)
+{
+ /* old size in p1, new in ps */
+ yyval = p2;
+ dprintf(".\tS%d <- \\s%d %d \\s%d; b=%g, h=%g\n",
+ yyval, ps, p2, p1, ebase[yyval], eht[yyval]);
+ if (szstack[nszstack] != 0) {
+ printf(".ds %d %s\\*(%d\\s\\n(%d\n", yyval, ABSPS(ps), p2, 99-nszstack);
+ } else
+ printf(".ds %d %s\\*(%d%s\n", yyval, DPS(p1,ps), p2, DPS(ps,p1));
+ nszstack--;
+ ps = p1;
+}
+
+void globsize(void)
+{
+ char temp[20];
+
+ getstr(temp, sizeof(temp));
+ if (temp[0] == '+') {
+ gsize += atoi(temp+1);
+ if (szstack[0] != 0)
+ szstack[0] = gsize;
+ } else if (temp[0] == '-') {
+ gsize -= atoi(temp+1);
+ if (szstack[0] != 0)
+ szstack[0] = gsize;
+ } else if (isdigit(temp[0])) {
+ gsize = atoi(temp);
+ szstack[0] = gsize;
+ printf(".nr 99 \\n(.s\n");
+ } else {
+ ERROR "illegal gsize %s ignored", temp WARNING;
+ }
+ yyval = eqnreg = 0;
+ ps = gsize;
+ if (gsize < 12 && !dps_set) /* sub and sup size change */
+ deltaps = gsize / 3;
+ else if (gsize < 20)
+ deltaps = gsize / 4;
+ else
+ deltaps = gsize / 5;
+}
diff --git a/src/cmd/eqn/sqrt.c b/src/cmd/eqn/sqrt.c
new file mode 100644
index 00000000..391d924e
--- /dev/null
+++ b/src/cmd/eqn/sqrt.c
@@ -0,0 +1,35 @@
+#include "e.h"
+
+void sqrt(int p2)
+{
+ static int af = 0;
+ int nps; /* point size for radical */
+ double radscale = 0.95;
+
+ if (ttype == DEVPOST)
+ radscale = 1.05;
+ nps = ps * radscale * eht[p2] / EM(1.0,ps) + 0.99; /* kludgy */
+ nps = max(EFFPS(nps), ps);
+ yyval = p2;
+ if (ttype == DEVCAT || ttype == DEVAPS)
+ eht[yyval] = EM(1.2, nps);
+ else if (ttype == DEVPOST)
+ eht[yyval] = EM(1.15, nps);
+ else /* DEV202, DEVPOST */
+ eht[yyval] = EM(1.15, nps);
+ dprintf(".\tS%d <- sqrt S%d;b=%g, h=%g, nps=%d\n",
+ yyval, p2, ebase[yyval], eht[yyval], nps);
+ printf(".as %d \\|\n", yyval);
+ nrwid(p2, ps, p2);
+ if (af++ == 0)
+ printf(".af 10 01\n"); /* make it two digits when it prints */
+ printf(".nr 10 %.3fu*\\n(.su/10\n", 9.2*eht[p2]); /* this nonsense */
+ /* guesses point size corresponding to height of stuff */
+ printf(".ds %d \\v'%gm'\\s(\\n(10", yyval, REL(ebase[p2],ps));
+ if (ttype == DEVCAT || ttype == DEVAPS)
+ printf("\\v'-.2m'\\(sr\\l'\\n(%du\\(rn'\\v'.2m'", p2);
+ else /* DEV202, DEVPOST so far */
+ printf("\\(sr\\l'\\n(%du\\(rn'", p2);
+ printf("\\s0\\v'%gm'\\h'-\\n(%du'\\^\\*(%d\n", REL(-ebase[p2],ps), p2, p2);
+ lfont[yyval] = rfont[yyval] = ROM;
+}
diff --git a/src/cmd/eqn/text.c b/src/cmd/eqn/text.c
new file mode 100644
index 00000000..261c7fbf
--- /dev/null
+++ b/src/cmd/eqn/text.c
@@ -0,0 +1,318 @@
+#include "e.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+#define CSSIZE 1000
+char cs[CSSIZE+20]; /* text string converted into this */
+char *csp; /* next spot in cs[] */
+char *psp; /* next character in input token */
+
+int lf, rf; /* temporary spots for left and right fonts */
+int lastft; /* last \f added */
+int nextft; /* next \f to be added */
+
+int pclass; /* class of previous character */
+int nclass; /* class of next character */
+
+int class[LAST][LAST] ={ /* guesswork, tuned to times roman postscript */
+
+ /*OT OL IL DG LP RP SL PL IF IJ VB */
+/*OT*/ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 0 }, /* OTHER */
+/*OL*/ { 1, 0, 1, 1, 1, 1, 1, 2, 2, 2, 0 }, /* OLET */
+/*IL*/ { 1, 1, 0, 1, 1, 1, 1, 3, 2, 1, 0 }, /* ILET */
+/*DG*/ { 1, 1, 1, 0, 1, 1, 1, 2, 2, 2, 0 }, /* DIG */
+/*LP*/ { 1, 1, 1, 1, 1, 2, 1, 2, 3, 3, 0 }, /* LPAR */
+/*RP*/ { 2, 2, 2, 1, 1, 1, 1, 2, 3, 3, 0 }, /* RPAR */
+/*SL*/ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0 }, /* SLASH */
+/*PL*/ { 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 0 }, /* PLUS */
+/*IF*/ { 3, 3, 1, 2, 2, 3, 2, 3, 0, 1, 1 }, /* ILETF */
+/*IJ*/ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0 }, /* ILETJ */
+/*VB*/ { 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 1 }, /* VBAR */
+
+};
+
+extern void shim(int, int);
+extern void roman(int);
+extern void sadd(char *);
+extern void cadd(int);
+extern int trans(int, char *);
+
+int textc(void) /* read next UTF rune from psp */
+{
+ wchar_t r;
+ int w;
+
+ w = mbtowc(&r, psp, 3);
+ if(w == 0){
+ psp++;
+ return 0;
+ }
+ if(w < 0){
+ psp += 1;
+ return 0x80; /* Plan 9-ism */
+ }
+ psp += w;
+ return r;
+}
+
+void text(int t, char *p1) /* convert text string p1 of type t */
+{
+ int c;
+ char *p;
+ tbl *tp;
+
+ yyval = salloc();
+ ebase[yyval] = 0;
+ eht[yyval] = EM(1.0, ps); /* ht in ems of orig size */
+ lfont[yyval] = rfont[yyval] = ROM;
+ lclass[yyval] = rclass[yyval] = OTHER;
+ if (t == QTEXT) {
+ for (p = p1; *p; p++) /* scan for embedded \f's */
+ if (*p == '\\' && *(p+1) == 'f')
+ break;
+ if (*p) /* if found \f, leave it alone and hope */
+ p = p1;
+ else {
+ sprintf(cs, "\\f%s%s\\fP", ftp->name, p1);
+ p = cs;
+ }
+ } else if (t == SPACE)
+ p = "\\ ";
+ else if (t == THIN)
+ p = "\\|";
+ else if (t == TAB)
+ p = "\\t";
+ else if ((tp = lookup(restbl, p1)) != NULL) {
+ p = tp->cval;
+ } else {
+ lf = rf = 0;
+ lastft = 0;
+ nclass = NONE; /* get started with no class == no pad */
+ csp = cs;
+ for (psp = p1; (c = textc()) != '\0'; ) {
+ nextft = ft;
+ pclass = nclass;
+ rf = trans(c, p1);
+ if (lf == 0) {
+ lf = rf; /* left stuff is first found */
+ lclass[yyval] = nclass;
+ }
+ if (csp-cs > CSSIZE)
+ ERROR "converted token %.25s... too long", p1 FATAL ;
+ }
+ sadd("\\fP");
+ *csp = '\0';
+ p = cs;
+ lfont[yyval] = lf;
+ rfont[yyval] = rf;
+ rclass[yyval] = nclass;
+ }
+ dprintf(".\t%dtext: S%d <- %s; b=%g,h=%g,lf=%c,rf=%c,ps=%d\n",
+ t, yyval, p, ebase[yyval], eht[yyval], lfont[yyval], rfont[yyval], ps);
+ printf(".ds %d \"%s\n", yyval, p);
+}
+
+int isalpharune(int c)
+{
+ return ('a'<=c && c<='z') || ('A'<=c && c<='Z');
+}
+
+int isdigitrune(int c)
+{
+ return ('0'<=c && c<='9');
+}
+
+trans(int c, char *p1)
+{
+ int f;
+
+ if (isalpharune(c) && ft == ITAL && c != 'f' && c != 'j') { /* italic letter */
+ shim(pclass, nclass = ILET);
+ cadd(c);
+ return ITAL;
+ }
+ if (isalpharune(c) && ft != ITAL) { /* other letter */
+ shim(pclass, nclass = OLET);
+ cadd(c);
+ return ROM;
+ }
+ if (isdigitrune(c)) {
+ shim(pclass, nclass = DIG);
+ roman(c);
+ return ROM; /* this is the right side font of this object */
+ }
+ f = ROM;
+ nclass = OTHER;
+ switch (c) {
+ case ':': case ';': case '!': case '%': case '?':
+ shim(pclass, nclass);
+ roman(c);
+ return f;
+ case '(': case '[':
+ shim(pclass, nclass = LPAR);
+ roman(c);
+ return f;
+ case ')': case ']':
+ shim(pclass, nclass = RPAR);
+ roman(c);
+ return f;
+ case ',':
+ shim(pclass, nclass = OTHER);
+ roman(c);
+ return f;
+ case '.':
+ if (rf == ROM)
+ roman(c);
+ else
+ cadd(c);
+ return f;
+ case '|': /* postscript needs help with default width! */
+ shim(pclass, nclass = VBAR);
+ sadd("\\v'.17m'\\z|\\v'-.17m'\\|"); /* and height */
+ return f;
+ case '=':
+ shim(pclass, nclass = PLUS);
+ sadd("\\(eq");
+ return f;
+ case '+':
+ shim(pclass, nclass = PLUS);
+ sadd("\\(pl");
+ return f;
+ case '>':
+ case '<': /* >, >=, >>, <, <-, <=, << */
+ shim(pclass, nclass = PLUS);
+ if (*psp == '=') {
+ sadd(c == '<' ? "\\(<=" : "\\(>=");
+ psp++;
+ } else if (c == '<' && *psp == '-') { /* <- only */
+ sadd("\\(<-");
+ psp++;
+ } else if (*psp == c) { /* << or >> */
+ cadd(c);
+ cadd(c);
+ psp++;
+ } else {
+ cadd(c);
+ }
+ return f;
+ case '-':
+ shim(pclass, nclass = PLUS); /* probably too big for ->'s */
+ if (*psp == '>') {
+ sadd("\\(->");
+ psp++;
+ } else {
+ sadd("\\(mi");
+ }
+ return f;
+ case '/':
+ shim(pclass, nclass = SLASH);
+ cadd('/');
+ return f;
+ case '~':
+ case ' ':
+ sadd("\\|\\|");
+ return f;
+ case '^':
+ sadd("\\|");
+ return f;
+ case '\\': /* troff - pass only \(xx without comment */
+ shim(pclass, nclass);
+ cadd('\\');
+ cadd(c = *psp++);
+ if (c == '(' && *psp && *(psp+1)) {
+ cadd(*psp++);
+ cadd(*psp++);
+ } else
+ fprintf(stderr, "eqn warning: unquoted troff command \\%c, file %s:%d\n",
+ c, curfile->fname, curfile->lineno);
+ return f;
+ case '\'':
+ shim(pclass, nclass);
+ sadd("\\(fm");
+ return f;
+
+ case 'f':
+ if (ft == ITAL) {
+ shim(pclass, nclass = ILETF);
+ cadd('f');
+ f = ITAL;
+ } else
+ cadd('f');
+ return f;
+ case 'j':
+ if (ft == ITAL) {
+ shim(pclass, nclass = ILETJ);
+ cadd('j');
+ f = ITAL;
+ } else
+ cadd('j');
+ return f;
+ default:
+ shim(pclass, nclass);
+ cadd(c);
+ return ft==ITAL ? ITAL : ROM;
+ }
+}
+
+char *pad(int n) /* return the padding as a string */
+{
+ static char buf[20];
+
+ buf[0] = 0;
+ if (n < 0) {
+ sprintf(buf, "\\h'-%du*\\w'\\^'u'", -n);
+ return buf;
+ }
+ for ( ; n > 1; n -= 2)
+ strcat(buf, "\\|");
+ if (n > 0)
+ strcat(buf, "\\^");
+ return buf;
+}
+
+void shim(int lc, int rc) /* add padding space suitable to left and right classes */
+{
+ sadd(pad(class[lc][rc]));
+}
+
+void roman(int c) /* add char c in "roman" font */
+{
+ nextft = ROM;
+ cadd(c);
+}
+
+void sadd(char *s) /* add string s to cs */
+{
+ while (*s)
+ cadd(*s++);
+}
+
+void cadd(int c) /* add character c to end of cs */
+{
+ char *p;
+ int w;
+
+ if (lastft != nextft) {
+ if (lastft != 0) {
+ *csp++ = '\\';
+ *csp++ = 'f';
+ *csp++ = 'P';
+ }
+ *csp++ = '\\';
+ *csp++ = 'f';
+ if (ftp == ftstack) { /* bottom level */
+ if (ftp->ft == ITAL) /* usual case */
+ *csp++ = nextft;
+ else /* gfont set, use it */
+ for (p = ftp->name; *csp = *p++; )
+ csp++;
+ } else { /* inside some kind of font ... */
+ for (p = ftp->name; *csp = *p++; )
+ csp++;
+ }
+ lastft = nextft;
+ }
+ w = wctomb(csp, c);
+ if(w > 0) /* ignore bad characters */
+ csp += w;
+}
diff --git a/src/cmd/eqn/tuning.c b/src/cmd/eqn/tuning.c
new file mode 100644
index 00000000..99718db3
--- /dev/null
+++ b/src/cmd/eqn/tuning.c
@@ -0,0 +1,153 @@
+#include "e.h"
+
+/*
+
+This file contains parameter values for many of the
+tuning parameters in eqn. Names are defined words.
+
+Strings are plugged in verbatim.
+Floats are usually in ems.
+
+*/
+
+/* In main.c: */
+
+double BeforeSub = 1.2; /* line space before a subscript */
+double AfterSub = 0.2; /* line space after a subscript */
+
+/* diacrit.c: */
+
+double Dvshift = 0.25; /* vertical shift for diacriticals on tall letters */
+double Dhshift = 0.025; /* horizontal shift for tall letters */
+double Dh2shift = 0.05; /* horizontal shift for small letters */
+double Dheight = 0.25; /* increment to height for diacriticals */
+double Barv = 0.68; /* vertical shift for bar */
+double Barh = 0.05; /* 1/2 horizontal shrink for bar */
+double Ubarv = 0.1; /* shift underbar up this much ems */
+double Ubarh = 0.05; /* 1/2 horizontal shrink for underbar */
+
+/* Also:
+ Vec, Dyad, Hat, Tilde, Dot, Dotdot, Utilde */
+
+/* eqnbox.c: */
+
+char *IRspace = "\\^"; /* space between italic & roman boxes */
+
+/* fat.c: */
+
+double Fatshift = 0.05; /* fattening shifts by Fatshift ems */
+
+/* funny.c: */
+
+int Funnyps = 5; /* point size change (== 5 above) */
+double Funnyht = 0.2; /* height correction */
+double Funnybase = 0.3; /* base correction */
+
+/* integral.c: */
+
+int Intps = 4; /* point size change for integral (== 4 above) */
+double Intht = 1.15; /* ht of integral in ems */
+double Intbase = 0.3; /* base in ems */
+double Int1h = 0.4; /* lower limit left */
+double Int1v = 0.2; /* lower limit down */
+double Int2h = 0.05; /* upper limit right was 8 */
+double Int2v = 0.1; /* upper limit up */
+
+/* matrix.c: */
+
+char *Matspace = "\\ \\ "; /* space between matrix columns */
+
+/* over.c: */
+
+double Overgap = 0.3; /* gap between num and denom */
+double Overwid = 0.5; /* extra width of box */
+double Overline = 0.1; /* extra length of fraction bar */
+
+/* paren.c* */
+
+double Parenbase = 0.4; /* shift of base for even count */
+double Parenshift = 0.13; /* how much to shift parens down in left ... */
+ /* ignored unless postscript */
+double Parenheight = 0.3; /* extra height above builtups */
+
+/* pile.c: */
+
+double Pilegap = 0.4; /* gap between pile elems */
+double Pilebase = 0.5; /* shift base of even # of piled elems */
+
+/* shift.c: */
+
+double Subbase = 0.2; /* subscript base belowe main base */
+double Supshift = 0.4; /* superscript .4 up main box */
+char *Sub1space = "\\|"; /* italic sub roman space */
+char *Sup1space = "\\|"; /* italic sup roman space */
+char *Sub2space = "\\^"; /* space after subscripted thing */
+char *SS1space = "\\^"; /* space before sub in x sub i sup j */
+char *SS2space = "\\^"; /* space before sup */
+
+/* sqrt.c: */
+ /* sqrt is hard! punt for now. */
+ /* part of the problem is that every typesetter does it differently */
+ /* and we have several typesetters to run. */
+
+/* text.c: */
+ /* ought to be done by a table */
+
+struct tune {
+ char *name;
+ char *cval;
+} tune[] ={
+ /* diacrit.c */
+ "vec_def", "\\f1\\v'-.5m'\\s-3\\(->\\s0\\v'.5m'\\fP", /* was \s-2 & .45m */
+ "dyad_def", "\\f1\\v'-.5m'\\s-3\\z\\(<-\\|\\(->\\s0\\v'.5m'\\fP",
+ "hat_def", "\\f1\\v'-.05m'\\s+1^\\s0\\v'.05m'\\fP", /* was .1 */
+ "tilde_def", "\\f1\\v'-.05m'\\s+1~\\s0\\v'.05m'\\fP",
+ "dot_def", "\\f1\\v'-.67m'.\\v'.67m'\\fP",
+ "dotdot_def", "\\f1\\v'-.67m'..\\v'.67m'\\fP",
+ "utilde_def", "\\f1\\v'1.0m'\\s+2~\\s-2\\v'-1.0m'\\fP",
+ /* funny.c */
+ "sum_def", "\\|\\v'.3m'\\s+5\\(*S\\s-5\\v'-.3m'\\|",
+ "union_def", "\\|\\v'.3m'\\s+5\\(cu\\s-5\\v'-.3m'\\|",
+ "inter_def", "\\|\\v'.3m'\\s+5\\(ca\\s-5\\v'-.3m'\\|",
+ "prod_def", "\\|\\v'.3m'\\s+5\\(*P\\s-5\\v'-.3m'\\|",
+ /* integral.c */
+ "int_def", "\\v'.1m'\\s+4\\(is\\s-4\\v'-.1m'",
+ 0, 0
+};
+
+tbl *ftunetbl[TBLSIZE]; /* user-defined names */
+
+char *ftunes[] ={ /* this table intentionally left small */
+ "Subbase",
+ "Supshift",
+ 0
+};
+
+void init_tune(void)
+{
+ int i;
+
+ for (i = 0; tune[i].name != NULL; i++)
+ install(deftbl, tune[i].name, tune[i].cval, 0);
+ for (i = 0; ftunes[i] != NULL; i++)
+ install(ftunetbl, ftunes[i], (char *) 0, 0);
+}
+
+#define eq(s, t) (strcmp(s,t) == 0)
+
+void ftune(char *s, char *t) /* brute force for now */
+{
+ double f = atof(t);
+ double *target;
+
+ while (*t == ' ' || *t == '\t')
+ t++;
+ if (eq(s, "Subbase"))
+ target = &Subbase;
+ else if (eq(s, "Supshift"))
+ target = &Supshift;
+ if (t[0] == '+' || t[0] == '-')
+ *target += f;
+ else
+ *target = f;
+}
diff --git a/src/cmd/eqn/y.tab.h b/src/cmd/eqn/y.tab.h
new file mode 100644
index 00000000..1f6d3c71
--- /dev/null
+++ b/src/cmd/eqn/y.tab.h
@@ -0,0 +1,57 @@
+#define CONTIG 57346
+#define QTEXT 57347
+#define SPACE 57348
+#define THIN 57349
+#define TAB 57350
+#define MATRIX 57351
+#define LCOL 57352
+#define CCOL 57353
+#define RCOL 57354
+#define COL 57355
+#define ABOVE 57356
+#define MARK 57357
+#define LINEUP 57358
+#define SUM 57359
+#define INT 57360
+#define PROD 57361
+#define UNION 57362
+#define INTER 57363
+#define DEFINE 57364
+#define TDEFINE 57365
+#define NDEFINE 57366
+#define DELIM 57367
+#define GSIZE 57368
+#define GFONT 57369
+#define INCLUDE 57370
+#define IFDEF 57371
+#define DOTEQ 57372
+#define DOTEN 57373
+#define FROM 57374
+#define TO 57375
+#define OVER 57376
+#define SQRT 57377
+#define SUP 57378
+#define SUB 57379
+#define SIZE 57380
+#define FONT 57381
+#define ROMAN 57382
+#define ITALIC 57383
+#define BOLD 57384
+#define FAT 57385
+#define UP 57386
+#define DOWN 57387
+#define BACK 57388
+#define FWD 57389
+#define LEFT 57390
+#define RIGHT 57391
+#define DOT 57392
+#define DOTDOT 57393
+#define HAT 57394
+#define TILDE 57395
+#define BAR 57396
+#define LOWBAR 57397
+#define HIGHBAR 57398
+#define UNDER 57399
+#define VEC 57400
+#define DYAD 57401
+#define UTILDE 57402