summaryrefslogtreecommitdiff
path: root/graphics/tree
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/tree
Initial commit
Diffstat (limited to 'graphics/tree')
-rw-r--r--graphics/tree/MANIFEST15
-rw-r--r--graphics/tree/Makefile.kit86
-rw-r--r--graphics/tree/README271
-rw-r--r--graphics/tree/mdoc.l93
-rw-r--r--graphics/tree/sample114
-rw-r--r--graphics/tree/tex.c670
-rw-r--r--graphics/tree/texsample228
-rw-r--r--graphics/tree/texsample.tex406
-rw-r--r--graphics/tree/tpar.l206
-rw-r--r--graphics/tree/tpsample106
-rw-r--r--graphics/tree/tree.1449
-rw-r--r--graphics/tree/tree.l1735
-rw-r--r--graphics/tree/unpar.l158
-rw-r--r--graphics/tree/use.raw740
14 files changed, 5277 insertions, 0 deletions
diff --git a/graphics/tree/MANIFEST b/graphics/tree/MANIFEST
new file mode 100644
index 0000000000..e3d7eea7a1
--- /dev/null
+++ b/graphics/tree/MANIFEST
@@ -0,0 +1,15 @@
+ File Name Archive # Description
+-----------------------------------------------------------
+ MANIFEST 1 this list of files
+ Makefile 1
+ README 1
+ mdoc.l 1 source code for mdoc (makes use.tre)
+ sample 1 sample to run tree on
+ tex.c 2 source code, #included in tree.l
+ texsample 1 sample to run tree on
+ tpar.l 1 source code for tpar
+ tpsample 1 sample to run tpar and tree on
+ tree.1 1 man page
+ tree.l 3 source code for tree
+ unpar.l 1 source code for unpar
+ use.raw 2 document (run mdoc & tree, then TeX)
diff --git a/graphics/tree/Makefile.kit b/graphics/tree/Makefile.kit
new file mode 100644
index 0000000000..2b3db369b0
--- /dev/null
+++ b/graphics/tree/Makefile.kit
@@ -0,0 +1,86 @@
+# Makefile for tree, June, 1990. Greg Lee
+
+#LEX =
+#LEXLIB = -ll
+# or if you don't have flex, use:
+LEX = lex
+LEXLIB = -ll
+
+INSTALL=install
+
+# Use flag -u or -t to make .tex files:
+UT = -u
+
+# Keyword required by PS driver at the begining of TeX
+# \specials to incorporate line of text directly in PS output
+# (see explanation at the beginning of tex.c). Default is
+# no keyword.
+#DEFS = -DSKEY=\"ps::\"
+#DEFS = -DSKEY=\"ps-string \"
+#DEFS = -DSKEY=\"ps-string=\"
+#DEFS = -DSKEY=\"pstext=\"
+DEFS =
+
+install: all
+ $(INSTALL) -o $(USER) -g $(GROUP) tree ${BIN}
+ $(INSTALL) -o $(USER) -g $(GROUP) tpar ${BIN}
+ $(INSTALL) -o $(USER) -g $(GROUP) unpar ${BIN}
+ $(INSTALL) -o $(USER) -g $(GROUP) tree.1 $(MAN)/man1
+
+all: tree tpar unpar
+
+tree: tree.l tex.c
+ $(LEX) tree.l
+ cc $(DEFS) -O -s -o tree lex.yy.c $(LEXLIB)
+ rm lex.yy.c
+
+tpar: tpar.l
+ $(LEX) tpar.l
+ cc -O -s -o tpar lex.yy.c $(LEXLIB)
+ rm lex.yy.c
+
+unpar: unpar.l
+ $(LEX) unpar.l
+ cc -O -s -o unpar lex.yy.c $(LEXLIB)
+ rm lex.yy.c
+
+mdoc: mdoc.l
+ $(LEX) mdoc.l
+ cc -O -s -o mdoc lex.yy.c $(LEXLIB)
+ @rm lex.yy.c
+
+use.tre: use.raw mdoc
+ rm -f use.tre
+ mdoc <use.raw >use.tre
+
+tex: sample.tex texsample.tex tpsample.tex use.tex
+
+sample.tex: sample tree
+ rm -f sample.tex
+ @echo '--- Expect a warning about an ill-formed \tree command ---'
+ tree $(UT) sample >sample.tex
+tpsample.tex: tpsample tree tpar
+ rm -f tpsample.tex
+ tpar -t tpsample |tree $(UT) >tpsample.tex
+texsample.tex: texsample tree
+ rm -f texsample.tex
+ tree $(UT) texsample >texsample.tex
+use.tex: use.tre tree
+ rm -f use.tex
+ @echo '--- Expect two warnings about discarded text ---'
+ tree $(UT) use.tre >use.tex
+
+shar:
+ makekit -m
+ mv Part01 tree.shar1
+ mv Part02 tree.shar2
+ mv Part03 tree.shar3
+
+DIST = MANIFEST Makefile README mdoc.l sample tex.c \
+ texsample tpar.l tpsample tree.1 tree.l unpar.l use.raw
+
+tar: $(DIST)
+ tar cf tree.tar $(DIST)
+
+clean:
+ rm -f *.aux *.dvi *.lof *.log *.toc *.blg *.bbl *.ilg *.ind *.idx lex.yy.c tree tpar unpar
diff --git a/graphics/tree/README b/graphics/tree/README
new file mode 100644
index 0000000000..72c0d15265
--- /dev/null
+++ b/graphics/tree/README
@@ -0,0 +1,271 @@
+
+Tree, a program for displaying trees.
+
+ Greg Lee, lee@uhccux.uhcc.hawaii.edu, 7/90
+
+
+ * *
+ Announcement
+ * ///////\\\\\\ *
+ / \
+ * Tree Drawing Program *
+ \ /
+ * \\\\\\\////// *
+ Available
+ * *
+
+The above is from the following tree-definition:
+
+ \tree -b9
+(
+(*(*\O(*\O(*\O(*\O)))))
+ ((Announcement\O(Available\I\O (Tree Drawing()) (\ \ \ \ Program()) ) ))
+(*(*\O(*\O(*\O(*\O)))))
+)
+
+
+The `tree' program formats trees for screen display or printing with
+TeX. The program, supporting utilities, and accompanying documents are
+free and in the public domain. If you distribute a modified version of
+`tree', please keep your version in the public domain.
+
+At the University of Hawaii, the tree program is available on the
+uhccux system in directory ~lingua/bin with source code and documents
+in directory ~lee/src/Tree. And in the Linguistics Department, the
+program is available on uhl2 in directory /usr/local/bin with source
+code and documents in ~greg/Tree.
+
+The predecessor program to this was written by Chris Barker, the
+Linguistics Board at University of California, Santa Cruz, email:
+barker@ling.ucsc.edu.
+
+This version has been tested only on Unix: SunOS 3.5, Ultrix 3.1, and
+SysV 3.50 (Unixpc). It requires the `lex' utility to compile, or else
+`flex', which is the free version of Unix `lex' by Vern Pacson. The
+Makefile is set up to use `flex'. To compile the source, type "make",
+which will process the source code with flex then will invoke the C
+compiler. This creates 3 programs: `tree', `tpar', and `unpar'. The
+last two are minor utilities that you may not have any need for; they
+are described below. Typing "make tex" compiles `mdoc' and uses that
+and `tree' and `tpar' to create some .tex files with examples and
+a document on the tree program.
+
+Basic usage for screen display is: "tree textfile", where the
+textfile has some trees. After you've made the program, try displaying
+the example files with:
+
+ % tree sample
+ % tree texsample
+
+The texsample file is intended to illustrate printed output using TeX,
+which you can get with the following (adapted for your local conventions
+for using TeX and printing):
+
+ % tree -t texsample > texsample.tex
+ % tex texsample
+ % lpr -d texsample.dvi
+
+And you can follow the similar procedure for the file sample. This
+should get you printout of trees done with horizontal and vertical
+lines. If you have a PostScript printer, the following may work to get
+trees made with slanty lines:
+
+ % tree -u texsample > texsample.tex
+ % tex texsample
+ % lpr -d texsample.dvi
+
+That is, everything the same, except use `-u' instead of `-t'. (`-t' is
+for TeX; the only logic to the `-u' is that `u' comes after `t'.) If
+this last doesn't work right, the most likely thing to have gone wrong
+is that your local PostScript driver program does not treat TeX \special
+commands, which I've used to embed PS code, in the same way that mine
+does. If that's a problem, there are two things you can do about it.
+(1) Find out what should be in a TeX \special to tell your driver to
+just spit out literally into its output whatever it finds in a \special,
+then modify the Makefile or the C code in the source tex.c accordingly
+(see `SKEY' in the code), or (2) email me and I'll send you my PS driver
+program (which is a modification of the free dvi2ps program from MIT).
+
+The Makefile also provides for "make tex" to create TeXable files
+use.tex, sample.tex, texsample.tex, and ptsample.tex for a sort of user
+manual and some sample output. If you can't get the `-u' option to
+work, you can change the definition of UT in the Makefile to -t.
+
+Tree has some options for modifying or decorating trees in various ways.
+Some of these can be used either for all the trees in a source text file
+by giving the option on the command line after `tree', or for some
+individual tree by giving the option after the `\tree' command within
+the text file. For instance, if the text has
+
+ \tree -t (S (Q (did) (V' (you go))))
+
+then TeX code will be generated for this particular tree in the text,
+but not necessarily for other trees in that text file. Here is another
+example:
+
+ % tree -L < filename
+ \tree -L (S(NP(N(features)))(V'(V(galore))))
+
+The first Unix command will have `tree' omit all connecting lines under
+nodes for all trees in the file `filename'. The second, as a line in a
+text file processed by tree, will do that for just the one tree that
+follows. There are other options that apply just to single nodes within
+a tree, which are given as backslash plus some capital letter. As it
+happens, in this instance there is an option \L for individual nodes,
+also:
+
+ \tree (S(NP(N\L(features)))(V'(\L V(galore))))
+
+which omits lines under just the two nodes `N' and `V'. The second \L
+in this example has to be separated by a space from the following V so
+`tree' can tell that this is not a TeX command with the name `LV'. (If
+it happens that you need to use a TeX command with the name `L' in a
+node, you could use \\L for this, but it is necessary to use \\ for
+TeX commands only in such cases of conflict.)
+
+Here is a reference list of the options or commands for formatting
+individual nodes. (See the man page and the "use" document for more
+info.) In this list, `<d>' is an optional single digit argument, and
+`<n>' is an obligatory non-negative integer argument.
+
+ Command: Option: Function:
+
+ \D<d> "daughter" label discontinuous daughter
+ \E "even" -E select basis for flatten command
+ \F "flatten" -F move nodes to lowest level
+ \H "head" center mother over this daughter
+ \I "invert" -I turn tree upside down
+ \L "lexical" -L don't put lines under nodes
+ \M<d> "mother" label mother of discontinuous daughter
+ \O "omit" -O omit line above nodes
+ \P "phantom" as "omit" but retain spacing
+ \T "triangle" -T put triangles under nodes
+ \R "relational" -R put aligned verticals at right of nodes
+ \B<d> "boldness" -b<n> do shaded triangles or bold lines (see below)
+ -g<n> use n as the minimal gap between nodes
+ -v don't suppress TeX commands on screen
+ -q suppress warnings
+
+All commands of the form backslash plus capital letter `tree' assumes
+are intended for it, and it eats them up without comment, even though
+in most cases they don't do anything.
+
+The option `-b<n>' has different effects depending on output is
+tty-style or TeX code. The sample files have examples for the latter.
+For tty output, here is a series of trees showing how the connecting
+"lines" can be varied. These are from the tree definition:
+
+ \tree (bold =<n>(family\T(Martha Henry))(uncle)(aunt)(kin(Fred)(Milly\H)))
+
+with values from 0 through 9 for <n> and with option `-b<n>':
+
+ bold =0
+ ____________|____________
+ | | | |
+ family uncle aunt kin
+ _____|______ _______|
+ |__________| | |
+ Martha Henry Fred Milly
+ bold =1
+ +-----------+-----------+
+ | | | |
+ family uncle aunt kin
+ +----+-----+ -------|
+ |----------| | |
+ Martha Henry Fred Milly
+ bold =2
+ ...........:...........
+ : : : :
+ family uncle aunt kin
+ ....:..... .......:
+ :::::::::::: : :
+ Martha Henry Fred Milly
+ bold =3
+ |||||||||||||||||||||||||
+ | | | |
+ family uncle aunt kin
+ |||||||||||| ||||||||
+ |||||||||||| | |
+ Martha Henry Fred Milly
+ bold =4
+ :::::::::::::::::::::::::
+ : : : :
+ family uncle aunt kin
+ :::::::::::: ::::::::
+ :::::::::::: : :
+ Martha Henry Fred Milly
+ bold =5
+ ........../ \..........
+ / : : \
+ family uncle aunt kin
+ ..../\.... .......:
+ :::::::::::: / *
+ Martha Henry Fred Milly
+ bold =6
+ __________/ \__________
+ / | | \
+ family uncle aunt kin
+ ____/\____ _______|
+ |||||||||||| / *
+ Martha Henry Fred Milly
+ bold =7
+ <<<<<<<<<<< >>>>>>>>>>>
+ / | | \
+ family uncle aunt kin
+ <<<<<>>>>> <<<<<<<|
+ |----------| / *
+ Martha Henry Fred Milly
+ bold =8
+ ////////////\\\\\\\\\\\
+ / | | \
+ family uncle aunt kin
+ /////\\\\\ ///////|
+ |||||||||||| / *
+ Martha Henry Fred Milly
+ bold =9
+ ////////////\\\\\\\\\\\
+ / | | \
+ family uncle aunt kin
+ /////\\\\\ ///////|
+ |**********| / *
+ Martha Henry Fred Milly
+
+The \B<d> command selects the different styles on a node-by-node
+basis, affecting the lines just below the node with the command.
+\B without argument is the same as \B9.
+
+The utilities `tpar' and `unpar' are for trees using indentation
+for indicating structure rather than parenthesization. For instance,
+feed this to `tpar':
+
+ \tree
+ S
+ NP
+ Det\L - the
+ N - rain
+ VP - V - falls
+
+to get back a parenthesized version that you can give to `tree':
+
+ \tree
+ (S
+ (NP
+ (Det\L(the))
+ (N(rain)))
+ (VP(V(falls))))
+
+With the option `-v', `tpar' will put some ending parens on new lines,
+and with the option `-t' it will turn bracketed digits and i,j,k,x,y,z
+into the TeX code for subscripting the digit or letter, and also
+translate N',A',V',P' into TeX code for putting bars over the letters.
+The `unpar' utility translates the other way, substituting indentation
+for parenthesization and, with the `-t' option, going back to the
+bracket and prime notation from the TeX code. The file tpsample has
+example trees in indented form.
+
+Bug reports and suggestions for changes are welcome.
+
+Greg Lee
+U.S.mail: 562 Moore Hall, Dept. of Linguistics, Univ. of Hawaii, HONO, HI 96822
+INTERNET: lee@uhccux.uhcc.hawaii.edu
+BITNET: lee@uhccux
diff --git a/graphics/tree/mdoc.l b/graphics/tree/mdoc.l
new file mode 100644
index 0000000000..afe9a31cdd
--- /dev/null
+++ b/graphics/tree/mdoc.l
@@ -0,0 +1,93 @@
+%{
+/* mdoc: utility to add \tree examples to "use" document for tree
+ * Greg Lee, July 1990
+ */
+char *buf, *bufp;
+char *line[100];
+int count = 0, last = 0, i;
+#define ADDCH(c) *bufp++ = c
+#define ADDS(s) strcpy(bufp,s); bufp += yyleng
+%}
+
+%s X
+
+%%
+
+^"\\xtwo"[ \t\n]+ {
+ ECHO;
+ last = 2;
+ line[0] = bufp;
+ BEGIN(X);
+}
+
+^"\\xthree"[ \t\n]+ {
+ ECHO;
+ last = 3;
+ line[0] = bufp;
+ BEGIN(X);
+}
+
+^"\\xfour"[ \t\n]+ {
+ ECHO;
+ last = 4;
+ line[0] = bufp;
+ BEGIN(X);
+}
+
+^"\\x"[ \t\n]+ {
+ ECHO;
+ last = 1;
+ line[0] = bufp;
+ BEGIN(X);
+}
+<X>"$" {
+ printf("\\$");
+ ADDCH('$');
+}
+<X>"\\ " {
+ printf("\\xbs{\\ }");
+ ADDS(yytext);
+}
+<X>\\[a-z]+ {
+ printf("\\xbs{%s}", yytext+1);
+ ADDS(yytext);
+}
+<X>\\. {
+ printf("\\xbs{%c}", yytext[1]);
+ ADDS(yytext);
+}
+<X>: {
+ ECHO;
+ ADDCH(0);
+ count++;
+ line[count] = bufp;
+}
+<X>"." {
+ ECHO;
+ if (count < last) ADDCH('.');
+ else {
+ ADDCH(0);
+
+ printf("\n\\smallbreak{\\parindent=.5in\\par");
+ printf("\\hskip-.2in\\it gives:\\tfont\n\\tree ");
+ for (i = 0; i < count; i++)
+ printf("%s\n", line[i]);
+ printf("}\\smallbreak\n");
+
+ count = last = 0;
+ bufp = buf;
+ BEGIN(0);
+ }
+}
+<X>. {
+ ECHO;
+ ADDCH(yytext[0]);
+}
+
+%%
+main()
+{ char *malloc();
+
+ buf = bufp = malloc(BUFSIZ);
+ yylex();
+}
diff --git a/graphics/tree/sample b/graphics/tree/sample
new file mode 100644
index 0000000000..77723a2523
--- /dev/null
+++ b/graphics/tree/sample
@@ -0,0 +1,114 @@
+
+Here are some example trees to display with the tree program. First,
+the examples from the man page:
+
+ (ex1) \tree (S(NP(John))(VP(runs)))
+
+ (ex2) \tree ((((John)(runs))))
+
+%(ex3) \tree \- this line will remain unchanged
+
+ (ex4) is not given, since it has an error
+
+ (ex5) \tree -q (a phrase composed of others(a phrase
+ (a)(phrase))
+ This is a comment.(composed) (of others
+ (of)(others)) )
+
+ (ex6) \tree ((S(John)(V(runs)(fast))) (==$>$)
+ (S(V(runs)(fast))(S(John)(does))))
+
+ (ex7) \tree (S % Comments like this
+ (NP % are skipped over.
+ (John)
+ )
+ (VP
+ (runs)
+ )
+ )
+
+ (ex8) \tree (NP (Det(John's \(genitive\)))
+ (N\([+count]\)(legs)) )
+
+ (ex9) \tree (\T S (every) (good boy)
+ (VP (\L V(does)) (\L A(fine)) ))
+
+ (ex10) \tree (S(PP\O\D(near)(him))(NP(John))
+ (VP\M(saw)(a snake)))
+
+Then here are a couple of trees from the sample file Jeff Goldberg
+distributed:
+
+(1) \tree
+(S (NP[+WH] (Who))
+ (S/NP (V[INV] (did))
+ (NP (you))
+ (VP[BSE]/NP (V[BSE] (see))
+ (NP[NULL]/NP (e))
+ )
+ )
+)
+
+(2) \tree
+(S (PP (P1 (P (on))
+ (NP (which)
+ (N1 (N (table)))
+ )
+ )
+ )
+ (S/PP (V (do))
+ (NP (you))
+ (VP/PP (V (think))
+ (S/PP (NP (Martha))
+ (VP/PP (V (believes))
+ (S/PP (NP (Irving))
+ (VP/PP (V (put)) (NP (Det (the) (N1 (N (book)))))
+ (PP/PP (e))
+ )
+ )
+ )
+ )
+ )
+ )
+)
+
+Chris Barker gave these examples (in a slightly different
+form):
+
+ \tree
+((S (NP (N) (PP (P) (NP)))
+ (VP (V) (PP (P) (NP))))
+
+ (\I S (\I NP (N) (\I PP (P) (NP)))
+ (VP (V) (\I PP (P) (NP)))))
+
+ \tree
+(\I\(mutakaatib\)\L
+ (u
+ (u ((C\O)(V)(C\O)))
+ (a (V) (C\O)
+ (V)
+ (V))
+(i ((C\O)(V)(C\O))))
+ )
+
+ \tree
+( (C
+ (u\I
+ (m)
+ (\O) % leave space below first `V' in upper tree
+ (g)
+ (n)
+ (\O) % leave space below second `V' in upper tree
+ (t)
+ )
+ )
+ (V)
+ (C ()) % empty node attaches to `g'
+ (C ()) % empty node attaches to `n'
+ (V)
+ (C ()) % empty node attaches to `t'
+ ((\O(s\O)))
+)
+
+\bye
diff --git a/graphics/tree/tex.c b/graphics/tree/tex.c
new file mode 100644
index 0000000000..10234f6e25
--- /dev/null
+++ b/graphics/tree/tex.c
@@ -0,0 +1,670 @@
+
+
+/*
+ * With the -u option, TeX \special commands are used to include
+ * PostScript commands into the PS file created by the PS driver
+ * (dvi2ps, psdvi, dvips, dvitops, or whatever). The driver should
+ * not attempt repositioning or anything -- just copy to its output.
+ * Some drivers may not be willing to do this, and others may need
+ * the \special to begin with a certain keyword before they will do it.
+ * Here is a list of those keywords I know about:
+ * "ps-string "
+ * "ps-string="
+ * "ps::"
+ * "pstext="
+ * The following define is for this keyword; it might have to be set
+ * to one of the above. (My version of dvi2ps does not require a
+ * keyword.)
+ */
+#ifndef SKEY
+#define SKEY "ps::"
+#endif
+
+/*
+ * Dimensions are in terms of em and ex (of the current font), with
+ * basic values assuming cmr 10, which has 1em = 10pt, 1ex = 4.31pt.
+ *
+ * Each character or space is reckoned to be 1/2 em, which is the
+ * width of a digit in the cmr fonts. However, each `col' unit in
+ * the tree is a half-space wide -- 1/4 em, that is.
+ *
+ * The normal width of rules is .4pt, which becomes .04em.
+ * The height of lines is that of a TeX \strut: 8.5pt above the
+ * baseline and 3.5pt below, and in ex units:
+ * 8.5pt/4.31=1.972ex
+ * 3.5pt/4.31=0.81206ex
+ * The horizontal bars made of "underlines" have vertical dimension
+ * starting 3.5pt below the baseline and going up .4pt to:
+ * 3.1pt/4.31=0.71925ex
+ * The ones made of "overlines" go to 8.5pt and start .4pt lower:
+ * 8.1pt/4.31=1.87935ex
+ * Rule width is .4pt/4.31 = .09280742ex.
+ */
+
+float hskip = 0; /* amount to hskip before next box or bar */
+
+dohskip () {
+ /* must emit this even when hskip is 0 to get out of
+ * vertical mode before an \hbox
+ */
+ printf ("\\hskip %.2fem", hskip);
+ hskip = 0;
+}
+
+/* record keeping for lines connecting discontinuous constituents */
+int m_ulabel[11];
+int d_ulabel[11];
+
+/*
+ * Keep track of the attributes from the \M and \D label
+ * commands. For the first of a matching pair, save our treeid
+ * in the ulabel array and issue PS commands to define the current
+ * (x,y) coordinates with names corresponding to the treeid. For
+ * the second of a matching pair, issue PS commands to draw a
+ * line back to the previous location.
+ */
+setiattrib(node, is_daughter)
+TREE node;
+int *is_daughter;
+{
+ int type = node->type;
+ int iattrib = 0;
+
+ if (type == VBAR && (iattrib = has(node,'D')) ) {
+ /* this is a daughter label */
+ *is_daughter = TRUE;
+ /* ... unless we're in an inverted tree */
+ /*if (node->mother && node->mother->type == OBAR)*/
+ if (has(node,'U') == 'i')
+ *is_daughter = FALSE;
+ if (iattrib == '+') iattrib = 10;
+ else iattrib -= '0';
+ d_ulabel[iattrib] = node->treeid;
+ /* if known already, get old treeid in iattrib, otherwise
+ * note with "-1" that current location must be defined
+ */
+ if (m_ulabel[iattrib]) iattrib = m_ulabel[iattrib];
+ else iattrib = -1;
+ }
+ else if ((type==HBAR || type==VBAR || type==OBAR)
+ && (iattrib = has(node,'M'))) {
+ /* this is a mother label */
+ *is_daughter = FALSE;
+ /* ... unless we're an OBAR: */
+ if (type == OBAR) *is_daughter = TRUE;
+ if (type == VBAR && has(node,'U') == 'i') *is_daughter = TRUE;
+ if (iattrib == '+') iattrib = 10;
+ else iattrib -= '0';
+ m_ulabel[iattrib] = node->treeid;
+ if (d_ulabel[iattrib]) iattrib = d_ulabel[iattrib];
+ else iattrib = -1;
+ }
+
+ if (debug_opt) printf("%% note iattrib %d\n", iattrib);
+
+ return(iattrib);
+}
+
+
+
+/* TeX height and depth to be used in current line for strut, etc. */
+float h, d;
+/* used only in following routine, except also set in print_tex_tree */
+int curr_row = -1;
+/* look at entire row to see what the smallest height and depth we can
+ * get away with are
+ */
+static
+ set_hd (node)
+ TREE node;
+{ int row_type = 0;
+ int top_row = node->row;
+
+ if (top_row == curr_row) return;
+ curr_row = top_row;
+ while (node && (node->row == top_row)) {
+ row_type |= node->type;
+ node = node->right;
+ }
+ if (row_type & NODENAME) {
+ if (debug_opt) printf("%% Next row needs a full size strut.\n");
+ h = 1.972;
+ d = .812;
+ }
+ else {
+ /* Make rows without text for node names about 2/3 of normal size.
+ */
+ if (debug_opt) printf("%% Setting height + depth to 2 ex's.\n");
+ h = 1.5;
+ d = .5;
+ }
+}
+
+
+/* Generate PS code for Bezier curve connecting discontinuous
+ * constituents (needs work). This has to be independent of scale
+ * or translation of coordinate system, since the PS driver may
+ * have changed these.
+ */
+curvegen(sf, is_daughter)
+char *sf;
+int is_daughter;
+{
+ if (is_daughter) printf("\\lower%1.3fex",d);
+ else printf("\\raise%1.3fex",h);
+
+ printf("\\hbox{\\special{%scurrentpoint ",SKEY);
+
+ /* Daughter is at, say, (DX,DY) and mother at (MX,MY);
+ * if we're now at the daughter, we need to calculate two
+ * inflexion points, somehow. (Even though the PS variable
+ * is called "mom", if we're at a mother node, it's actually
+ * a daughter.)
+ */
+ if (is_daughter) {
+ printf("currentpoint pop mom%sy ",sf); /* (DX,MY) */
+ printf("mom%sx currentpoint exch pop ",sf); /* (MX, (DY+MY)/2 ) */
+ printf("mom%sy add 2 div ",sf);
+ }
+ else {
+ /* We're at the mother, and the first inflexion point has to bend
+ * us down, then the second has be up above the daughter so we hit
+ * it going more or less downward.
+ */
+/* cpx */
+ printf("currentpoint pop ");
+/* cpy 2 mul dy sub */
+ printf("currentpoint exch pop 2 mul mom%sy sub ",sf);
+ /* (MX, MY*2 - DY) */
+/* dx */
+ printf("mom%sx ",sf);
+/* dy 2 mul cpy sub */
+ printf("mom%sy 2 mul currentpoint exch pop sub ",sf);
+ /* (DX, DY*2 - MY) */
+/* dx dy */
+ }
+ /* and wind up at (DX,DY) or (MX,MY) */
+ printf("mom%sx mom%sy curveto stroke ",sf,sf);
+
+ printf("moveto}}%%\n");
+}
+
+char m[4], n[4];
+/* m and n are suffixes for PS identifiers initialized here for
+ * later use. m is for local lines; n is for discontinuous
+ * constituent lines requested through labels
+ */
+setsuffix(s, id)
+char *s;
+int id;
+{
+ s[0] = 'a'; s[1] = 'a'; s[2] = 'a'; s[3] = '\0';
+ s[0] += id / (26*26);
+ s[1] += (id / 26) % 26;
+ s[2] += id % 26;
+}
+
+char *whichbar[] = {
+ "",
+ "\\big\\Vert",
+ "\\big\\downarrow",
+ "\\big\\Downarrow",
+ "\\big\\uparrow",
+ "\\big\\Uparrow",
+ "\\big\\updownarrow",
+ "\\diamondsuit",
+ "\\triangle",
+ ""
+};
+char *whichobar[] = {
+ "",
+ "\\big\\Vert",
+ "\\big\\uparrow",
+ "\\big\\Uparrow",
+ "\\big\\downarrow",
+ "\\big\\Downarrow",
+ "\\big\\updownarrow",
+ "\\diamondsuit",
+ "\\nabla",
+ ""
+};
+
+int greyness;
+
+ /* The vertical bars start horizontally half way through a
+ * character space and go .4pt further to the right. For the
+ * -u option, issue PS to draw a line to the previously defined
+ * position under the node name above. (For upside down trees,
+ * the position over the node name below is unfortunately not yet
+ * defined -- haven't figured out what to do about that -- not
+ * sure I care enough.)
+ */
+texvbar(node, iattrib, r, is_daughter)
+TREE node;
+int iattrib, is_daughter;
+float r;
+{ TREE mom = node->mother;
+ int do_a_line = FALSE,
+ do_a_bar = FALSE,
+ do_a_tbar = FALSE,
+ do_nothing = FALSE,
+ def_a_sister = FALSE,
+ def_an_osister = FALSE,
+ def_a_mother = FALSE,
+ do_a_triangle = FALSE,
+ do_a_box = FALSE,
+ do_an_obox = FALSE;
+
+ do_a_line = (utex_opt && mom && mom->type == HBAR);
+ if (mom && mom->row > node->row) do_a_line = FALSE;
+
+ def_an_osister = (!has(node,'O') && utex_opt
+ && mom && mom->type == OBAR);
+ if (def_an_osister) {
+ def_a_sister = TRUE;
+ if (has(node,'S') == 'f' || has(node,'S') == 'o')
+ mom->left = node;
+ if (has(node,'S') == 'o') def_a_mother = TRUE;
+ }
+
+ if (do_a_line && has(node,'T') && !has(node,'B')) {
+ if (has(node,'S') == 'f' || has(node,'S') == 'o')
+ def_a_sister = TRUE;
+ if (has(node,'S') == 'o' || has(node,'S') == 'l')
+ do_a_triangle = TRUE;
+ if (!do_a_triangle && !def_a_sister) do_nothing = TRUE;
+ }
+
+ if (has(node,'O') || has(node,'P')) do_nothing = TRUE;
+ if (iattrib && utex_opt) do_nothing = FALSE;
+ if (utex_opt && iattrib == -1) def_a_mother = TRUE;
+ do_a_bar = (!do_a_line && !do_nothing && !def_an_osister);
+ if (has(node,'B')) do_a_bar = TRUE;
+ if (do_a_bar && has(node,'T')) {
+ if (has(node,'S') == 'f' || has(node,'S') == 'o') {
+ if (mom && mom->type == OBAR) do_an_obox = TRUE;
+ /*else if (mom && node == mom->daughter) do_a_box = TRUE;*/
+ else /*if (mom && node == mom->daughter)*/ do_a_box = TRUE;
+ do_nothing = TRUE;
+ }
+ else do_nothing = TRUE;
+ }
+ if (has(node,'O') || has(node,'P')) do_a_bar = FALSE;
+ if (do_a_bar && (!utex_opt || has(node,'B')) && whichbar[b][0]) {
+ do_a_tbar = TRUE;
+ do_a_bar = FALSE;
+ }
+
+ hskip += .25;
+
+ if (do_a_box || do_an_obox) {
+ TREE first = node, last;
+ int len;
+ while (node->sister
+ && node->mother == node->sister->mother
+ && has(node,'S') != 'l'
+ && has(node,'S') != 'o'
+ && node->sister->type == VBAR) {
+ node->mother = NULL;
+ node = node->sister;
+ }
+ last = node;
+ last->mother = NULL;
+ if (first != last) {
+ len = last->col + last->l - first->col;
+ r = len;
+ r /= COLMUL;
+ }
+ dohskip();
+ printf ("\\vrule width.04em");
+ hskip -= .04;
+ if (greyness) {
+ printf ("\\xleaders\\hbox to .%dem{\\hss$\\",
+ greyness);
+ if (do_a_box) printf("Down");
+ else printf("Up");
+ printf ("arrow$\\hss}\\hskip%.2fem\n",
+ r/2 - .50 - .04);
+ }
+ else {
+ if (do_a_box)
+ printf ("\\vrule width%.2fem height%1.3fex depth%1.3fex%%\n",
+ r/2 - .50 - .04, .09281 - d, d);
+ else
+ printf ("\\vrule width%.2fem height%1.3fex depth%1.3fex%%\n",
+ r/2 - .50 - .04, h, .09281 - h);
+ }
+ if (first != last) hskip -= (r/2 - .50);
+ printf ("\\vrule width.04em");
+ }
+
+
+
+ if (do_nothing) {
+ hskip += .25;
+ return;
+ }
+ dohskip();
+ if (do_a_bar) {
+ printf ("\\vrule width.04em%%\n");
+ hskip -= .04;
+ }
+ if (do_a_line) {
+ setsuffix(m, mom->treeid);
+ printf("\\lower%1.3fex\\hbox{\\special{%scurrentpoint",d,SKEY);
+ }
+ if (def_an_osister) {
+ setsuffix(m, node->treeid);
+ printf("\\raise%1.3fex\\hbox{\\special{%scurrentpoint",h,SKEY);
+ }
+ if (def_a_sister)
+ printf(" /sis%sy exch def /sis%sx exch def}}%%\n",m,m);
+ if (do_a_triangle) {
+ if (def_a_sister) {
+ hskip += r/2 - .75;
+ dohskip();
+ hskip += .25;
+ printf("\\lower%1.3fex\\hbox{",d);
+ printf("\\special{%scurrentpoint",SKEY);
+ }
+ printf(" sis%sx sis%sy lineto mom%sx mom%sy lineto",m,m,m,m);
+ printf(" closepath");
+ if (greyness)
+ printf(" .%d setgray fill 0 setgray", greyness);
+ else printf(" stroke");
+ }
+ if (do_a_line && !do_a_tbar && !def_a_sister && !do_a_triangle
+ && !do_a_bar && !has(node,'O') && !has(node,'P'))
+ printf(" mom%sx mom%sy lineto stroke",m,m);
+
+ if (do_a_line && (do_a_triangle || !def_a_sister)) {
+ printf(" moveto}}%%\n");
+ }
+ if (def_a_mother) {
+ if (def_an_osister) {
+ hskip += r/2 - .75;
+ dohskip();
+ hskip += .25;
+ is_daughter = FALSE;
+ }
+ setsuffix(n, node->treeid);
+ if (is_daughter) printf("\\lower%1.3fex",d);
+ else printf("\\raise%1.3fex",h);
+ printf("\\hbox{\\special{%s currentpoint",SKEY);
+ printf(" /mom%sy exch def /mom%sx exch def}}%%\n",n,n);
+ }
+ if (utex_opt && iattrib > 0) {
+ setsuffix(n, iattrib);
+ curvegen(n, is_daughter);
+ }
+ if (do_a_tbar) {
+ hskip -= .25 - .04;
+ dohskip();
+ printf("\\hbox to 0.5em{\\hss$%s$\\hss}%%\n",
+ (has(node,'U') == 'i')? whichobar[b] : whichbar[b]);
+ hskip -= .25 + .04;
+ }
+
+ hskip += .25;
+}
+
+
+
+ /* Horizontal bars also start half way through a space.
+ * They have a vertical bar in the center and extend .4pt
+ * further than half way through a character space at the
+ * end to cap the vertical bar that will come below.
+ * For the -u option, instead of rules, generate PS code
+ * to remember the coordinates under the node name above, so
+ * later can draw line from daughters back to here.
+ */
+texhbar(node, iattrib, r, rm, is_daughter)
+TREE node;
+int iattrib, is_daughter;
+float r, rm;
+{ TREE mom = node->mother;
+
+ if (utex_opt && !has(node,'B')) {
+/* REVISE HERE */
+/* rm/2 + (r - rm)/2 = rm/2 + r/2 - rm/2 = r/2 */
+
+ hskip += rm/2 + .25;
+ dohskip ();
+ if (debug_opt) printf("%% Here is mom [%d]\n", node->treeid);
+ printf("\\raise%1.3fex\\hbox{\\special{%scurrentpoint",h,SKEY);
+ setsuffix(m, node->treeid);
+ printf(" /mom%sy exch def /mom%sx exch def}}%%\n",m,m);
+ if (iattrib > 0) {
+ setsuffix(n, iattrib);
+ curvegen(n, is_daughter);
+ }
+ hskip += (r - rm)/2 - .25;
+ } else {
+ float w;
+ hskip += .25;
+ dohskip ();
+ if (b == 9 && r >= 6)
+ printf("\\hbox to %.2fem{\\downbracefill}%%\n",
+ r/2 - .50 + .04);
+ else if (!node->mother)
+ printf ("\\vrule width%.2fem height%1.3fex depth%1.3fex%%\n",
+ r/2 - .50 + .04, .09281 - d, d);
+ else {
+ if ((w = rm/2) > .01)
+ printf ("\\vrule width%.2fem height%1.3fex depth%1.3fex%%\n",
+ w, .09281 - d, d);
+ printf ("\\vrule width.04em");
+ if ((w = r/2 - w - .50) > .01)
+ printf ("\\vrule width%.2fem height%1.3fex depth%1.3fex%%\n",
+ w, .09281 - d, d);
+ }
+ hskip += .25 -.04;
+ }
+}
+
+
+
+texobar(node, iattrib, r, rm, is_daughter)
+TREE node;
+int iattrib, is_daughter;
+float r, rm;
+{
+ /* "left" is actually a pointer up to first daughter */
+ if (utex_opt && !has(node,'B') && node->left && node->left->mother == node
+ && node->left->type == VBAR) {
+ TREE sis = node->left;
+ hskip += rm/2 + .25;
+ dohskip ();
+ if (debug_opt) printf("%% Here is bottom pt [%d]\n", node->treeid);
+ printf("\\lower%1.3fex\\hbox{\\special{%scurrentpoint",d,SKEY);
+
+ if (iattrib == -1) {
+ setsuffix(n, node->treeid);
+ printf(" currentpoint /mom%sy exch def /mom%sx exch def",n,n);
+ }
+
+ while (sis && sis->mother == node) {
+ if (has(sis,'O') || has(sis,'P')) {
+ sis = sis->sister;
+ continue;
+ }
+ setsuffix(m, sis->treeid);
+ if (has(node,'T')) {
+ if (has(node,'S') == 'f'
+ || has(node,'S') == 'l'
+ || has(node,'S') == 'o')
+ printf(" sis%sx sis%sy lineto",m,m);
+ }
+ else printf(" currentpoint sis%sx sis%sy lineto moveto",m,m);
+ if (has(node,'T') && has(node,'S') == 'o')
+ printf(" mom%sx mom%sy lineto",m,m);
+ sis = sis->sister;
+ }
+ if (has(node,'T')) {
+ printf(" closepath");
+ if (greyness)
+ printf(" .%d setgray fill 0 setgray", greyness);
+ else printf(" stroke");
+ }
+ else printf(" stroke");
+ printf(" moveto}}%%\n");
+ if (iattrib > 0) {
+ setsuffix(n, iattrib);
+ curvegen(n, is_daughter);
+ }
+ hskip += (r - rm)/2 - .25;
+
+ }
+ else {
+ float w;
+ hskip += .25;
+ dohskip ();
+ if (b == 9 && r >= 6)
+ printf("\\hbox to %.2fem{\\upbracefill}%%\n",
+ r/2 - .50 + .04);
+ else if (node->mother && node->right) {
+ if ((w = rm/2) > .01)
+ printf ("\\vrule width%.2fem height%1.3fex depth%1.3fex%%\n",
+ w, h, .09281 - h);
+ printf ("\\vrule width.04em");
+ if ((w = r/2 - w - .50) > .01)
+ printf ("\\vrule width%.2fem height%1.3fex depth%1.3fex%%\n",
+ w, h, .09281 - h);
+ }
+ else printf ("\\vrule width%.2fem height%1.3fex depth%1.3fex%%\n",
+ r/2 - .50 + .04, h, .09281 - h);
+ hskip += .25 - .04;
+ }
+}
+
+texnodename(node, r)
+TREE node;
+float r;
+{
+ if (has(node,'P')) hskip += r/2;
+ else {
+ dohskip ();
+ if (has(node,'R'))
+ printf ("\\hbox to %.2fem{\\hss{%s}}%%\n",
+ r/2, node->n);
+ else printf ("\\hbox to %.2fem{\\hss{%s}\\hss}%%\n",
+ r/2, node->n);
+ }
+}
+
+/* emit TeX code for a bar or a box containing a node name */
+boxitup (node)
+TREE node;
+{
+ float r = node->l, rm;
+ int iattrib = 0;
+ int is_daughter;
+ int i;
+ TREE mom = node->mother;
+
+ if (b = has(node,'B')) {
+ if (b == '+') b = 9;
+ else if (isdigit(b)) b -= '0';
+ else b = 0;
+ greyness = b;
+ }
+ else {
+ for (b = black_opt; b > 10; b /= 10) ;
+ for (greyness = black_opt; greyness >= 100; greyness /= 10);
+ }
+ if (greyness > 9) greyness = 100 - greyness;
+ else if (greyness) greyness = 10 - greyness;
+
+ if (mom && node != mom->daughter && node->sister) mom = NULL;
+
+ /* set height and depth for raising and lowering and for strut
+ * at end of line
+ */
+ set_hd(node);
+
+ iattrib = setiattrib(node, &is_daughter);
+
+ /* halve width to compensate for doubling col values */
+ r /= COLMUL;
+ i = node->mid;
+ if (COLMUL > 2) i /= (COLMUL/2);
+ rm = i;
+ if (COLMUL > 1) rm /= 2;
+
+ /* now generate TeX code for VBARs, HBARs, and NODENAMEs */
+ switch(node->type) {
+ case VBAR: texvbar(node, iattrib, r, is_daughter);
+ break;
+ case HBAR: texhbar(node, iattrib, r, rm, is_daughter);
+ break;
+ case OBAR: texobar(node, iattrib, r, rm, is_daughter);
+ break;
+ case NODENAME: texnodename(node, r);
+ break;
+ }
+}
+
+
+/* Like preceding routine tex(), except collect spaces and
+ * emit globs of TeX \hskip, \hbox, and \vrule commands (for
+ * respectively space, node names, and tree lines).
+ */
+tex(tree)
+TREE tree;
+{
+ int row = tree->row,
+ col = 0,
+ i;
+
+ hskip = (float) indent / 2;
+
+ /* mark all labels as undefined */
+ for (i = 0; i < 11; i++) {
+ m_ulabel[i] = 0;
+ d_ulabel[i] = 0;
+ }
+ /* make sure set_hd looks at first row */
+ curr_row = -1;
+
+ /* Each line of the tree will be a paragraph, so prevent white space
+ * breaking up segments of vertical rules; put a strut at the
+ * end of each line to make it high enough. I'm not using regular
+ * \strut commands, because my own TeX code is not careful about
+ * keeping \strut defined appropriately for the font in use.
+ */
+ printf ("\n\n{\\parskip=0pt\\offinterlineskip%%\n");
+
+ while (1) {
+ if (!tree) {
+ printf ("\\vrule width0em height%1.3fex depth%1.3fex",h,d);
+ printf ("\\par}\n");
+ bufp = buf; /* can reuse string buffer for next tree */
+ /* (could free malloc'd memory for tree nodes, too) */
+ return;
+ }
+ if (tree->row > row) {
+ /* Put a strut at the end of each line. The height and
+ * depth were determined by set_hd, called by boxitup.
+ */
+ printf ("\\vrule width0em height%1.3fex depth%1.3fex",h,d);
+ /* prevent page breaks in midst of tree */
+ printf ("\\par\\penalty10000\n");
+ row++;
+ col = 0;
+ hskip = (float) indent / 2;
+ }
+ else if ((tree->row == row)
+ && (tree->col == col)) {
+ boxitup(tree);
+ col += tree->l;
+ tree = tree->right;
+ }
+ else {
+ /* to advance one column, hskip 1/4 em, which is only 1/2
+ * en space, since we doubled all the col values
+ */
+ hskip +=.50/COLMUL;
+ col++;
+ }
+ }
+}
diff --git a/graphics/tree/texsample b/graphics/tree/texsample
new file mode 100644
index 0000000000..61b4b2b90d
--- /dev/null
+++ b/graphics/tree/texsample
@@ -0,0 +1,228 @@
+
+% before running TeX, process this with:
+% tree -t <texsample >texsample.tex
+% or tree -u <texsample >texsample.tex
+
+\nopagenumbers
+% hi is a strut to leave more room above overlined things
+\def\hi{\vrule width0em height10pt depth3.5pt}
+
+ NP: Article Replacement
+\bigskip
+ \tree
+(S$_0$
+ (NP
+ (Det
+ (John$_i$'s)
+ )
+ (\hi $\overline{\rm N}$
+ (N\L
+ (denunciation)
+ )
+ (\hi $\overline{\rm P}$
+ (P\L
+ (of)
+ )
+ (NP$_i$
+ (himself)
+ )
+ )
+ )
+ )
+ (\hi $\overline{\rm V}$
+ (V\L
+ (surprise)
+ )
+ (NP
+ (us)
+ )
+ )
+)
+
+\bigskip
+
+\noindent{\rm 2c. John's denunciation of himself surprised us.}\medskip
+
+ \tree
+(
+ (S$_0$
+ (NP
+ (Det\L
+ (the)
+ )
+ (\hi$\overline{\rm N}$
+ (N\L
+ (ACTION)
+ )
+ (S$_1$
+ (NP$_i$
+ (John)
+ )
+ (\hi$\overline{\rm V}$
+ (V\L
+ (denounce)
+ )
+ (NP$_i$
+ (him)
+ )
+ )
+ )
+ )
+ )
+ (\hi$\overline{\rm V}$
+ (V\L
+ (surprise)
+ )
+ (NP
+ (us)
+ )
+ )
+ )
+ (\rm S$_1$: Reflexivization $\rightarrow$)
+ (S$_0$
+ (NP
+ (Det\L
+ (the)
+ )
+ (\hi$\overline{\rm N}$
+ (N\L
+ (ACTION)
+ )
+ (S$_1$
+ (NP$_i$
+ (John)
+ )
+ (\hi$\overline{\rm V}$
+ (V\L
+ (denounce)
+ )
+ (NP$_i$
+ (himself)
+ )
+ )
+ )
+ )
+ )
+ (\hi$\overline{\rm V}$
+ (V\L
+ (surprise)
+ )
+ (NP
+ (us)
+ )
+ )
+ )
+)
+
+
+ \noindent{\rm $\overline{\rm N}$: Nominalization}\smallskip
+ \tree
+(S$_0$
+ (NP
+ (Det\L
+ (the)
+ )
+ (\hi$\overline{\rm N}$
+ (\hi$\overline{\rm N}$
+ (N
+ (V\L
+ (denounce)
+ )
+ (N\L
+ (ACTION)
+ )
+ )
+ (NP$_i$
+ (himself)
+ )
+ )
+ (NP$_i$
+ (John)
+ )
+ )
+ )
+ (\hi$\overline{\rm V}$
+ (V\L
+ (surprise)
+ )
+ (NP
+ (us)
+ )
+ )
+)
+
+
+ \noindent{\rm $\overline{\rm N}$: Preposition insertion}\smallskip
+ \tree
+(S$_0$
+ (NP
+ (Det\L
+ (the)
+ )
+ (\hi$\overline{\rm N}$
+ (\hi$\overline{\rm N}$
+ (N\L
+ (denunciation)
+ )
+ (\hi$\overline{\rm P}$
+ (P\L
+ (of)
+ )
+ (NP$_i$
+ (himself)
+ )
+ )
+ )
+ (\hi$\overline{\rm P}$
+ (P\L
+ (by)
+ )
+ (NP$_i$
+ (John)
+ )
+ )
+ )
+ )
+ (\hi$\overline{\rm V}$
+ (V\L
+ (surprise)
+ )
+ (NP
+ (us)
+ )
+ )
+)
+
+
+ \noindent{\rm NP: Article Replacement}\smallskip
+ \tree
+(S$_0$
+ (NP
+ (Det
+ (John's)
+ )
+ (\hi$\overline{\rm N}$
+ (N\L
+ (denunciation)
+ )
+ (\hi$\overline{\rm P}$
+ (P\L
+ (of)
+ )
+ (NP$_i$
+ (himself)
+ )
+ )
+ )
+ )
+ (\hi$\overline{\rm V}$
+ (V\L
+ (surprise)
+ )
+ (NP
+ (us)
+ )
+ )
+)
+
+\bye
diff --git a/graphics/tree/texsample.tex b/graphics/tree/texsample.tex
new file mode 100644
index 0000000000..c5b96d7497
--- /dev/null
+++ b/graphics/tree/texsample.tex
@@ -0,0 +1,406 @@
+
+% before running TeX, process this with:
+% tree -t <texsample >texsample.tex
+% or tree -u <texsample >texsample.tex
+
+\nopagenumbers
+% hi is a strut to leave more room above overlined things
+\def\hi{\vrule width0em height10pt depth3.5pt}
+
+ NP: Article Replacement
+\bigskip
+
+
+{\parskip=0pt\offinterlineskip%
+\hskip 13.25em\hbox to 1.00em{\hss{S$_0$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 8.56em\vrule width5.25em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width5.06em height-0.407ex depth0.500ex%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 8.56em\vrule width.04em%
+\hskip 10.27em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 8.06em\hbox to 1.00em{\hss{NP}\hss}%
+\hskip 9.56em\hbox to 0.50em{\hss{\hi $\overline{\rm V}$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 5.75em\vrule width3.00em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width2.62em height-0.407ex depth0.500ex%
+\hskip 5.84em\vrule width1.75em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width1.50em height-0.407ex depth0.500ex%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 5.75em\vrule width.04em%
+\hskip 5.59em\vrule width.04em%
+\hskip 5.84em\vrule width.04em%
+\hskip 3.21em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 5.00em\hbox to 1.50em{\hss{Det}\hss}%
+\hskip 4.62em\hbox to 0.50em{\hss{\hi $\overline{\rm N}$}\hss}%
+\hskip 5.38em\hbox to 0.50em{\hss{V}\hss}%
+\hskip 2.50em\hbox to 1.00em{\hss{NP}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 5.75em\vrule width.04em%
+\hskip 2.96em\vrule width2.75em height-0.719ex depth0.812ex%
+\vrule width.04em\vrule width2.50em height-0.719ex depth0.812ex%
+\hskip 1.21em\hbox to 4.00em{\hss{surprise}\hss}%
+\hskip 1.25em\vrule width.04em%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 4.00em\hbox to 3.50em{\hss{John$_i$'s}\hss}%
+\hskip 1.25em\vrule width.04em%
+\hskip 5.21em\vrule width.04em%
+\hskip 5.96em\hbox to 1.00em{\hss{us}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 8.50em\hbox to 0.50em{\hss{N}\hss}%
+\hskip 4.75em\hbox to 0.50em{\hss{\hi $\overline{\rm P}$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 5.75em\hbox to 6.00em{\hss{denunciation}\hss}%
+\hskip 1.25em\vrule width1.00em height-0.719ex depth0.812ex%
+\vrule width.04em\vrule width1.00em height-0.719ex depth0.812ex%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 13.00em\vrule width.04em%
+\hskip 1.96em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 12.75em\hbox to 0.50em{\hss{P}\hss}%
+\hskip 1.00em\hbox to 1.50em{\hss{NP$_i$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 12.50em\hbox to 1.00em{\hss{of}\hss}%
+\hskip 1.50em\vrule width.04em%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 13.25em\hbox to 3.50em{\hss{himself}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par}
+
+
+\bigskip
+
+\noindent{\rm 2c. John's denunciation of himself surprised us.}\medskip
+
+
+
+{\parskip=0pt\offinterlineskip%
+\hskip 8.31em\hbox to 1.00em{\hss{S$_0$}\hss}%
+\hskip 2.38em\hbox to 10.00em{\hss{\rm S$_1$: Reflexivization $\rightarrow$}\hss}%
+\hskip 2.38em\hbox to 1.00em{\hss{S$_0$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 4.00em\vrule width5.00em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width4.56em height-0.407ex depth0.500ex%
+\hskip 6.15em\vrule width5.00em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width4.56em height-0.407ex depth0.500ex%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 4.00em\vrule width.04em%
+\hskip 9.52em\vrule width.04em%
+\hskip 6.15em\vrule width.04em%
+\hskip 9.52em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 3.50em\hbox to 1.00em{\hss{NP}\hss}%
+\hskip 8.81em\hbox to 0.50em{\hss{\hi$\overline{\rm V}$}\hss}%
+\hskip 5.44em\hbox to 1.00em{\hss{NP}\hss}%
+\hskip 8.81em\hbox to 0.50em{\hss{\hi$\overline{\rm V}$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 1.75em\vrule width2.25em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width2.25em height-0.407ex depth0.500ex%
+\hskip 5.65em\vrule width1.75em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width1.50em height-0.407ex depth0.500ex%
+\hskip 2.27em\vrule width2.25em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width2.25em height-0.407ex depth0.500ex%
+\hskip 5.65em\vrule width1.75em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width1.50em height-0.407ex depth0.500ex%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 1.75em\vrule width.04em%
+\hskip 4.46em\vrule width.04em%
+\hskip 5.65em\vrule width.04em%
+\hskip 3.21em\vrule width.04em%
+\hskip 2.27em\vrule width.04em%
+\hskip 4.46em\vrule width.04em%
+\hskip 5.65em\vrule width.04em%
+\hskip 3.21em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 1.00em\hbox to 1.50em{\hss{Det}\hss}%
+\hskip 3.50em\hbox to 0.50em{\hss{\hi$\overline{\rm N}$}\hss}%
+\hskip 5.19em\hbox to 0.50em{\hss{V}\hss}%
+\hskip 2.50em\hbox to 1.00em{\hss{NP}\hss}%
+\hskip 1.06em\hbox to 1.50em{\hss{Det}\hss}%
+\hskip 3.50em\hbox to 0.50em{\hss{\hi$\overline{\rm N}$}\hss}%
+\hskip 5.19em\hbox to 0.50em{\hss{V}\hss}%
+\hskip 2.50em\hbox to 1.00em{\hss{NP}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 1.00em\hbox to 1.50em{\hss{the}\hss}%
+\hskip 1.25em\vrule width2.50em height-0.719ex depth0.812ex%
+\vrule width.04em\vrule width2.44em height-0.719ex depth0.812ex%
+\hskip 1.21em\hbox to 4.00em{\hss{surprise}\hss}%
+\hskip 1.25em\vrule width.04em%
+\hskip 1.52em\hbox to 1.50em{\hss{the}\hss}%
+\hskip 1.25em\vrule width2.50em height-0.719ex depth0.812ex%
+\vrule width.04em\vrule width2.44em height-0.719ex depth0.812ex%
+\hskip 1.21em\hbox to 4.00em{\hss{surprise}\hss}%
+\hskip 1.25em\vrule width.04em%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 3.75em\vrule width.04em%
+\hskip 4.90em\vrule width.04em%
+\hskip 5.96em\hbox to 1.00em{\hss{us}\hss}%
+\hskip 3.81em\vrule width.04em%
+\hskip 4.90em\vrule width.04em%
+\hskip 5.96em\hbox to 1.00em{\hss{us}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 3.50em\hbox to 0.50em{\hss{N}\hss}%
+\hskip 4.19em\hbox to 1.00em{\hss{S$_1$}\hss}%
+\hskip 10.06em\hbox to 0.50em{\hss{N}\hss}%
+\hskip 4.19em\hbox to 1.00em{\hss{S$_1$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 2.00em\hbox to 3.50em{\hss{ACTION}\hss}%
+\hskip 1.25em\vrule width2.00em height-0.719ex depth0.812ex%
+\vrule width.04em\vrule width1.88em height-0.719ex depth0.812ex%
+\hskip 7.09em\hbox to 3.50em{\hss{ACTION}\hss}%
+\hskip 1.25em\vrule width2.00em height-0.719ex depth0.812ex%
+\vrule width.04em\vrule width1.88em height-0.719ex depth0.812ex%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 6.75em\vrule width.04em%
+\hskip 3.84em\vrule width.04em%
+\hskip 11.84em\vrule width.04em%
+\hskip 3.84em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 6.00em\hbox to 1.50em{\hss{NP$_i$}\hss}%
+\hskip 2.88em\hbox to 0.50em{\hss{\hi$\overline{\rm V}$}\hss}%
+\hskip 10.88em\hbox to 1.50em{\hss{NP$_i$}\hss}%
+\hskip 2.88em\hbox to 0.50em{\hss{\hi$\overline{\rm V}$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 6.75em\vrule width.04em%
+\hskip 2.21em\vrule width1.75em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width1.50em height-0.407ex depth0.500ex%
+\hskip 10.21em\vrule width.04em%
+\hskip 2.21em\vrule width1.75em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width1.50em height-0.407ex depth0.500ex%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 5.75em\hbox to 2.00em{\hss{John}\hss}%
+\hskip 1.25em\vrule width.04em%
+\hskip 3.21em\vrule width.04em%
+\hskip 9.21em\hbox to 2.00em{\hss{John}\hss}%
+\hskip 1.25em\vrule width.04em%
+\hskip 3.21em\vrule width.04em%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 8.75em\hbox to 0.50em{\hss{V}\hss}%
+\hskip 2.25em\hbox to 1.50em{\hss{NP$_i$}\hss}%
+\hskip 11.50em\hbox to 0.50em{\hss{V}\hss}%
+\hskip 2.25em\hbox to 1.50em{\hss{NP$_i$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 7.00em\hbox to 4.00em{\hss{denounce}\hss}%
+\hskip 1.25em\vrule width.04em%
+\hskip 10.46em\hbox to 4.00em{\hss{denounce}\hss}%
+\hskip 1.25em\vrule width.04em%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 11.50em\hbox to 1.50em{\hss{him}\hss}%
+\hskip 13.25em\hbox to 3.50em{\hss{himself}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par}
+
+
+
+ \noindent{\rm $\overline{\rm N}$: Nominalization}\smallskip
+
+
+{\parskip=0pt\offinterlineskip%
+\hskip 15.06em\hbox to 1.00em{\hss{S$_0$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 10.25em\vrule width5.50em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width5.12em height-0.407ex depth0.500ex%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 10.25em\vrule width.04em%
+\hskip 10.59em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 9.75em\hbox to 1.00em{\hss{NP}\hss}%
+\hskip 9.88em\hbox to 0.50em{\hss{\hi$\overline{\rm V}$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 6.88em\vrule width3.50em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width3.19em height-0.407ex depth0.500ex%
+\hskip 5.65em\vrule width1.75em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width1.50em height-0.407ex depth0.500ex%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 6.88em\vrule width.04em%
+\hskip 6.65em\vrule width.04em%
+\hskip 5.65em\vrule width.04em%
+\hskip 3.21em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 6.12em\hbox to 1.50em{\hss{Det}\hss}%
+\hskip 5.69em\hbox to 0.50em{\hss{\hi$\overline{\rm N}$}\hss}%
+\hskip 5.19em\hbox to 0.50em{\hss{V}\hss}%
+\hskip 2.50em\hbox to 1.00em{\hss{NP}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 6.12em\hbox to 1.50em{\hss{the}\hss}%
+\hskip 3.44em\vrule width2.50em height-0.719ex depth0.812ex%
+\vrule width.04em\vrule width2.44em height-0.719ex depth0.812ex%
+\hskip 1.21em\hbox to 4.00em{\hss{surprise}\hss}%
+\hskip 1.25em\vrule width.04em%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 11.06em\vrule width.04em%
+\hskip 4.90em\vrule width.04em%
+\hskip 5.96em\hbox to 1.00em{\hss{us}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 10.81em\hbox to 0.50em{\hss{\hi$\overline{\rm N}$}\hss}%
+\hskip 3.94em\hbox to 1.50em{\hss{NP$_i$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 8.38em\vrule width2.75em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width2.62em height-0.407ex depth0.500ex%
+\hskip 2.21em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 8.38em\vrule width.04em%
+\hskip 5.34em\vrule width.04em%
+\hskip 1.21em\hbox to 2.00em{\hss{John}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 8.12em\hbox to 0.50em{\hss{N}\hss}%
+\hskip 4.38em\hbox to 1.50em{\hss{NP$_i$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 6.00em\vrule width2.50em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width2.25em height-0.407ex depth0.500ex%
+\hskip 2.96em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 6.00em\vrule width.04em%
+\hskip 4.71em\vrule width.04em%
+\hskip 1.21em\hbox to 3.50em{\hss{himself}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 5.75em\hbox to 0.50em{\hss{V}\hss}%
+\hskip 4.25em\hbox to 0.50em{\hss{N}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 4.00em\hbox to 4.00em{\hss{denounce}\hss}%
+\hskip 1.00em\hbox to 3.50em{\hss{ACTION}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par}
+
+
+
+ \noindent{\rm $\overline{\rm N}$: Preposition insertion}\smallskip
+
+
+{\parskip=0pt\offinterlineskip%
+\hskip 14.69em\hbox to 1.00em{\hss{S$_0$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 9.50em\vrule width5.75em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width5.62em height-0.407ex depth0.500ex%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 9.50em\vrule width.04em%
+\hskip 11.34em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 9.00em\hbox to 1.00em{\hss{NP}\hss}%
+\hskip 10.62em\hbox to 0.50em{\hss{\hi$\overline{\rm V}$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 6.19em\vrule width3.50em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width3.12em height-0.407ex depth0.500ex%
+\hskip 6.40em\vrule width1.75em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width1.50em height-0.407ex depth0.500ex%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 6.19em\vrule width.04em%
+\hskip 6.59em\vrule width.04em%
+\hskip 6.40em\vrule width.04em%
+\hskip 3.21em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 5.44em\hbox to 1.50em{\hss{Det}\hss}%
+\hskip 5.62em\hbox to 0.50em{\hss{\hi$\overline{\rm N}$}\hss}%
+\hskip 5.94em\hbox to 0.50em{\hss{V}\hss}%
+\hskip 2.50em\hbox to 1.00em{\hss{NP}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 5.44em\hbox to 1.50em{\hss{the}\hss}%
+\hskip 2.69em\vrule width3.25em height-0.719ex depth0.812ex%
+\vrule width.04em\vrule width3.12em height-0.719ex depth0.812ex%
+\hskip 1.21em\hbox to 4.00em{\hss{surprise}\hss}%
+\hskip 1.25em\vrule width.04em%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 9.62em\vrule width.04em%
+\hskip 6.34em\vrule width.04em%
+\hskip 5.96em\hbox to 1.00em{\hss{us}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 9.38em\hbox to 0.50em{\hss{\hi$\overline{\rm N}$}\hss}%
+\hskip 5.88em\hbox to 0.50em{\hss{\hi$\overline{\rm P}$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 7.00em\vrule width2.75em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width2.50em height-0.407ex depth0.500ex%
+\hskip 2.71em\vrule width1.00em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width1.00em height-0.407ex depth0.500ex%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 7.00em\vrule width.04em%
+\hskip 5.21em\vrule width.04em%
+\hskip 2.71em\vrule width.04em%
+\hskip 1.96em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 6.75em\hbox to 0.50em{\hss{N}\hss}%
+\hskip 4.75em\hbox to 0.50em{\hss{\hi$\overline{\rm P}$}\hss}%
+\hskip 2.25em\hbox to 0.50em{\hss{P}\hss}%
+\hskip 1.00em\hbox to 1.50em{\hss{NP$_i$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 4.00em\hbox to 6.00em{\hss{denunciation}\hss}%
+\hskip 1.25em\vrule width1.00em height-0.719ex depth0.812ex%
+\vrule width.04em\vrule width1.00em height-0.719ex depth0.812ex%
+\hskip 1.21em\hbox to 1.00em{\hss{by}\hss}%
+\hskip 1.50em\vrule width.04em%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 11.25em\vrule width.04em%
+\hskip 1.96em\vrule width.04em%
+\hskip 2.71em\hbox to 2.00em{\hss{John}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 11.00em\hbox to 0.50em{\hss{P}\hss}%
+\hskip 1.00em\hbox to 1.50em{\hss{NP$_i$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 10.75em\hbox to 1.00em{\hss{of}\hss}%
+\hskip 1.50em\vrule width.04em%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 11.50em\hbox to 3.50em{\hss{himself}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par}
+
+
+
+ \noindent{\rm NP: Article Replacement}\smallskip
+
+
+{\parskip=0pt\offinterlineskip%
+\hskip 12.81em\hbox to 1.00em{\hss{S$_0$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 8.19em\vrule width5.25em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width4.94em height-0.407ex depth0.500ex%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 8.19em\vrule width.04em%
+\hskip 10.15em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 7.69em\hbox to 1.00em{\hss{NP}\hss}%
+\hskip 9.44em\hbox to 0.50em{\hss{\hi$\overline{\rm V}$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 5.50em\vrule width2.75em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width2.62em height-0.407ex depth0.500ex%
+\hskip 5.84em\vrule width1.75em height-0.407ex depth0.500ex%
+\vrule width.04em\vrule width1.50em height-0.407ex depth0.500ex%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 5.50em\vrule width.04em%
+\hskip 5.34em\vrule width.04em%
+\hskip 5.84em\vrule width.04em%
+\hskip 3.21em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 4.75em\hbox to 1.50em{\hss{Det}\hss}%
+\hskip 4.38em\hbox to 0.50em{\hss{\hi$\overline{\rm N}$}\hss}%
+\hskip 5.38em\hbox to 0.50em{\hss{V}\hss}%
+\hskip 2.50em\hbox to 1.00em{\hss{NP}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 5.50em\vrule width.04em%
+\hskip 2.71em\vrule width2.75em height-0.719ex depth0.812ex%
+\vrule width.04em\vrule width2.50em height-0.719ex depth0.812ex%
+\hskip 1.21em\hbox to 4.00em{\hss{surprise}\hss}%
+\hskip 1.25em\vrule width.04em%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 4.00em\hbox to 3.00em{\hss{John's}\hss}%
+\hskip 1.25em\vrule width.04em%
+\hskip 5.21em\vrule width.04em%
+\hskip 5.96em\hbox to 1.00em{\hss{us}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 8.00em\hbox to 0.50em{\hss{N}\hss}%
+\hskip 4.75em\hbox to 0.50em{\hss{\hi$\overline{\rm P}$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 5.25em\hbox to 6.00em{\hss{denunciation}\hss}%
+\hskip 1.25em\vrule width1.00em height-0.719ex depth0.812ex%
+\vrule width.04em\vrule width1.00em height-0.719ex depth0.812ex%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 12.50em\vrule width.04em%
+\hskip 1.96em\vrule width.04em%
+\vrule width0em height1.500ex depth0.500ex\par\penalty10000
+\hskip 12.25em\hbox to 0.50em{\hss{P}\hss}%
+\hskip 1.00em\hbox to 1.50em{\hss{NP$_i$}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 12.00em\hbox to 1.00em{\hss{of}\hss}%
+\hskip 1.50em\vrule width.04em%
+\vrule width0em height1.972ex depth0.812ex\par\penalty10000
+\hskip 12.75em\hbox to 3.50em{\hss{himself}\hss}%
+\vrule width0em height1.972ex depth0.812ex\par}
+
+
+\bye
diff --git a/graphics/tree/tpar.l b/graphics/tree/tpar.l
new file mode 100644
index 0000000000..a601fd888b
--- /dev/null
+++ b/graphics/tree/tpar.l
@@ -0,0 +1,206 @@
+%{
+/*
+ * tpar: pre-processor for tree; adds parens according to indentation.
+ * Version 0.1
+ *
+ * Blank line ends the tree.
+ * ` - ' adds following item on same line as single child.
+ * Does not do forests -- add outer parens in source as part of
+ * beginning and ending node names or use null command \Z.
+ * Option -t converts N',V',A',P' by adding TeX \overline commands,
+ * and [<digit or i,j,k,x,y,z>] by adding TeX subscripting
+ * commands.
+ * Option -v puts right parentheses on new lines, with indentation
+ * the same as the preceding matching paren.
+ *
+ * Greg, lee@uhccux.uhcc.hawaii.edu, 6/24/90
+ */
+
+#define TRUE 1
+#define FALSE 0
+int tex_opt = FALSE;
+int v_opt = FALSE;
+
+int outercol = 0;
+int linenumber = 0;
+int indent = 0;
+int minindent = 0;
+int level = 0;
+int buried[100];
+int extra = 0;
+%}
+
+%s T O X
+
+%%
+
+<O>\n {
+ outercol = 0;
+ indent = 0;
+ linenumber++;
+ ECHO;
+}
+
+<T,X>\n {
+ if (!outercol) {
+ descend(minindent);
+ ECHO;
+ BEGIN(O);
+ }
+ indent = outercol = 0;
+ linenumber++;
+}
+
+<O>\t {
+ outercol++;
+ while (outercol % 8) outercol++;
+ ECHO;
+}
+
+<T,X>\t {
+ outercol++;
+ while (outercol % 8) outercol++;
+}
+
+<T,X>" " {
+ outercol++;
+ if (indent) ECHO;
+}
+
+<T,X>[ \t]+"-"[ \t]+ {
+ extra++;
+ printf("(");
+}
+
+\\tree[ \t]*(-([tuvLTOIFER]+|[bg][0-9]+)[ \t]*)* {
+ outercol += yyleng;
+ level = extra = 0;
+ minindent = 200;
+ buried[0] = -1;
+ if (tex_opt) BEGIN(X);
+ else BEGIN(T);
+ ECHO;
+}
+
+<O>. {
+ outercol++;
+ ECHO;
+}
+
+<X>[NVAP]' {
+ ascend();
+ outercol += 2;
+ printf("$\\overline{\\rm %c}$", yytext[0]);
+}
+
+<X>\[[0-9ijkxyz]\] {
+ ascend();
+ outercol += 3;
+ printf("$_%c$", yytext[1]);
+}
+
+<T,X>\\Z[ \t]*$ {
+ ascend();
+ outercol += 2;
+}
+
+<T,X>. {
+ ascend();
+ outercol++;
+ ECHO;
+}
+
+%%
+
+descend(indent)
+int indent;
+{ int i;
+
+ if (extra) do printf(")"); while (--extra);
+ if (indent > buried[level]) {
+ buried[++level] = indent;
+ }
+ else {
+ printf(")");
+ while (level >= 0 && indent < buried[level]) {
+ level--;
+ if (v_opt) {
+ printf("\n");
+ for (i = 1; i < buried[level]; i++)
+ printf(" ");
+ }
+ printf(")");
+ }
+ }
+ printf("\n");
+}
+
+ascend()
+{ int i;
+
+ if (indent) return;
+ descend(indent = outercol+1);
+ if (indent < minindent) minindent = indent;
+ for (i = 1; i < indent; i++) printf(" ");
+ printf("(");
+}
+
+extern char *optarg; /* from getopt */
+extern int optind;
+
+main(argc, argv)
+int argc;
+char *argv[];
+{ int c;
+ char *progname = NULL, *basename();
+
+ progname = basename (argv[0]);
+ while ((c = getopt (argc, argv, "htv")) != EOF)
+ switch (c) {
+ case 't': tex_opt = TRUE; break;
+ case 'v': v_opt = TRUE; break;
+ case 'h':
+ default:
+ fprintf(stderr, "Usage: %s [options] [files]\n", progname);
+ fprintf(stderr, "options = -t\t(TeX code)\n");
+ fprintf(stderr, " -v\t(parens on new lines)\n");
+ fprintf(stderr, " -h\t(print this information)\n");
+ exit(1);
+ }
+
+ BEGIN(O);
+
+ if (optind >= argc) {
+ (void) yylex ();
+ }
+ else for (; (optind < argc); optind++) {
+ if (yyin == NULL) yyin = stdin;
+ if (freopen (argv[optind], "r", stdin) != NULL) {
+#ifdef FLEX_SCANNER
+ /* to get flex to look at > 1 file */
+ yy_init = 1;
+#endif
+ (void) yylex ();
+ if (level > 1) descend(minindent);
+ outercol = linenumber = indent = minindent = 0;
+ level = extra = 0;
+ }
+ else {
+ (void) fprintf (stderr,
+ "Couldn't open file: %s\n", argv[optind]);
+ exit (1);
+ }
+ }
+ if (level > 1) descend(minindent);
+}
+
+
+char *basename (s)
+char *s;
+{
+ char *p, *strrchr();
+
+ if (p = strrchr(s, '/'))
+ return(++p);
+ else return(s);
+}
diff --git a/graphics/tree/tpsample b/graphics/tree/tpsample
new file mode 100644
index 0000000000..36793dea84
--- /dev/null
+++ b/graphics/tree/tpsample
@@ -0,0 +1,106 @@
+\noindent
+
+Here are some examples to illustrate the tpar program and the
+`T' triangle, `L' lexical, `O' omit, `M' mother, `D' daughter,
+and `P' phantom tree commands.
+
+%% For tty output, use
+%% % tpar tpsample |tree |more
+%% or % tpar -t tpsample |tree |more
+%% For TeX output, use
+%% % tpar -t tpsample |tree -t >tpsample.tex
+%% or % tpar -t tpsample |tree -u >tpsample.tex
+
+This is from the man page:
+
+ (ex8) \tree \T S
+ every
+ good boy
+ VP
+ \L V - does
+ \L A - fine
+
+A couple of examples from McCawley's text:
+
+p. 35
+(6)\tree -b2
+S[0]
+ S[1]
+ S[2]
+ NP\T - the terrorists
+ VP
+ V\L - shoot
+ NP\T - the hostage
+ n't
+ Adv\L - probably
+
+The V' with `say' in this next example came out too wide, originally,
+because the two constituents following the V, the P' and NP, couldn't be
+put close enough together. I wanted to lower the S[2] under the NP so
+it would go closer to the preceding P', so I've put a node with no name
+but with command Z between the NP and the S[2] below it. The
+Z command does not do anything except hold a place in the tree;
+it's a little tricky.
+
+p. 689
+(8)\tree
+S[0]
+ NP[x]
+ the
+ S[3]
+ NP - you
+ V'\T - send $x$ many Christmas\L - cards to your friends
+ S[1]
+ NP - it
+ V'
+ V\L - say
+ P'\T - in the Times Al.
+ NP
+ \Z
+ S[2]
+ NP\T - President R
+ V'\T
+ send more than\L - $x$ Christmas cards to\L - Republican supporters
+
+
+In this example from McCawley, p. 310, the V is made an unnatural
+mother of the Adv with the M and D commands, and the line that
+would have connected the Adv to the S is omitted with the O command.
+The original position of the Adv is marked with a phantom, to get the
+tree to look like something belongs here.
+
+(6b) \tree
+V'
+ \M V
+ V\L - prove
+ ghost\P
+ NP
+ S\T - that the earth is round
+ \D\O Adv\L - conclusively
+
+From McCawley, p. 423. There are two side-by-side trees here, but
+the left one has omitted lines, so that all that is visible is
+`RNR' and the arrow. The N-bar is connected to the S `who teach ...'
+with M and D commands, but the line connecting the S to its natural
+mother remains. To get the line connecting the two N-bars to slant
+to the left, the P command is used to put a phantom constituent in
+the original position of the RNR'd S. That first Z command is there
+just to hold a place in the tree.
+
+(21) \tree
+\Z
+ \O - \O - RNR\O\L - ---$>$
+ NP
+ NP
+ Det\L - most
+ N'\M
+ N' - N\L - linguists
+ some room\P
+ and
+ NP
+ Det\L - almost\L - all
+ N'
+ N' - N\L - anthro-\L - pologists
+ S\D\T - who teach at\L - American\L - universities
+
+\bye
diff --git a/graphics/tree/tree.1 b/graphics/tree/tree.1
new file mode 100644
index 0000000000..3bcf5345fa
--- /dev/null
+++ b/graphics/tree/tree.1
@@ -0,0 +1,449 @@
+.TH TREE 1 LOCAL
+.SH NAME
+tree, tpar
+.SH SYNOPSIS
+.B tree
+[ options ] [ files ]
+.br
+.B tpar
+[
+.B \-t
+] [
+.B \-v
+] [ files ]
+.br
+.B unpar
+[
+.B \-t
+]
+.B <
+file
+.SH DESCRIPTION
+.I Tree
+reformats trees in a text whose structure is given by parenthesization
+into trees displayed with horizontal and vertical lines (or diagonal
+lines) connecting the
+node names.
+The companion program
+.I tpar
+is an optional utility for adding parentheses to trees with structure
+indicated by indentation.
+See the example file ptsample and the comments at the beginning of
+the source tpar.l for more information.
+The other utility
+.I unpar
+does the opposite of
+.IR tpar :
+it removes parentheses.
+.PP
+.I Tree
+has 13 options:
+.TP
+.B \-t
+causes
+.I tree
+to emit
+.I TeX
+code.
+.TP
+.B \-u
+also produces
+.I TeX
+code, but with PostScript commands for
+diagonal lines.
+.TP
+.BR \-b <num>
+sets the blackness of triangles drawn under certain nodes (see below).
+For the
+.B \-t
+option, extra verticals fill in the base of ``triangles'', the
+spacing of them depending on <num>.
+For tty output, various characters are used to approximate connecting
+lines, again depending on <num>.
+.TP
+.B \-v
+displays
+.I TeX
+commands for tty output \- normally they are suppressed.
+.TP
+.BR \-g <num>
+uses <num> for gap separating subtrees in place of default value of 2.
+.TP
+.BR \-q
+suppresses warning messages that are otherwise issued when various
+circumstances suggest a possible problem with the definition of a
+tree.
+The warnings are given for blank lines, `\\tree' commands, or text
+after a node name when any of these are found within a tree definition.
+.TP
+.B \-O
+causes the lines connecting node names to be omitted.
+This option has the same effect as giving the `\\O' command
+for each node.
+.TP
+.B \-L
+omits the lines connecting nodes, leaving no vertical space
+where the lines would have been.
+This option has the same effect as giving the `\\L' command for each node.
+.TP
+.B \-T
+draws triangles under nodes instead of branches.
+This option has the same effect as giving the `\\T' command for each node.
+.TP
+.B \-I
+turns trees upside down.
+This option has the same effect as giving the `\\I' command for the top node
+(or the top nodes, in the case of side-by-side trees).
+.TP
+.B \-F
+lowers terminals to lowest level found in the subtree whose top node
+is marked with `\\E'', or else to the lowest level in the entire
+tree if `\\E' has not been used. If a terminal has a node immediately
+above it with the `\\L' lexical command, this is lowered too.
+This option has the same effect as giving the `\\F' command for each
+terminal node (or lexical node above it).
+.TP
+.B \-E
+restricts the context for lowering with `\\F' commands or the
+.B \-F
+option to each subtree under a branching node.
+This option has the same effect as giving the `\\E' command for
+every branching node.
+.TP
+.B \-R
+places node names to the left of verticals.
+This option has the same effect as giving the `\\R' command for
+every non-terminal node.
+.PP
+.I Tree
+processes the text in the files named on the command line,
+and the resulting text with the
+reformatted trees is produced on the standard output.
+If no file names are given on the command line, input
+text is assumed on the standard input.
+.sp
+.DS
+ % tree inputtextfile >outputtextfile
+.br
+ % tree <inputtextfile >outputtextfile
+.br
+ % tree -t old.tex >new.tex
+.DE
+.sp
+A tree in a text is introduced by the command `\\tree'.
+.sp
+.DS
+ (ex1) \\tree (S(NP(John))(VP(runs)))
+.DE
+.sp
+The formatted tree will be indented by the space that separated the
+`\\tree' command from the left margin (8 spaces for the above example).
+The `\\tree' command may be followed by the same options that can
+be given on the command line.
+In case of a conflict, an option given in the text overrides
+one given on the command line.
+Nodes need not have names, but if the root node has no name, you need
+an extra pair of enclosing parentheses if the daughters of the
+root are to be connected by lines:
+.sp
+.DS
+ (ex2) \\tree ((((John))((runs))))
+.DE
+.sp
+.PP
+After any options, the `\\tree' command must be followed by a tree.
+In the case of inappropriate options, or when the next
+non-whitespace character after the command and valid options is not
+a `(', the command is ignored (and it remains in the processed text).
+.sp
+.DS
+ (ex3) \\tree \- this line will remain unchanged
+.DE
+.sp
+If what follows the command does begin like a tree, but does not
+have enough right parens to balance the left ones, an error is reported.
+.sp
+.DS
+ (ex4) \\tree (S(NP(John)(VP(runs))) \- a bad tree missing
+.br
+ a right paren
+.DE
+.sp
+Trees contain node names and (sub)trees.
+The name of the node comes before any sub-trees; text after a sub-tree
+not in parentheses is treated as a comment and is discarded.
+Since placing text in this position is not an ordinary way of putting
+comments into a tree definition, unless the
+.B \-q
+option is given, warning messages are issued when such text is found.
+.sp
+.DS
+ (ex5) \\tree -q (a phrase composed of others(a phrase
+.br
+\ \ \ \ \ (a)(phrase))
+.br
+\ \ \ \ \ This is a comment.(composed) (of others
+.br
+\ \ \ \ \ (of)(others)) )
+.DE
+.sp
+Several trees can be placed side-by-side by giving no name to the
+topmost node:
+.sp
+.DS
+ (ex6) \\tree ((S(John)(V(runs)(fast))) (==>)
+.br
+ (S(V(runs)(fast))(S(John)(does))))
+.DE
+.sp
+Spacing and new lines are generally not significant, except that spacing
+between parts of a node name causes a space to be part of the name (only
+a single space appears for multiple blanks or tabs).
+As in
+.IR TeX ,
+the percent character introduces a comment which continues through
+the end of the line.
+(ex7) produces the
+same tree as (ex1) above:
+.sp
+.DS
+ (ex7) \\tree (S % Comments like this
+ (NP % are skipped over.
+ (John)
+ )
+ (VP
+ (runs)
+ )
+ )
+.DE
+.sp
+To include left or right paren as part of a node name, precede it with a
+back slash.
+.sp
+.DS
+ (ex8) \\tree (NP (Det(John's \\(genitive\\)))
+.br
+ (N\\([+count]\\)(legs)) )
+.DE
+.sp
+A blank may also be made part of a node name by preceding it with a
+backslash (but this is not usually necessary).
+It is not necessary to use `\\\\' to
+make backslash part of a node name, although it is possible, since
+this will produce a single backslash in the output.
+A percent sign is counted a comment character, as in
+.IR TeX ,
+so to include a percent that will print, use `\\%'.
+When generating
+.I TeX
+code,
+.I tree
+will leave the backslash there, as well as the percent, so that
+.I TeX
+will print a percent.
+.PP
+The horizontal space separating subparts of a tree is by default
+two spaces. This can be varied by calling
+.I tree
+with the
+.B -g
+(for ``gap'') option, for instance:
+.sp
+.DS
+ % tree -g4 infile
+.DE
+.sp
+gives twice the default gap.
+You might need to increase the gap when using
+.IR TeX ,
+because it's possible for node names to run into one another.
+.PP
+A node can be given a display attribute with a command of the
+form backslash plus capital letter.
+`\\T' draws a triangle under a node name instead of a vertical or
+diagonal lines,
+and `\\L' for `lexical' omits the vertical under a node with a single child.
+The triangle is for the common convention to indicate structure
+not given explicitly.
+Without the
+.B \-u
+option, it is not actually a triangle, but rather a box with a
+vertical at the top.
+With that option, it is an outlined triangle or, if the
+.B \-b
+option was given with a non-zero value, it is a filled triangle,
+with blackness determined by the number after
+.BR \-b .
+(This number is interpreted as a decimal fraction with higher
+values giving darker shades of gray; 8 is darker than 2,
+and 85 is just a tiny bit darker than 8.)
+.sp
+.DS
+ (ex9) \\tree (\\T S (every) (good boy)
+.br
+ (VP (\\L V(does)) (\\L A(fine)) ))
+.DE
+.sp
+In this example, a triangle is drawn under the S-node, and the
+`does' and `fine' are placed immediately under the `V' and `A'
+with no connecting vertical line.
+(The `\\L' command is also useful for piling up several lines of
+text to avoid using too much horizontal space \- see the ptsample
+file for illustration.)
+.PP
+Other commands are `\\I' for inverting a tree,
+and `\\H' for designating a node as head of a branching
+constituent so that the mother node will be aligned over it.
+`\\R' puts a vertical at the right of a node and aligns upper
+and lower parts of the tree with this vertical, so that the node
+name appears to the left of connecting tree lines.
+`\\B' and `\\B0'-`\\B9' are ``bolding'' commands that vary the
+style of the connecting lines beneath a node.
+.PP
+There are two commands for getting related constituents on
+the same horizontal level.
+`\\F' moves a node with everything under it down, if necessary,
+to get a subtree down to level of the lowest node found elsewhere
+in the tree.
+`\\E' modifies the effect of `\\F' commands by restricting the
+downward displacement to the lowest node found in the subtree
+with the its top node marked `\\E'.
+.PP
+There is also the bare beginning of a facility for drawing
+discontinuous constituents. The line that would ordinarily
+connect a node with the mother above it can be omitted
+with the `\\O' command.
+Alternatively, the line can be omitted with the `\\P' command,
+but then the name is also not displayed (though the tree is
+formatted as though there were a name present).
+Drawing a new line to connect a node
+to a node other than its natural mother requires PostScript
+commands, so it can only be done when using the
+.B \-u
+option (described below).
+You label the mother with `\\M'
+and label the (presumably) discontinuous daughter with `\\D'.
+A curvy line will then be drawn between the mother and the daughter.
+If you need to connect other pairs of nodes, you can add a single
+digit after the `\\M' and `\\D' (giving 10 more pairs of labels).
+Unfortunately, several
+daughters can be connected to the same mother in this way only
+when all the daughters save possibly one come lower in the tree
+than the mother or, if at the same level, to the right of the
+mother.
+It is not possible to connect more than one unnatural mother to a given
+daughter.
+Leaves cannot be unnatural mothers.
+.sp
+.DS
+ (ex10) \\tree (S(PP\\O\\D(near)(him))(NP(John))
+.br
+ (VP\\M(saw)(a snake)))
+.DE
+.sp
+Here a line over `PP' is omitted and a curvy line drawn from the
+top of `PP', since it has the daughter label `\\D', to a position
+under `VP', since it has the corresponding mother label `\\M'.
+.PP
+The
+.I TeX
+code output with the
+.B \-t
+or
+.B \-u
+option is rather primitive, since
+.I tree
+uses a rough approximation for the widths of node names.
+The width of a
+node name is taken to be the number of characters in the name times the
+`en' space of the current font, the `en' space being half an `em' or
+`quad'. Each line of print making up the tree is assumed to be 12
+points high when the current `ex' height is that of Computer Modern
+Roman at 10 points, and is adjusted proportionately for `ex' heights
+different from this.
+.PP
+The approximation for the width of names may be off by quite a bit when
+node names have a lot of capital letters, or when they contain
+.I TeX
+commands.
+To compensate for this,
+.I tree
+adds some extra space for names that have lots of caps,
+and it removes space taken up by
+.I TeX
+commands, on the assumption that
+.I TeX
+commands will not change the width of printed stuff (which
+assumption may easily be wrong, of course).
+.PP
+If you do put font changing commands into node names, it is not
+necessary to group them in braces to confine their effects to the
+node names, since
+.I tree
+adds braces around node names, anyway.
+Every line of a tree is a paragraph, so one way to control left
+indentation is to give `\\parindent' an appropriate value.
+Page breaks are prevented within a tree, so if you have not provided
+enough vertically stretchable space around trees, you may get
+.I TeX
+underfull vbox error messages, or, in the case of a tree too long
+for a page, a fatal error.
+.PP
+The
+.B \-u
+option works like the
+.B \-t
+option, except that for right-side up trees, instead of having
+.I TeX
+draw horizontal and vertical rules, PostScript commands for
+diagonal lines are issued.
+Naturally, this method of obtaining slanty lines is going
+to work only if you have a PostScript printer.
+The PostScript code is stuck inside
+.I TeX
+.B special
+commands, and the dvi-file translator program is expected
+just to include this code in its PostScript output.
+(Not all PS drivers for
+.I TeX
+do this, or do it in the same way.
+If it's a problem, email Greg for a version of
+.I dvi2ps
+that behaves right.)
+.SH BUGS
+Curvy lines from `\\M' and `\\D' are likely to run through node
+names.
+.PP
+The thickness of diagonal lines is not varied with different
+font sizes.
+But you could change it
+.I ad hoc
+by including in the text a command of the form:
+.br
+\ \ \ \ \ `\\special{<num> setlinewidth}'.
+.PP
+Triangles over two or more nodes are not wide enough.
+.PP
+Lowering a node by enclosing it in multiple parentheses just extends
+the vertical line above it, causing a corner with the \-u option.
+A curve would be nicer.
+.PP
+There are undocumented \-d debug and \-h help options.
+.PP
+Terminal nodes of inverted trees that are re-attached to empty nodes
+of a larger construction are not treated correctly by the `\\R'
+command or the \-R option.
+.PP
+A node name in the same row as a very high or deep name will have
+excessive white space above or below it.
+Fonts with small ex-heights have tree lines too close to the tops
+of capitals, and fonts with large ex-heights have them too far away.
+.SH "SEE ALSO"
+tex(1)
+.SH AUTHOR
+Greg Lee, U. Hawaii Dept. of Linguistics, lee@uhccux.uhcc.hawaii.edu
+.PP
+.I Tree
+was inspired by a predecessor program written by Chris Barker,
+Linguistics Board at University of California, Santa Cruz,
+barker@ling.ucsc.edu
diff --git a/graphics/tree/tree.l b/graphics/tree/tree.l
new file mode 100644
index 0000000000..289debbf83
--- /dev/null
+++ b/graphics/tree/tree.l
@@ -0,0 +1,1735 @@
+%{
+/* tree: format trees
+ * Version 1.1 -- Greg Lee, lee@uhccux.uhcc.hawaii.edu, June 24, 1990
+ *
+ * This program is free and in the public domain. Please keep future
+ * versions in the public domain.
+ *
+ * The inspiration for and predecessor to `tree' was a program by
+ * Chris Barker, of the Linguistics Board at University of California,
+ * Santa Cruz, email: barker@ling.ucsc.edu.
+ *
+ * A pattern matching function yylex() is built, which finds tree
+ * definitions in a text; yylex() is called recursively to build
+ * a tree structure in memory; a sequence of formatting operations
+ * is carried out (see printtree()); then the formatted tree is
+ * displayed by tty() or, for TeX code, the function tex().
+ */
+#include <ctype.h>
+
+#define TRUE 1
+#define FALSE 0
+
+/* When formatting for TeX, multiply column widths by this to get better
+ * positioning:
+ */
+#define COLMUL 8
+
+/* The c_ values are from the command line; the real values are taken
+ * from them or from options given after the \tree command.
+ */
+ int tex_opt, c_tex_opt = FALSE; /* generate TeX code? */
+ int utex_opt, c_utex_opt = FALSE;/* generate TeX code with PS? */
+ int gap_opt, c_gap_opt = 2; /* space between subtrees */
+ int black_opt, c_black_opt = 0; /* black triangles */
+ int debug_opt = FALSE; /* tracing? */
+ int quiet_opt, c_quiet_opt = FALSE; /* no warnings */
+ int verbose_opt, c_verbose_opt = FALSE; /* show tex commands? */
+ int lexical_opt, c_lexical_opt = FALSE; /* no lines */
+ int T_opt, c_T_opt = FALSE;
+ int O_opt, c_O_opt = FALSE;
+ int I_opt, c_I_opt = FALSE;
+ int F_opt, c_F_opt = FALSE;
+ int E_opt, c_E_opt = FALSE;
+ int R_opt, c_R_opt = FALSE;
+
+/* count columns before \tree command encountered */
+ int indent = 0;
+/* count caps in name to compensate for extra width */
+ int capscount = 0;
+/* keep track of recursion in yylex() calls to assign nodes to rows */
+ int level = 0;
+ int maxlevel = 0;
+/* source line (not useful now -- need some error checking) */
+ int linenumber = 1;
+
+/* types of nodes */
+#define HBAR 1 /* horizontal bar */
+#define VBAR 2 /* vertical bar */
+#define OBAR 4 /* horizontal overbar */
+#define NODENAME 8 /* named node */
+
+#define NAMEROOM 20000 /* how much to malloc for node names */
+char *buf, *bufp; /* for buffer storing node names */
+
+/* A node has a:
+ * row, from row 1, telling how far from the top of the tree it is;
+ * col, from col 0, how far from the left;
+ * mid, its horizontal mid point, used for vertical alignment;
+ * l, its width in columns;
+ * treeid, an identifying number;
+ * type, whether its a name or a bar of some sort;
+ * attrib, a list of 26 values of attributes bestowed by \<cap>s;
+ * n, pointer to its name if it has one;
+ * and a bunch of pointers to contiguous nodes in the tree.
+ *
+ * Attributes `S' and `U' are used internally; must change this if
+ * there are to be \S or \U commands.
+ */
+typedef struct list {
+ int row, col, mid, l, treeid, type;
+ char attrib[26];
+ char *n;
+ struct list *daughter;
+ struct list *sister;
+ struct list *mother;
+ struct list *right;
+ struct list *left;
+} LIST, *TREE;
+
+/* next number for treeid */
+int treenum = 1;
+
+TREE newnode();
+
+/* global reference by yylex() */
+TREE tree;
+
+#define ERROR(message) fprintf(stderr,"Tree: %s (line %d).\n", \
+ message, linenumber)
+
+/* Next is code for flex to build the yylex() function. There are three
+ * states the pattern matcher can be in:
+ * T, if it's matching text after the \tree command that defines
+ * a tree;
+ * N, if it's echoing text that is not in the scope of a \tree command;
+ * C, if it's discarding comments within the definition of a tree.
+ */
+%}
+
+%s T N C
+
+%%
+<N>\n {
+ indent = 0;
+ linenumber++;
+ ECHO;
+}
+<N>\t {
+ indent++;
+ while (indent % 8) indent++;
+ ECHO;
+}
+<N>. {
+ indent++;
+ ECHO;
+}
+<N>\\tree[ \t\n]*(-([tuvqLTOIFER]+|[bg][0-9]+)[ \t\n]*)*\([ \t\n]* {
+ TREE root;
+
+ setoptions(yytext + 5);
+ level++;
+ if (level > maxlevel) maxlevel = level;
+ root = newnode(level,bufp);
+ tree = root;
+/* do a whole tree: in state T analyze the tree definition
+ * and build the tree; format and display, and resume echoing
+ * text until the next tree definition is found.
+ */
+ BEGIN(T);
+ yylex();
+ printtree(root);
+ maxlevel = 0;
+ BEGIN(N);
+}
+<N>\\tree {
+ if (!quiet_opt) ERROR("ill-formed \\tree command ignored");
+ ECHO;
+}
+<T,C>\([ \t\n]* {
+ TREE node;
+
+ notenewlines(yytext);
+ level++;
+ if (level > maxlevel) maxlevel = level;
+ addchar('\0'); /* terminate last node name */
+ capscount = 0; /* no caps in next name yet */
+ node = newnode(level,bufp);
+/* nodes at same level of embedding are connected together as
+ * sisters; but if current level is greater than that of
+ * the node that was just being made, this next node must be
+ * a daughter of that node.
+ */
+ if (tree->row < level) tree->daughter = node;
+ else tree->sister = node;
+ tree = node;
+ BEGIN(T);
+ yylex();
+ tree = node;
+}
+<T,C>\) {
+ level--;
+ addchar('\0');
+ capscount = 0;
+/* discard text now until the beginning of the next node
+ */
+ BEGIN(C);
+/* this is a return from a yylex() invocation called from yylex().
+ */
+ return;
+}
+<T>[ \t\n]+\\% {
+ notenewlines(yytext);
+ addchar(' ');
+ if (tex_opt || verbose_opt) {
+ addchar('\\');
+ tree->l++;
+ }
+ addchar('%');
+ tree->l += 2;
+}
+<T>\\[%#\&\$] {
+ if (tex_opt || verbose_opt) {
+ addchar('\\');
+ tree->l++;
+ }
+ addchar(yytext[1]);
+ tree->l++;
+}
+<T,C>%.*\n {
+ notenewlines(yytext);
+}
+<T,C>[ \t\n]*%.*\n[ \t\n]*/[\)\(] {
+ notenewlines(yytext);
+}
+<T>\\[MDB][0-9][ \t\n]+ {
+ giveval(tree, yytext[1], yytext[2]);
+}
+<T>\\[MDB][0-9]/[^A-Za-z] {
+ giveval(tree, yytext[1], yytext[2]);
+}
+<T>\\[A-Z][ \t\n]+ {
+ give(tree, yytext[1]);
+}
+<T>\\[A-Z]/[^A-Za-z] {
+ give(tree, yytext[1]);
+}
+<T>\\[ )(\\] {
+ addchar(yytext[1]);
+ tree->l++;
+}
+<T>(\\[`'"^~=.])|(\$[_^]) {
+ if (tex_opt || verbose_opt) {
+ addchar(yytext[0]);
+ addchar(yytext[1]);
+ if (verbose_opt) tree->l += 2;
+ }
+}
+<T>[\${}] {
+ if (tex_opt || verbose_opt) {
+ addchar(yytext[0]);
+ if (verbose_opt) tree->l++;
+ }
+}
+<T>[A-HJ-Z] {
+ addchar(yytext[0]);
+ tree->l++;
+ if (tex_opt && ++capscount > 3) {
+ tree->l++;
+ capscount = 0;
+ }
+}
+<T>. {
+ addchar(yytext[0]);
+ tree->l++;
+}
+<T>\\tree[ \t\n]* {
+ if (!quiet_opt) ERROR("\\tree command found inside tree");
+ notenewlines(yytext);
+ if (tex_opt || verbose_opt) {
+ int i;
+ for (i = 0; i < yyleng; i++) {
+ addchar(yytext[i]);
+ if (verbose_opt) tree->l++;
+ }
+ }
+}
+<T>\\[A-Za-z]+[ \t\n]* {
+ notenewlines(yytext);
+ if (tex_opt || verbose_opt) {
+ int i;
+ for (i = 0; i < yyleng; i++) {
+ addchar(yytext[i]);
+ if (verbose_opt) tree->l++;
+ }
+ }
+}
+
+<T>[ \t\n]+/[\)\(] {
+ notenewlines(yytext);
+}
+<T>[ \t\n]+ {
+ notenewlines(yytext);
+ if (tree->l) {
+ addchar(' ');
+ tree->l++;
+ }
+}
+<C>[^ \t\n\(\)]+ {
+ if (!quiet_opt) ERROR("word after node name ignored");
+}
+<C>. ;
+<C>\n linenumber++;
+
+%%
+
+/* count newlines in string; update linecount; issue warning if
+ * blank line
+ */
+notenewlines(s)
+char *s;
+{ int warn = 0;
+ while (*s) {
+ if (*s == '\n') {
+ if (warn && !quiet_opt)
+ ERROR("blank line within tree");
+ else warn++;
+ linenumber++;
+ }
+ else if (*s != ' ' && *s != '\t') warn = 0;
+ s++;
+ }
+}
+
+/* Called for every \tree in input. Resets option values from defaults
+ * established on command line.
+ */
+setoptions(s)
+char *s;
+{ int c, gap = -1;
+
+ tex_opt = c_tex_opt;
+ utex_opt = c_utex_opt;
+ gap_opt = c_gap_opt;
+ black_opt = c_black_opt;
+ verbose_opt = c_verbose_opt;
+ quiet_opt = c_quiet_opt;
+ lexical_opt = c_lexical_opt;
+ T_opt = c_T_opt;
+ O_opt = c_O_opt;
+ I_opt = c_I_opt;
+ F_opt = c_F_opt;
+ E_opt = c_E_opt;
+ R_opt = c_R_opt;
+
+ while (c = *s++)
+ switch (c) {
+ case 't': tex_opt = TRUE; utex_opt = FALSE; break;
+ case 'u': utex_opt = TRUE; tex_opt = TRUE; break;
+ case 'g': gap = gap_opt = atoi(s); break;
+ case 'b': black_opt = atoi(s); break;
+ case 'v': verbose_opt = TRUE; break;
+ case 'q': quiet_opt = TRUE; break;
+ case 'L': lexical_opt = TRUE; break;
+ case 'T': T_opt = TRUE; break;
+ case 'O': O_opt = TRUE; break;
+ case 'I': I_opt = TRUE; break;
+ case 'F': F_opt = TRUE; break;
+ case 'E': E_opt = TRUE; break;
+ case 'R': R_opt = TRUE; break;
+ case '\n': linenumber++; break;
+ }
+ if (gap >= 0 && tex_opt) gap_opt *= COLMUL;
+}
+
+
+extern char *optarg; /* from getopt */
+extern int optind;
+
+main(argc, argv)
+int argc;
+char *argv[];
+{ int c;
+ char *progname = NULL, *basename();
+
+ if ( (bufp = buf = (char *)malloc(NAMEROOM)) == 0 ) {
+ fprintf(stderr, "can't get memory space\n");
+ exit(1);
+ }
+
+ progname = basename (argv[0]);
+ while ((c = getopt (argc, argv, "hg:tub:vLTOIFERdq")) != EOF)
+ switch (c) {
+ case 'g': c_gap_opt = max(0, atoi(optarg)); break;
+ case 't': c_tex_opt = TRUE; break;
+ case 'u': c_utex_opt = TRUE; c_tex_opt = TRUE; break;
+ case 'b': c_black_opt = max(0, atoi(optarg)); break;
+ case 'v': c_verbose_opt = TRUE; break;
+ case 'd': debug_opt = TRUE; break;
+ case 'q': c_quiet_opt = TRUE; break;
+ case 'L': c_lexical_opt = TRUE; break;
+ case 'T': c_T_opt = TRUE; break;
+ case 'O': c_O_opt = TRUE; break;
+ case 'I': c_I_opt = TRUE; break;
+ case 'F': c_F_opt = TRUE; break;
+ case 'E': c_E_opt = TRUE; break;
+ case 'R': c_R_opt = TRUE; break;
+ case 'h':
+ default:
+ fprintf(stderr, "Usage: %s [options] [files]\n", progname);
+ fprintf(stderr, "options = -gnum\t(gap between subtrees)\n");
+ fprintf(stderr, " -h\t(print this information)\n");
+ fprintf(stderr, " -t\t(TeX code)\n");
+ fprintf(stderr, " -u\t(TeX code w. diagonals)\n");
+ fprintf(stderr, " -bnum\t(black triangles)\n");
+ fprintf(stderr, " -v\t(show TeX commands)\n");
+ fprintf(stderr, " -q\t(quiet)\n");
+ fprintf(stderr, " -L\t(lexical)\n");
+ fprintf(stderr, " -T\t(triangles)\n");
+ fprintf(stderr, " -O\t(omit lines)\n");
+ fprintf(stderr, " -I\t(invert)\n");
+ fprintf(stderr, " -F\t(flatten)\n");
+ fprintf(stderr, " -E\t(even)\n");
+ fprintf(stderr, " -R\t(relational)\n");
+ exit(1);
+ }
+
+ /* doubled column values for tex code */
+ if (c_tex_opt) c_gap_opt *= COLMUL;
+
+ BEGIN(N);
+
+ if (optind >= argc) {
+ (void) yylex ();
+ }
+ else for (; (optind < argc); optind++) {
+ if (yyin == NULL) yyin = stdin;
+ if (freopen (argv[optind], "r", stdin) != NULL) {
+#ifdef FLEX_SCANNER
+ /* to get flex to look at > 1 file */
+ yy_init = 1;
+#endif
+ (void) yylex ();
+ if (level) {
+ fprintf(stderr,"Unbalanced parens in file: %s\n",
+ argv[optind]);
+ exit(1);
+ }
+ }
+ else {
+ (void) fprintf (stderr,
+ "Couldn't open file: %s\n", argv[optind]);
+ exit (1);
+ }
+ }
+ if (level) {
+ fprintf(stderr,"Unbalanced parens.\n");
+ exit(1);
+ }
+}
+
+
+char *basename (s)
+char *s;
+{
+ char *p, *strrchr();
+
+ if (p = strrchr(s, '/'))
+ return(++p);
+ else return(s);
+}
+
+max(a, b)
+int a, b;
+{
+ return ((a > b) ? a : b);
+}
+
+TREE newnode(row, n)
+int row;
+char *n;
+{ TREE temp;
+ int i;
+
+ temp = (TREE) malloc (sizeof (LIST));
+ if (!temp) {
+ ERROR("out of memory");
+ exit(1);
+ }
+ temp->daughter = NULL;
+ temp->sister = NULL;
+ temp->mother = NULL;
+ temp->right = NULL;
+ temp->left = NULL;
+ temp->n = n;
+ temp->l = 0;
+ temp->row = row;
+ temp->col = 0;
+ temp->mid = 0;
+ temp->treeid = treenum++;
+ temp->type = NODENAME;
+ for (i = 0; i < 26; i++) temp->attrib[i] = '\0';
+ if (lexical_opt) give(temp,'L');
+ if (T_opt) give(temp,'T');
+ if (O_opt) give(temp,'O');
+ if (R_opt) give(temp,'R');
+ return (temp);
+}
+
+/* append one node name character in buffer; this is called only
+ * from within yylex().
+ */
+addchar(c)
+char c;
+{
+ *bufp++ = c;
+}
+
+/* after yylex() has built an in-memory tree structure, printtee()
+ * formats and displays it.
+ */
+printtree(root)
+TREE root;
+{ TREE over;
+
+ addbars(root, 0); /* put in VBARs and HBARs */
+ flatbars(root, maxlevel); /* interpret \E and \F commands */
+ rectify(root); /* `left' links for row/col order */
+ addlinks(root); /* miscellaneous initialization */
+ over = newnode(0, NULL); /* preliminary to calling align: */
+ over->daughter = root; /* new node is needed for the */
+ root->mother = root->left = over; /* case of an inverted root */
+ if (I_opt) {
+ /* for side-by-side trees, interpret -I option as meaning that
+ * each tree should be inverted individually
+ */
+ if (root->l) give(root,'I');
+ else if (root->daughter) {
+ TREE node = root->daughter;
+ if (node->type == HBAR) node = node->daughter;
+ if (node->type == VBAR)
+ while (node && node->type == VBAR) {
+ give(node->daughter,'I');
+ node = node->sister;
+ }
+ else while (node) {
+ give(node,'I');
+ node = node->sister;
+ }
+ }
+ }
+ align(root); /* assign column values for */
+ /* vertical alignment */
+ root = over->daughter; /* root will be a different node */
+ /* if it was just inverted */
+ free(over);
+ if (debug_opt) {
+ fprintf(stderr,"\n\n\t------ROOT------\n");
+ debugprint(root);
+ }
+ if (!root->l) { /* remove empty top nodes to get */
+ /* side-by-side trees */
+ TREE old;
+ if (root->daughter) {
+ old = root;
+ root = root->daughter;
+ free(old);
+ }
+ if (root->type == HBAR && root->daughter) {
+ TREE node;
+ old = root;
+ root = root->daughter;
+ free(old);
+ /* mothers of roots are made NULL to block the middle
+ * vertical of an HBAR for tty output
+ */
+ if (root->type == VBAR && root->daughter) {
+ for (node = root; node; node = node->sister)
+ if (node->daughter) node->daughter->mother = NULL;
+ old = root;
+ root = root->daughter;
+ free(old);
+ }
+ }
+ else if (root->type == VBAR && root->daughter) {
+ old = root;
+ root = root->daughter;
+ free(old);
+ }
+ root->mother = NULL;
+ }
+ if (tex_opt) tex(root); /* now display */
+ else tty(root);
+ bufp = buf; /* can reuse name buffer for next tree */
+ freenodes(root);
+}
+
+freenodes(tree)
+TREE tree;
+{ TREE next;
+
+ while (tree) {
+ next = tree->right;
+ free(tree);
+ tree = next;
+ }
+}
+
+
+/* b is from the value given for the -b option */
+int b;
+/* these are the characters used to draw screen trees; the arrays
+ * are indexed by variable b above
+ */
+char tf[] = "_-:|::|-|*"; /* triangle fill */
+char itf[] = "~-:|::|-|*"; /* inverted triangle fill */
+char vb[] = "||:|::||||"; /* vertical bar */
+char lhb[] = "_-.|:._<//"; /* left part of horizontal bar */
+char rhb[] = "_-.|:._>\\\\"; /* right part of horizontal bar */
+char ilhb[] = "~-\"|:\"^<\\\\";/* left of inverted horizontal bar */
+char irhb[] = "~-\"|:\"^>//"; /* right of inverted horizontal bar */
+char lvb[] = "_-.|://<//"; /* left of vertical centerpiece */
+char mvb[] = " +:|: "; /* middle of vertical centerpiece */
+char rvb[] = "_+.|:\\\\>\\\\";/* right of vertical centerpiece */
+char lcb[] = " |:|://///"; /* vertical for left sister */
+char rcb[] = " |:|:\\\\\\\\\\";/* vertical for right sister */
+char lchb[] = "_+ |: "; /* left corner of horizontal bar */
+char rchb[] = "_+ |: "; /* right corner of horizontal bar */
+char ilchb[] = "_+ |: "; /* left corner of inv'd horizontal bar */
+char irchb[] = "_+ |: "; /* right corner of inv'd horizontal bar */
+
+
+/* display tree for screen */
+tty(root)
+TREE root;
+{ TREE node;
+ int row = root->row, col = 0, i;
+
+ if (debug_opt) {
+ putchar('\n');
+ for (col = 0; col < indent; col++) putchar(' ');
+ col = 0;
+ }
+
+ /* display each node, left-to-right and top-to-bottom */
+ for (node = root; node; node = node->right) {
+
+ /* boldness is from \B command or -b option */
+ if (b = has(node,'B')) {
+ if (b == '+') b = 9;
+ else if (isdigit(b)) b -= '0';
+ else b = 0; /* presumably impossible */
+ }
+ else for (b = black_opt; b > 10; b /= 10) ;
+
+ /* newline and indentation */
+ if (node->row > row) {
+ while (node->row > row) { putchar('\n'); row++; }
+ for (col = 0; col < indent; col++) putchar(' ');
+ col = 0;
+ }
+
+ /* spacing between nodes */
+ for ( ; node->col > col; col++) putchar(' ');
+
+ /* disconnect illegitimate sisters created by inversion */
+ if (node->sister && node->sister->mother != node->mother)
+ node->sister = NULL;
+
+ /* display a node in a way appropriate to its type */
+ switch (node->type) {
+ case NODENAME:
+ if (has(node,'P')) /* space over phantom node */
+ for (i = 0; i < node->l; i++) putchar(' ');
+ else printf("%s", node->n);
+ break;
+ case VBAR:
+ /* join all verticals at the base of a triangle */
+ if (has(node,'T') && !has(node,'O')) {
+ char hbar = tf[b];
+ /* no vertical if this is not the first or
+ * only sister
+ */
+ if (has(node,'S') != 'f'
+ && has(node,'S') != 'o') {
+ for (i = 0; i < node->l; i++)
+ putchar(' ');
+ break;
+ }
+ /* use special fill character for base of
+ * inverted triangle
+ */
+ if (node->mother && node->mother->type == OBAR)
+ hbar = itf[b];
+ /* make left edge of base */
+ putchar(vb[b]);
+ /* when only one node at base, length of base
+ * is length of node
+ */
+ if (has(node,'S') == 'o')
+ for (i = 2; i < node->l; i++)
+ putchar(hbar);
+ /* but when there are several nodes at the
+ * base, the base goes from the first to the
+ * last sister
+ */
+ else {
+ while (node->sister
+ && node->mother == node->sister->mother
+ && has(node,'S') != 'l'
+ && node->sister->type == VBAR)
+ node = node->sister;
+ for ( ; node->col > col+1; col++)
+ putchar(hbar);
+ col++;
+ }
+ /* make the right edge of the base */
+ putchar(vb[b]);
+ break;
+ } /* end of code for triangle bases */
+
+ /* space over omitted or phantom lines */
+ if (has(node,'O') || has(node,'P')) putchar(' ');
+ /* possibly do a bold vertical */
+ else if (!blackvbar(node))
+ /* do a plain vertical */
+ putchar(vb[b]);
+ break;
+
+ case HBAR:
+ /* possibly do a bold hbar */
+ if (node->l >= 4 && blackhbar(node)) break;
+ /* otherwise, make the left side, */
+ for (i = 0; i < node->mid; i++) putchar(lhb[b]);
+ /* ... then the middle */
+ if (node->mother) putchar(vb[b]);
+ else putchar(lhb[b]);
+ /* ... then the right side */
+ for (i = 0; i < node->l - node->mid - 1; i++)
+ putchar(rhb[b]);
+ break;
+
+ case OBAR:
+ /* similar to hbar, above */
+ if (node->l >= 4 && blackobar(node)) break;
+ for (i = 0; i < node->mid; i++) putchar(ilhb[b]);
+ if (node->mother && node->right) putchar(vb[b]);
+ else putchar(ilhb[b]);
+ for (i = 0; i < node->l - node->mid - 1; i++)
+ putchar(irhb[b]);
+ break;
+ } /* end of switch */
+
+ col += node->l;
+
+ } /* end of loop to display each node */
+}
+
+
+/* draw horizontal bar with corners missing and a centerpiece */
+blackhbar(node)
+TREE node;
+{ int i, lless;
+
+ /* don't do it if no boldness requested or a \Head has forced
+ * the "midpoint" of the hbar to one end
+ */
+ if (!b || !node->mid || node->mid +1 >= node->l) return(FALSE);
+
+ /* make the center of the bar a little to the left, usually,
+ * for even-length bars, so the two parts of the centerpiece
+ * tend to come under the middle two characters of the name above
+ */
+ lless = (node->l % 2 && b < 8) ? 2 : 1;
+
+ /* the left corner */
+ putchar(lchb[b]);
+
+ /* the left segment before the centerpiece */
+ for (i = lless; i < node->mid; i++) putchar(lhb[b]);
+
+ /* lower levels of bolding look better with a one-char
+ * centerpiece
+ */
+ if (b < 3) {
+ if (lless == 2) putchar(lhb[b]);
+ putchar(mvb[b]);
+ putchar(rhb[b]);
+ }
+ else {
+ /* the two-char centerpiece */
+ putchar(lvb[b]);
+ if (lless == 2) putchar(mvb[b]);
+ putchar(rvb[b]);
+ }
+
+ /* now the right segment before the corner */
+ for (i = 3; i < node->l - node->mid; i++)
+ putchar(rhb[b]);
+
+ /* finally the right corner */
+ putchar(rchb[b]);
+
+ /* yes, we did one */
+ return(TRUE);
+}
+
+/* as above, but for inverted trees */
+blackobar(node)
+TREE node;
+{ int i, lless;
+
+ if (!b || !node->mid || node->mid +1 >= node->l) return(FALSE);
+
+ lless = (node->l % 2 && b < 8) ? 2 : 1;
+ putchar(ilchb[b]);
+ for (i = lless; i < node->mid; i++) putchar(ilhb[b]);
+ if (b < 3) {
+ if (lless == 2) putchar(ilhb[b]);
+ putchar(mvb[b]);
+ putchar(irhb[b]);
+ }
+ else {
+ if (b == 7) putchar(lvb[b]);
+ else putchar(rvb[b]);
+ if (lless == 2) putchar(mvb[b]);
+ if (b == 7) putchar(rvb[b]);
+ else putchar(lvb[b]);
+ }
+ for (i = 3; i < node->l - node->mid; i++)
+ putchar(irhb[b]);
+ putchar(irchb[b]);
+ return(TRUE);
+}
+
+/* draw corner sisters appropriate to horizontal above them */
+blackvbar(node)
+TREE node;
+{
+ /* don't do it when no boldness was asked for, or there is
+ * no node name above, or the hbar above was too short to
+ * be made bold
+ */
+ if (!b || !node->mother || node->mother->l < 4)
+ return(FALSE);
+ /* mark heads */
+ if (b >= 5 && has(node,'H')) {
+ putchar('*');
+ return(TRUE);
+ }
+ /* if it's the first sister, use a corner char */
+ if (has(node,'S') == 'f') {
+ if (node->mother->type == HBAR) {
+ putchar(lcb[b]);
+ return(TRUE);
+ }
+ if (node->mother->type == OBAR) {
+ putchar(rcb[b]);
+ return(TRUE);
+ }
+ }
+ /* likewise if its the last sister, but use the other corner char */
+ else if (has(node,'S') == 'l') {
+ if (node->mother->type == HBAR) {
+ putchar(rcb[b]);
+ return(TRUE);
+ }
+ if (node->mother->type == OBAR) {
+ putchar(lcb[b]);
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+}
+
+/* take care of spacing between daughters of a branching node, and
+ * figure width of the sisters; called by align()
+ */
+sisterbal(tree)
+TREE tree;
+{
+ TREE temp, first, last, head = NULL;
+ int hblen, rlen, bestspace, space, numdaughters = 1, leeway;
+ int join = FALSE;
+
+ /* figure which sisters are to be covered by the bar; mark them
+ * for convenience later in display routines
+ */
+ for (first = tree->daughter; has(first,'O') && first->sister;
+ first = first->sister);
+ for (last = first; last->sister; last = last->sister);
+ while (has(last,'O') && last != first) last = last->left;
+ giveval(first,'S','f');
+ giveval(last,'S','l');
+
+ /* look for heads and nodes that came from the bottom of inverted
+ * subtrees -- we must not try to balance the latter
+ */
+ for (temp = first; temp != last; temp = temp->sister) {
+ numdaughters++ ;
+ if (has(temp, 'H')) head = temp;
+ if (has(temp->sister, 'H')) head = temp->sister;
+ if (has(temp, 'I') == 2) join = TRUE;
+ if (has(temp->sister, 'I') == 2) join = TRUE;
+ }
+
+ /* first approximation to the length of the bar */
+ hblen = (last->col + last->l) - first->col;
+ rlen = (last->col + last->mid + 1/*COLMUL*/) - (first->col + first->mid);
+
+ /* first, try to adjust in a way that does not require
+ * widening the bar
+ */
+ if (numdaughters > 2) bestspace = rlen / (numdaughters - 1);
+ else bestspace = 0;
+ if (!join) for (temp = first; temp != last; temp = temp->sister) {
+ space = temp->sister->col + temp->sister->mid
+ - (temp->col + temp->mid);
+ leeway = rightroom(temp) - gap_opt;
+ if (temp == first && numdaughters == 2) leeway /= 2;
+ if (space > bestspace && leeway > 0) {
+ space -= bestspace;
+ if (space > leeway) space = leeway;
+ moveright(temp, space);
+ if (temp == first) {
+ hblen = (last->col + last->l)
+ - tree->daughter->col;
+ rlen = (last->col + last->mid + 1/*COLMUL*/)
+ - (first->col + first->mid);
+ bestspace = rlen / (numdaughters - 1);
+ }
+ }
+ }
+ bestspace = 0;
+
+ /* then look for the widest space between adjacent sisters, and
+ * widen the space between others to match
+ */
+ if (!join) for (temp = first; temp != last; temp = temp->sister) {
+ if ((space = temp->sister->col + temp->sister->mid
+ - (temp->col + temp->mid)) > bestspace)
+ bestspace = space;
+ }
+ if (!join) for (temp = first; temp != last; temp = temp->sister) {
+ if ((space = temp->sister->col + temp->sister->mid
+ - (temp->col + temp->mid)) < bestspace)
+ moveright(temp->sister, bestspace - space);
+ }
+
+ /* triangles with a single node at their bases are a special case */
+ if (last == first && last->daughter) {
+ hblen = last->daughter->l;
+ last->l = last->daughter->l;
+ last->col = last->daughter->col;
+ giveval(last,'S','o');
+ }
+ /* revise hbar length and fill in lengths */
+ else hblen = (last->col + last->l) - first->col;
+ tree->l = hblen;
+ if (head) tree->mid = head->col + head->mid - first->col;
+ else tree->mid = (hblen - 1) / 2;
+/* ( arguably, when slanty lines will be drawn, the length of the
+ * hbar should be a little less -- must try this some day )
+ */
+
+ /* if the left edge of the hbar is to the right of the left
+ * edge of the first sister, align all the sisters now
+ */
+ if ((space = tree->col - first->col) > 0) {
+ for (temp = tree->daughter; temp; temp = temp->sister)
+ moveright(temp, space);
+ return(0);
+ }
+ /* otherwise, tell align() to move the hbar to the right */
+ return(space);
+}
+
+/* assign col values to nodes for appropriate vertical alignments;
+ * also call for inversion of trees with \Is
+ */
+align(tree)
+TREE tree;
+{ int diff, thisrow;
+ TREE offspring, invert();
+
+ if (tree) {
+ /* the vbar of a relational node has already been aligned */
+ if (has(tree,'R') && tree->type == VBAR) return;
+
+ /* every node has to go at least far enough to the right to
+ * avoid bumping into the node on the left (if any)
+ */
+ if (tree->left && tree->left->row == tree->row)
+ tree->col = tree->left->col + tree->left->l + gap_opt;
+ else tree->col = 0;
+
+ /* force relational nodes to align on the vbar, by artifically
+ * considering the vbar to be at the "midpoint" of the node
+ */
+ if (has(tree,'R') && tree->type == NODENAME && tree->sister) {
+ tree->sister->col = tree->col + tree->l + gap_opt/4;
+ tree->mid = tree->sister->col + tree->sister->mid - tree->col;
+ }
+
+ /* for non-terminal nodes, align the lower parts of the tree
+ * (cyclically), and calculate the displacement required to
+ * line this tree up above its offspring
+ */
+ if (offspring = tree->daughter) {
+ align(offspring);
+ offspring = tree->daughter; /* may have different tree if inverted*/
+ diff = 0;
+ if (tree->type == HBAR) {
+ /* do not change alignment of the top (formerly bottom)
+ * parts of an inverted subtree, since they are already
+ * properly aligned with nodes below them; but the whole
+ * subtree can be moved by its top left node
+ */
+ if (has(tree,'I') == 1) diff = tree->col - offspring->col;
+ else diff = sisterbal(tree);
+ }
+ /* the case of sisters which are not under an hbar can arise
+ * through use of \L; we center the tree over them
+ */
+ else if (has(offspring,'I') != 2 && has(offspring,'I') != 3
+ && offspring->sister && !has(offspring->sister,'R')) {
+ TREE temp, first, last;
+ for (first = offspring; has(first,'O') && first->sister;
+ first = first->sister);
+ for (last = first; last->sister; last = last->sister);
+ if (last == first) first = offspring;
+ else while (has(last,'O') && last != first) last = last->left;
+ for (temp = first; ; temp = temp->sister) {
+ if (has(temp,'H')) first = last = temp;
+ if (temp == last) break;
+ }
+ diff = tree->col + tree->mid
+ - (first->col + first->mid
+ + last->col + last->mid)/2;
+ }
+ /* here the tree has a single daughter; line up the midpoints */
+ else {
+ /* this propagates a mark up the tree that tells the
+ * sisterbal() routine not to change the alignment of
+ * an empty node that has been attached to part of an
+ * inverted tree, because that would undo the work we
+ * did in attaching it
+ */
+ if (has(offspring,'I') == 2) giveval(tree,'I',2);
+ diff = tree->col + tree->mid
+ - (offspring->col + offspring->mid);
+ }
+
+ /* now actually do the alignment by moving either the tree
+ * or the offspring to the right, whichever is required
+ */
+ if (diff > 0) {
+ moveright(offspring, diff);
+ /* move the bar at the right of a relational node along
+ * with the node
+ */
+ if (has(offspring->sister,'R')
+ && offspring->sister->type == VBAR)
+ offspring->sister->col += diff;
+ /* this is a duplication of effort, I think, but it does
+ * have to be done here
+ */
+ else align(offspring->sister);
+ }
+ else if (diff < 0) {
+ tree->col -= diff;
+ if (has(tree->sister,'R')) tree->sister->col -= diff;
+ }
+ }
+
+ /* in the case of a terminal node, there is ordinarily nothing
+ * to do, but it may be possible to align empty nodes with parts of
+ * an inverted subtree beneath them
+ */
+ else if (tree->type == VBAR) { /* a terminal vbar is an "empty node" */
+ /* An inverted subtree is connected to the rest by its upper left
+ * corner, which as been conveniently marked with an I-attribute
+ * value of 3. We are going work our way to the left along the
+ * current row looking for such a corner, then if we find one,
+ * go down one row to the top row of the inverted subtree and
+ * work our way right an equal number of nodes to find a node to
+ * align with. After the corner, nodes in this top row have been
+ * marked with an I-attribute value of 2, so we can tell when
+ * the search has failed.
+ */
+ TREE node = tree, invh = NULL;
+ int bcount = 1;
+ /* first work our way left: */
+ while (node->left && node->left->row == node->row) {
+ if (debug_opt)
+ printf("\nAL: at #%d going left to #%d.",
+ node->treeid,node->left->treeid);
+ if (has(node->left->daughter,'I') == 3) {
+ invh = node->left->daughter;
+ break;
+ }
+ else {
+ node = node->left;
+ bcount++;
+ }
+ }
+ /* then right an equal distance along top of inverted tree */
+ while (bcount && invh && has(invh->sister,'I') == 2) {
+ if (debug_opt)
+ printf("\nAL: at #%d going right to #%d.",
+ invh->treeid,invh->sister->treeid);
+ invh = invh->sister;
+ bcount--;
+ }
+ /* have we found one? yes, if we're still in the inverted
+ * tree and the node is not to the left of us (we can't
+ * move this tree node to the left -- only to the right)
+ */
+ if (has(invh,'I') == 2 && tree->col + tree->mid <= invh->col + invh->mid) {
+ if (debug_opt)
+ printf("\naligning #%d over #%d.\n",
+ tree->treeid,invh->treeid);
+ /* do the alignment */
+ tree->col = invh->col + invh->mid - tree->mid;
+ /* mark as not subject to balancing by sisterbal() */
+ giveval(tree,'I',2);
+ }
+ } /* end alignment of terminal node */
+
+ /* if inversion was requested, do it */
+ if (has(tree,'I') == '+')
+ tree = invert(tree);
+
+ /* recurse left-to-right */
+ align(tree->sister);
+ }
+}
+
+/* do inversion of a tree; much global info in the tree has to be
+ * kept correct, so this is hard; the actual inversion is done
+ * by inv(); invert() is called by align() just above
+ */
+TREE invert(tree)
+TREE tree;
+{ TREE mother, sister, node, inv();
+
+ /* make all nodes in each row sisters; makes inversion easier,
+ * and makes it possible later to move the inverted tree around from
+ * above
+ */
+ makelbranch(tree);
+ /* save these links for later reattachment */
+ mother = tree->mother;
+ sister = tree->sister;
+ tree->sister = NULL;
+ tree = inv(tree, NULL);
+ /* in the special case where a tree has VBARs at the top
+ * after inversion, put an HBAR over the VBARs
+ */
+ if (tree->sister && mother && mother->type == VBAR
+ && tree->type == VBAR && tree->sister->type == VBAR
+ && (!mother->mother || mother->mother->type != HBAR)) {
+ TREE last;
+ for (last = tree->sister;
+ last->sister && last->sister->type == VBAR;
+ last = last->sister)
+ last->mother = mother;
+ last->mother = mother;
+ mother->type = HBAR;
+ giveval(mother,'I',1);
+ mother->l = last->col + last->l - tree->col;
+ mother->mid = (mother->l - 1)/2;
+ }
+ /* otherwise mark the top row so align() can tell that these
+ * nodes are at the top of an inverted tree and can find the
+ * top left corner
+ */
+ else if (mother && !(mother->type == VBAR && has(mother,'O'))) {
+ for (node = tree; node; node = node->sister)
+ giveval(node,'I',2);
+ giveval(tree,'I',3);
+ }
+ /* it's possible that inversion has caused parts of the inverted
+ * tree to bump against things to the left; now check for this
+ * and, to preserve internal alignment, when necessary move the
+ * entire subtree to the right
+ */
+ for (node = tree; node; node = node->daughter) {
+ TREE temp;
+ int room;
+ if (node->left && node->left->row == node->row)
+ if ((room = node->left->col + node->left->l + gap_opt
+ - node->col) > 0)
+ for (temp = tree; temp; temp = temp->sister)
+ moveright(temp, room);
+ }
+ /* if this corner of the tree is a vbar, should a line be drawn
+ * to an hbar above, or an obar below? maybe both -- I really
+ * don't know
+ */
+ tree->mother = mother; /* ?? */
+
+ /* in -L trees, following not quite right */
+ if (mother) {
+ mother->daughter = tree;
+ }
+ /* reattach former sister to rightmost sister of top */
+ while (tree->sister) tree = tree->sister;
+ tree->sister = sister;
+
+ return(tree);
+}
+
+/* see how much a tree could be moved to the right without coming
+ * too close to anything following; called by sisterbal()
+ */
+rightroom(west)
+TREE west;
+{ int mingap = 10000, gap;
+ TREE node, south = NULL;
+
+ if (west) south = west->daughter;
+ else return(0);
+ while (west) {
+ if (west->right && west->row == west->right->row) {
+ gap = west->right->col - west->col - west->l;
+ if (gap < mingap) mingap = gap;
+ }
+ node = south;
+ south = west = NULL;
+ while (node) {
+ west = node;
+ if (node->daughter) south = node->daughter;
+ node = node->sister;
+ }
+ }
+ return(mingap);
+}
+
+/* move a tree right by increasing col values */
+moveright(tree, amount)
+TREE tree;
+int amount;
+{
+ while (tree) {
+ tree->col += amount;
+ if (tree = tree->daughter) {
+ TREE sis;
+ sis = tree->sister;
+ while (sis) {
+ moveright(sis, amount);
+ sis = sis->sister;
+ }
+ }
+ }
+}
+
+/* flip a tree organized as a stack of linked sets of sisters, keeping
+ * left and right links correct; gah!; called by invert()
+ */
+TREE inv(tree,rest)
+TREE tree, rest;
+{ TREE temp, node, right, left, last, lastd;
+ int row;
+
+ if (tree) {
+ temp = tree->daughter;
+ tree->daughter = rest;
+
+ for (node = tree; node; node = node->sister) {
+ if (node->type == HBAR) node->type = OBAR;
+ else if (node->type == OBAR) node->type = HBAR;
+ else if (node->type == VBAR) {
+ /* this is so texvbar() can tell when to invert
+ * arrows when bold verticals have been requested
+ */
+ if (has(node,'U') == 'i') giveval(node,'U','u');
+ else giveval(node,'U','i');
+ }
+ }
+
+ row = tree->row;
+ for (last = tree; last->sister; last = last->sister) ;
+ right = last->right;
+ left = tree->left;
+ node = tree;
+ while (node && node->daughter) {
+ for (last = node; ;) {
+ last->row = node->daughter->row;
+ if (!last->sister) break;
+ last = last->sister;
+ }
+ for (lastd = node->daughter; lastd->sister;
+ lastd = lastd->sister) ;
+ if (lastd->right) last->right = lastd->right;
+ else last->right = node->daughter;
+ if (node->daughter->left)
+ node->left = node->daughter->left;
+ last->right->left = last;
+ if (node->left) node->left->right = node;
+ node = node->daughter;
+ }
+ if (left) node->left = left;
+ else node->left = last;
+ for (last = node; ;) {
+ last->row = row;
+ if (!last->sister) break;
+ last = last->sister;
+ }
+ last->right = right;
+ if (right) right->left = last;
+ if (left) left->right = node;
+
+ if (debug_opt) { fprintf(stderr,"\n\nCalled inv():\n");
+ debugprint(tree); }
+ return(inv(temp,tree));
+ }
+ else return(rest);
+}
+
+/* convert a tree to left-branching; this is a preliminary to inverting a tree;
+ * called by invert()
+ */
+makelbranch(tree)
+TREE tree;
+{ TREE node, east, west, south, last;
+
+ east = west = tree;
+ while (tree) {
+ for (node = east, last = south = NULL; ; node = node->right) {
+ if (node->daughter) {
+ last = node->daughter;
+ if (!south) south = node->daughter;
+ node->daughter = NULL;
+ }
+ if (node == west) break;
+ else node->sister = node->right;
+ }
+ if (west->right == south) west->right = NULL;
+ if (south && south->left == west) south->left = NULL;
+ while (last && last->sister) last = last->sister;
+ west = last;
+ east->daughter = south;
+ tree = east = south;
+ }
+}
+
+/* initialize some links to contiguous nodes, and also lengths and
+ * mid column values
+ */
+addlinks(tree)
+TREE tree;
+{
+ while (tree) {
+ if (tex_opt) tree->l *= COLMUL;
+ tree->mid = (tree->l - 1) / 2;
+ if (tree->right) tree->right->left = tree;
+ if (tree->daughter) tree->daughter->mother = tree;
+ if (tree->sister) tree->sister->mother = tree->mother;
+ tree = tree->right;
+ }
+}
+
+/* for debugging */
+printnode(node)
+TREE node;
+{ int i;
+
+ if (!node) {
+ fprintf(stderr,"NIL");
+ return;
+ }
+ if (node->type == VBAR)
+ fprintf(stderr,"#%d | at %d/%d", node->treeid,
+ node->col, node->row);
+ else if (node->type == HBAR)
+ fprintf(stderr,"#%d _|_ at %d/%d", node->treeid,
+ node->col, node->row);
+ else if (node->type == OBAR)
+ fprintf(stderr,"#%d ^|^ at %d/%d", node->treeid,
+ node->col, node->row);
+ else fprintf(stderr,"#%d=%s at %d/%d", node->treeid, node->n,
+ node->col, node->row);
+ fprintf(stderr,"[");
+ for (i = 0; i < 26; i++) {
+ char c;
+ if ((c = node->attrib[i]) == '+')
+ fprintf(stderr,"%c", 'A'+i);
+ else if (c)
+ fprintf(stderr,"%c=%d", 'A'+i, c);
+ }
+ fprintf(stderr,"]");
+}
+
+/* for debugging */
+debugprint(tree)
+TREE tree;
+{
+ if (tree) {
+ debugprint(tree->daughter);
+ printnode(tree);
+ if (tree->daughter) {
+ fprintf(stderr," DAUGHTER:");
+ printnode(tree->daughter);
+ }
+ if (tree->sister) {
+ fprintf(stderr," SISTER:");
+ printnode(tree->sister);
+ }
+ fprintf(stderr,"\n ");
+ if (tree->mother) {
+ fprintf(stderr," MOM:");
+ printnode(tree->mother);
+ }
+ if (tree->left) {
+ fprintf(stderr," LEFT:");
+ printnode(tree->left);
+ }
+ if (tree->right) {
+ fprintf(stderr," RIGHT:");
+ printnode(tree->right);
+ }
+ fprintf(stderr,"\n");
+ debugprint(tree->sister);
+ }
+}
+
+/* create new VBAR or HBAR node; called by addbars() */
+TREE newbar(model, row, bartype)
+TREE model;
+int row, bartype;
+{ TREE temp;
+ int i;
+
+ temp = newnode(row, NULL);
+ temp->type = bartype;
+ temp->l = 1;
+ for (i = 0; i < 26; i++) temp->attrib[i] = model->attrib[i];
+
+ /* bars get the following attributes only when above empty
+ * nodes (and that is done in addbars() when a NODENAME is
+ * removed)
+ */
+ giveval(temp,'F',0);
+ giveval(temp,'I',0);
+ giveval(temp,'R',0);
+
+ return(temp);
+}
+
+/* test node for value of attribute */
+has(tree, attrib)
+TREE tree;
+char attrib;
+{
+ if (tree && attrib >= 'A' && attrib <= 'Z')
+ return(tree->attrib[attrib - 'A']);
+ else return(0);
+}
+
+/* give value of attribute to node */
+giveval(tree, attrib, val)
+TREE tree;
+char attrib, val;
+{ int prev;
+
+ if (tree && attrib >= 'A' && attrib <= 'Z') {
+ prev = tree->attrib[attrib - 'A'];
+ tree->attrib[attrib - 'A'] = val;
+ return(prev);
+ }
+ else return(0);
+}
+
+/* give `+' value of attribute to node */
+give(tree, attrib)
+TREE tree;
+char attrib;
+{
+ return(giveval(tree, attrib, '+'));
+}
+
+/* stick in VBARs above name nodes, and HBARs under branching nodes;
+ * also remove empty name nodes
+ */
+addbars(tree, addrows)
+TREE tree;
+int addrows;
+{ TREE kin, mother, node, temp;
+ int numsisters;
+
+ if (tree) {
+ /* account for new rows created above by adding bars */
+ tree->row += addrows;
+ /* I don't think maxlevel is used now, but may as well
+ * keep it up to date
+ */
+ if (tree->row > maxlevel) maxlevel = tree->row;
+ /* add no bars directly under node with \L */
+ if (has(tree,'L')) {
+ /* for -F option, propagate F attribute up from a
+ * terminal to dominating \L nodes
+ */
+ if (F_opt && tree->daughter
+ && !has(tree->daughter->daughter,'F')) {
+ give(tree,'F'); /* work up through higher \L nodes */
+ giveval(tree->daughter,'F',0);
+ }
+ /* save reference for following business with R nodes */
+ node = tree;
+ /* go down and add bars to lower parts of tree */
+ tree = tree->daughter;
+ while (tree) {
+ addbars(tree, addrows);
+ tree = tree->sister;
+ }
+ /* for -R, propagate absence of R attribute up from
+ * terminals to dominating \L nodes
+ */
+ if (R_opt && !has(node->daughter,'R'))
+ giveval(node,'R',0);
+ }
+ /* no \L command, so unless this is a terminal, we do want to
+ * add bars under it -- either just a vbar, or for branching
+ * nodes, an hbar and under that a vbar for each sister
+ */
+ else if (tree->daughter) {
+ kin = mother = tree;
+ tree = tree->daughter;
+ /* nodes with \O will not be covered by an hbar, so count
+ * the sisters that will be covered, to decide whether
+ * this should appear as a branching node
+ */
+ for (node = tree, numsisters = 0; node; node = node->sister)
+ if (!has(node,'O')) numsisters++;
+ /* for tty output, a triangle base needs 3 characters,
+ * and for triangles over single daughter nodes, the name
+ * may be too short
+ */
+ if (!tex_opt && numsisters < 2 && tree->l < 3)
+ giveval(kin,'T',0);
+ /* triangles over single daughters do need an hbar, but
+ * otherwise unless there are at least 2 sisters to cover,
+ * no hbar is needed
+ */
+ if (numsisters > 1 || (has(kin,'T')
+ /* need at least one node at base */
+ && numsisters
+ /* a vbar cannot serve as a good base */
+ && tree->l
+ /* would get odd results over inverted tree */
+ && !has(tree,'I')
+ )
+ ) {
+ /* auto-evening for all branching nodes */
+ if (E_opt) give(kin,'E');
+ /* make the hbar and attach it */
+ temp = newbar(kin, tree->row + addrows, HBAR);
+ temp->mother = mother;
+ mother = temp;
+ temp->daughter = tree;
+ kin->daughter = temp;
+ /* shift lower parts of tree down one row */
+ addrows++;
+ kin = temp;
+ }
+ /* now add a vbar above the daughter and each sister */
+ while (tree) {
+ temp = newbar(tree, tree->row + addrows, VBAR);
+ /* whether a vbar is part of a triangle is determined
+ * by node above, not the one below it, and similarly
+ * for bolding and \M labels
+ */
+ giveval(temp,'T',0);
+ giveval(temp,'B',has(mother,'B'));
+ giveval(temp,'M',0);
+ if (mother->type == NODENAME)
+ giveval(temp,'M',has(mother,'M'));
+ if (has(mother,'T') && mother->type == HBAR && !has(temp,'O')) give(temp,'T');
+
+ /* attach the new bar */
+ temp->mother = mother;
+ if (tree == kin->daughter) kin->daughter = temp;
+ else kin->sister = temp;
+ /* finish attachment and work down the tree if this
+ * is a non-empty node
+ */
+ if (tree->l) {
+ temp->daughter = tree;
+ tree->mother = temp;
+ addbars(tree, addrows+1);
+ }
+ /* but if it is an empty node, discard it after copying
+ * attributes that we wouldn't want to lose
+ */
+ else {
+ addbars(tree, addrows);
+ temp->daughter = tree->daughter;
+ if (tree->daughter) tree->daughter->mother = temp;
+ if (has(tree,'F')) give(temp,'F');
+ if (has(tree,'I')) give(temp,'I');
+ giveval(temp,'M',has(tree,'M'));
+ free(tree);
+ }
+ /* make the single-noded base of a triangle wide enough
+ * to cover the name below it, and cause the apex of
+ * such a triangle to be moved downward together with
+ * its base in case there is flattening
+ */
+ if (has(temp,'T') && numsisters == 1) {
+ temp->l = tree->l;
+ if (has(tree,'F')) {
+ give(kin,'F');
+ giveval(tree,'F',0);
+ }
+ }
+ /* vbar takes over any link to sister at right */
+ kin = temp;
+ temp = tree->sister;
+ tree->sister = NULL;
+
+ /* add vertical to the right of relational node */
+ if (has(tree,'R') && tree->type == NODENAME && tree->l
+ && (!has(tree,'L') || has(tree->daughter,'R'))) {
+ TREE rtemp;
+ rtemp = newbar(tree, tree->row, VBAR);
+ give(rtemp,'R');
+ giveval(rtemp,'T',0);
+ giveval(rtemp,'O',0);
+ tree->sister = rtemp;
+ }
+ /* now loop to add vbar to sister, if any */
+ tree = temp;
+ }
+ }
+ /* here it's a terminal node; do flatten it if -F option,
+ * but don't automatically display it as relational for -R opt.
+ */
+ else {
+ if (F_opt) give(tree,'F');
+ if (R_opt) giveval(tree,'R',0);
+ }
+ } /* if (tree) */
+}
+
+/* find lowest node in tree, ignoring inverted subtrees */
+howlow(tree)
+TREE tree;
+{ int row, low = 0;
+
+ while (tree) {
+ if (tree->row > low) low = tree->row;
+ tree = tree->daughter;
+ if (tree && (row = howlow(tree->sister)) > low) low = row;
+ if (tree && tree->type == NODENAME && has(tree,'I')) break;
+ }
+ return(low);
+}
+
+/* increase row numbers */
+movedown(tree, amount)
+TREE tree;
+int amount;
+{
+ while (tree) {
+ tree->row += amount;
+ movedown(tree->sister, amount);
+ tree = tree->daughter;
+ }
+}
+
+/* add VBARs to bring \F'd constituents downward */
+flatbars(tree, bottom)
+TREE tree;
+int bottom;
+{ TREE node, temp, next;
+ int far = bottom;
+
+ if (tree) {
+ if ( (tree->type == NODENAME || (tree->type == HBAR
+ && tree->mother && tree->mother->type == VBAR) )
+ && has(tree,'E') )
+ bottom = howlow(tree);
+ if (!(node = tree->daughter)) {
+ temp = tree->left;
+ if (temp && temp->sister == tree) {
+ node = tree;
+ tree = temp;
+ }
+ }
+ while (node) {
+ next = node->sister;
+ if (next) next->left = node;
+ if (node->daughter) {
+ if (has(node,'F')) far -= howlow(node) - node->row;
+ else flatbars(node, bottom);
+ }
+ if (has(node,'F')) {
+ if (node->type == VBAR) far--;
+ while (node->row < far) {
+ temp = newbar(node, node->row, VBAR);
+ temp->daughter = node;
+ if (has(node,'R') && node->sister) node->sister->row++;
+ else {
+ temp->sister = node->sister;
+ node->sister = NULL;
+ }
+ node->row++;
+ if (node == tree->sister && next) next->left = temp;
+ if (node == tree->daughter) tree->daughter = temp;
+ else if (node == tree->sister) tree->sister = temp;
+ /*else ERROR("flatbars");*/
+ if (!tree->sister) giveval(tree,'T',0);
+ if (node->type == VBAR && has(node,'T'))
+ giveval(node,'T',0);
+ else giveval(temp,'T',0);
+ node->mother = temp; /* ?? */
+ tree = temp;
+ }
+ if (node->daughter) {
+ movedown(node->daughter, node->row + 1
+ - node->daughter->row);
+ }
+ } /* end if (has(node,'F')) */
+ tree = node;
+ node = next;
+ } /* end if (node) */
+ } /* end if (tree) */
+}
+
+/* initialize `left' links in one row of tree; called by rectify() */
+TREE rectifyrow(prev, root, row)
+TREE prev, root;
+int row;
+{ TREE node = root, last = NULL, temp;
+
+ if (node && node->row <= row) {
+ if (node->row == row) {
+ prev->right = node;
+ if (debug_opt) {
+ fprintf(stderr,"\nLINK OF ");
+ printnode(prev);
+ fprintf(stderr," TO ");
+ printnode(node);
+ }
+ last = prev = node;
+ }
+ else if (temp = rectifyrow(prev, node->daughter, row))
+ last = prev = temp;
+ if (temp = rectifyrow(prev, node->sister, row))
+ last = prev = temp;
+ }
+ return(last);
+}
+
+/* initialize `left' links so can traverse tree in row-column order */
+rectify(root)
+TREE root;
+{ TREE node = root;
+ int row;
+
+ for (row = 2; node = rectifyrow(node, root, row); row++) ;
+}
+
+/* all TeX code in is tex.c */
+#include "tex.c"
diff --git a/graphics/tree/unpar.l b/graphics/tree/unpar.l
new file mode 100644
index 0000000000..3bcbdfd7b0
--- /dev/null
+++ b/graphics/tree/unpar.l
@@ -0,0 +1,158 @@
+%{
+/*
+ * unpar.l: substitute indentation for parenthesization.
+ * Version 0.1
+ * (unpar recognizes some \tree definitions as correct which tree
+ * rejects.)
+ * -- Greg Lee, lee@uhccux.uhcc.hawaii.edu, 6/24/90
+ */
+#define TRUE 1
+#define FALSE 0
+int tex_opt = FALSE;
+int level = 0;
+int havename = 0;
+int wait = 0;
+int i;
+%}
+
+%s T X C
+
+%%
+
+^".tr" {
+ printf("\\tree");
+ havename = 1;
+ BEGIN(T);
+}
+
+\\tree[ \t]*(-([tuvLTOIFER]+|[bg][0-9]+)[ \t]*)* {
+ ECHO;
+ havename = 1;
+ if (tex_opt) BEGIN(X);
+ else BEGIN(T);
+}
+
+<T,X>^[ \t]+ ;
+<T,X>[ \t]+$ ;
+
+<T,X>\n ;
+
+<T,X>\\\( {
+ havename = 1;
+ ECHO;
+}
+<T,X>[^ \t\n\(\)]/\( {
+ havename = 1;
+ ECHO;
+ putchar(' ');
+}
+<T,X>"("([^\)\(]|\\\)|\\\()+"("([^\)\(]|\\\)|\\\()+")"([^\)\(]|\\\)|\\\()*")" {
+ wait = 2;
+ REJECT;
+}
+<T,X>"("[ \t\n]* {
+ level++;
+ if (wait == 1) printf(" - ");
+ else {
+ if (!havename) printf("\\Z\n");
+ else putchar('\n');
+ indent();
+ }
+ havename = 0;
+ if (wait) wait--;
+}
+<T,X>")"[^\)\(]+ {
+ if (level == 1) {REJECT;}
+ else level--;
+}
+<T,X>")" {
+ level--;
+ if (!level) {
+ printf("\n");
+ BEGIN(0);
+ }
+}
+<X>\$_[0-9ijkxyz]\$ {
+ havename = 1;
+ printf("[%c]", yytext[2]);
+}
+<X>\$\\overline\{\\rm\ [NAVP]\}\$ {
+ havename = 1;
+ printf(" %c'", yytext[15]);
+}
+<T,X>\\[%\(\)] {
+ havename = 1;
+ ECHO;
+}
+<T,X>% {
+ BEGIN(C);
+}
+<C>\n {
+ if (tex_opt) BEGIN(X);
+ else BEGIN(T);
+}
+<C>. ;
+<T,X>. {
+ havename = 1;
+ ECHO;
+}
+
+%%
+
+indent()
+{ int i;
+
+ for (i = 0; i < 2*(level-1); i++) putchar(' ');
+}
+
+extern char *optarg; /* from getopt */
+extern int optind;
+
+main(argc, argv)
+int argc;
+char *argv[];
+{ int c;
+ char *progname = NULL, *basename();
+
+ progname = basename (argv[0]);
+ while ((c = getopt (argc, argv, "ht")) != EOF)
+ switch (c) {
+ case 't': tex_opt = TRUE; break;
+ case 'h':
+ default:
+ fprintf(stderr, "Usage: %s [options] [files]\n", progname);
+ fprintf(stderr, "options = -t\t(remove TeX code)\n");
+ fprintf(stderr, " -h\t(print this information)\n");
+ exit(1);
+ }
+
+ if (optind >= argc) {
+ (void) yylex ();
+ }
+ else for (; (optind < argc); optind++) {
+ if (yyin == NULL) yyin = stdin;
+ if (freopen (argv[optind], "r", stdin) != NULL) {
+#ifdef FLEX_SCANNER
+ /* to get flex to look at > 1 file */
+ yy_init = 1;
+#endif
+ (void) yylex ();
+ }
+ else {
+ (void) fprintf (stderr,
+ "Couldn't open file: %s\n", argv[optind]);
+ exit (1);
+ }
+ }
+}
+
+
+char *basename (s)
+char *s;
+{
+ char *p, *strrchr();
+
+ if (p = strrchr(s, '/'))
+ return(++p);
+ else return(s);
+}
diff --git a/graphics/tree/use.raw b/graphics/tree/use.raw
new file mode 100644
index 0000000000..4750790b44
--- /dev/null
+++ b/graphics/tree/use.raw
@@ -0,0 +1,740 @@
+% Version 1.0
+\nopagenumbers
+\headline={\tenrm Use of {\sl tree}\hfil\folio}
+\voffset=2\baselineskip
+\raggedbottom
+
+\font\tfont=Helvetica at 8pt
+\font\exf=cmtt8
+\font\eightrm=cmr8
+\parindent=0pt
+\newcount\exno
+\exno=0
+\def\x#1:#2.{
+\advance\exno by1
+{\baselineskip10pt
+\smallbreak
+\leavevmode
+\obeyspaces
+\hbox to 3em{\hfill(\the\exno)}%
+\quad\hbox to 4.5in{{\exf\char"5C tree\ #1}\hfill}\hfill{\sl#2}}
+\smallbreak
+}
+\def\xtwo#1:#2:#3.{
+\advance\exno by1
+{\baselineskip10pt
+\smallbreak
+\leavevmode
+\obeyspaces
+\hbox to 3em{\hfill(\the\exno)}%
+\quad\hbox to 4.5in{{\exf\char"5C tree\ #1}\hfill}\par
+\quad\quad\quad\hbox to 4.5in{{\exf#2}\hfill}\hfill{\sl#3}}
+\smallbreak
+}
+\def\xthree#1:#2:#3:#4.{
+\advance\exno by1
+{\baselineskip10pt
+\smallbreak
+\leavevmode
+\obeyspaces
+\hbox to 3em{\hfill(\the\exno)}%
+\quad\hbox to 4.5in{{\exf\char"5C tree\ #1}\hfill}\par
+\quad\quad\quad\hbox to 4.5in{{\exf#2}\hfill}\par
+\quad\quad\quad\hbox to 4.5in{{\exf#3}\hfill}\hfill{\sl#4}}
+\smallbreak
+}
+\def\xfour#1:#2:#3:#4:#5.{
+\advance\exno by1
+{\baselineskip10pt
+\smallbreak
+\leavevmode
+\obeyspaces
+\hbox to 3em{\hfill(\the\exno)}%
+\quad\hbox to 5.5in{{\exf\char"5C tree\ #1}\hfill}\par
+\quad\quad\quad\hbox to 5.5in{{\exf#2}\hfill}\par
+\quad\quad\quad\hbox to 5.5in{{\exf#3}\hfill}\par
+\quad\quad\quad\hbox to 5.5in{{\exf#4}\hfill}\hfill{\sl#5}}
+\smallbreak
+}
+\newdimen\svhsize\newdimen\svparindent
+\def\xp#1:#2\par{%
+\svparindent=\parindent
+\parindent=0pt
+\svhsize=\hsize
+\hsize=1.6in
+\setbox0=\vbox{
+\raggedright
+{\tt #1}
+}
+\hsize=4in
+\setbox1=\vbox{#2}
+\ht0=\ht1
+\hsize=\svhsize
+\vskip.10in plus.05in minus.02in
+\hbox to \hsize{\qquad\box0\hss\box1}
+\vskip.10in plus.05in minus.02in
+\parindent=\svparindent
+}
+\def\up{{\tt\char"5E}}
+\def\bs#1{{\tt\char"5C #1}}
+\def\xbs#1{{\exf\char"5C #1}}
+\def\tl{{\tt\char"7E}}
+\def\c#1{{\tt\char"5C #1}}
+\def\o#1{{\tt-#1}}
+\def\sect#1\par{\medbreak{\eightrm\uppercase{#1.}}\ }
+\centerline{Use of {\sl tree} program}\bigskip
+
+\beginsection Input/output.
+
+{\sl Tree} takes input from a text file with trees defined in
+a parenthesis notation and produces a new text with graphic
+displays of the trees substituted for the original definitions.
+The display can be either tty-style, for screen display or
+(crude) printing with a typewriter font, or \TeX-style, for
+formatting and printing with \TeX.
+
+Assuming that the file `tfile' has some tree definitions, give
+this Unix command to display trees on your terminal screen:
+\smallskip
+\hskip .5in{\tt\% tree tfile}
+\smallskip
+\noindent
+and these commands to get printout:
+\smallskip
+\hskip .5in{\tt\% tree -u tfile >tfile.tex}\par
+\hskip .5in{\tt\% tex tfile}\par
+\hskip .5in{\tt\% lpr -d tfile.dvi}
+\smallskip
+\noindent
+But it might be necessary to adapt the above slightly, depending
+on local details of how \TeX\ and your printing software works.
+\beginsection Parenthesis notation.
+
+A tree consists of left and right parentheses surrounding a node name
+and zero or more trees.
+
+\x (): empty node.
+\x (runs): one node.
+\x (runs(John)): two nodes.
+
+The characters making up the name cannot be separated by trees.
+Stuff after the first subtree not itself part of a subtree is
+discarded.
+
+\x (ru(John)ns there): discarded text.
+
+The interpretation of the text of names is similar to that in \TeX,
+so spacing is free.
+For one thing,
+spaces, tabs, or newlines at the beginning or end of node names are ignored.
+
+\xthree
+ ( runs (:
+ John:
+ )):
+ free spacing.
+
+And also,
+multiple spaces, tabs, or newlines within a name count as a single space.
+The next three trees are all the same:
+
+\x (runs fast):.
+\x (runs fast):.
+\xtwo (runs:
+ fast ): free spacing.
+
+As well as ordinary characters, a node name in the source file may also
+have certain special character combinations and \TeX\ commands,
+which are discussed in the next two sections.
+\beginsection Special characters and commands.
+
+There are two special characters, left and right parentheses, and a
+number of special character combinations. The `\bs{}' character begins
+all special combinations, but it is
+considered simply as part of a node name unless it occurs in one of the
+combinations listed below. After `\bs{}' plus capital letter, a space or
+a tab is optional and is ignored if present, except that it must be
+present to separate the special combination from a following alphabetic
+character. (Thus {\tt \bs{TeX}}, for instance, is left unchanged as part
+of a node name, but {\tt H\bs{T} eX} is interpreted as the node name
+`HeX' with the command to draw a triangle under this node.)
+
+\xp (: Begins a tree.
+
+\xp ): Ends a tree.
+
+\xp \bs(: Includes the left paren character in a node name.
+
+\xp \bs): Includes the right paren character in a node name.
+
+\xp \bs{}$<$blank$>$:
+ Includes the space character in a node name.
+
+\xp \bs{}\bs{}: Includes the backslash character in a node name.
+
+\xp \c{L}: ``Lexical'' omits lines and vertical space under a node.
+
+\xp \c{I}: ``Invert'' turns a subtree upside down.
+
+\xp \c{H}: ``Head'' on a node under a branching node centers the
+ branching node over the head node.
+
+\xp \c{T}: ``Triangle'' draws a triangle under a node.
+
+\xp \c{F}: ``Flatten'' moves a subtree down to the lowest level.
+ However, nameless nodes are moved down one less level,
+ so that the vertical will end above the position
+ the name, if there were one, would occupy if moved
+ to the lowest level.
+
+\xp \c{E}: ``Even'' restricts the meaning of ``lowest'' for the
+ \c{F} command to the lowest level node dominated by
+ the node marked with \c{E}. Inverted subtrees are
+ ignored when searching for the lowest node.
+
+\xp \c{M}: ``Mother'' draws curvy line from below node to above one
+ or more nodes with \c{D}. No other \c{M} command
+ can be given for the same node.
+
+\xp \c{D}: ``Daughter'' draws curvy line from above node to below a
+ single node with \c{M}. No other \c{D} command can be
+ given for the same node. No more than one node labeled
+ with \c{D} can be higher in the tree than the
+ corresponding node labeled with \c{M}.
+
+\xp \c{M0}-\c{M9}: Like \c{M} but paired with \c{D0}-\c{D9},
+ respectively.
+
+\xp \c{D0}-\c{D9}: Like \c{D} but paired with \c{M0}-\c{M9},
+ respectively.
+
+\xp \c{B0}-\c{B9}: ``Bold'' replaces vertical connecting lines under
+ a node with various \TeX\ symbols --- arrows or double
+ lines. Under branching nodes, \c{B0}--\c{B8} give a
+ horizontal bar with a tail on top, and \c{B9} gives
+ a brace. Under nodes with the \c{T} ``triangle''
+ command, \c{B0}--\c{B8} give a
+ rectangle with a tail on top and, for \c{B1}--, filled
+ with various numbers of double arrows (not very
+ attractive), and \c{B9} uses a brace.
+
+\xp \c{B}: ``Brace'' requests a brace under a branching node and
+ simple verticals above each of the daughters, or
+ a simple vertical under a non-branching node. It is
+ the same as \c{B9}. The minimum size of a brace is
+ about 2 ems in CMR 10. If the brace would have to be
+ less than 2.5 ems, consequently (leaving a little
+ leeway), tree draws a horizontal bar instead.
+
+\xp \c{O}: ``Omit'' omits the line above a node that would have connected
+ it to its mother.
+
+\xp \c{P}: ``Phantom'' omits the line above a node that would
+ have connected it to its mother and also omits the node
+ name, but reserves horizontal space in the tree as if the
+ node name were actually there.
+
+\xp \c{R}: ``Relational'' puts a vertical bar to the right of a node
+ name and aligns any connecting tree lines above or below
+ with this vertical, so that the node name appears to
+ be associated with a connecting line, rather than a
+ tree node. The root nodes of single (not side-by-side)
+ trees are unaffected.
+
+\xp \bs{}$<$capital-letter$>$:
+ If the capital is followed by an alphabetic character,
+ this is not special. Otherwise, if the capital is not
+ part of one of the combinations listed above, this is
+ ignored--it does not become part of the node name, and
+ it has no effect.
+
+You will notice that there is some potential conflict between
+{\sl tree} commands and \TeX\ commands, since both use backslash
+as the command introducing character.
+If you need to use \TeX's backslash-space command, you can
+use `\bs{}\bs{}\ ', and {\sl tree} will leave single backslash plus
+space in the name, with this counting for one character of width
+(see the section below on the width of names).
+If you happen to have defined some \TeX\ commands with single
+capital letters as names, similarly, you can double the backslash
+to keep them in the name, and the combination will not contribute
+toward the calculated width of the name.
+\beginsection Options.
+
+Either after the program name {\sl tree} or after the command
+\bs{tree} in a textfile, one can specify options that affect
+the kind of output {\sl tree} produces or apply commands to
+nodes in some global way.
+Options after \bs{tree} concern only the one tree which follows,
+but options on the command line apply to all trees in the files
+processed by this invocation of {\sl tree.}
+In case of conflict, an option after the \bs{tree} command overrides
+one given on the command line.
+Options are single letters given after hyphen and, in a few cases,
+followed by a non-negative integer argument.
+Several options together can be separated by spaces and each
+introduced by a separate hyphen, or next to each other and after
+a single hyphen.
+A numeric argument can come immediately after its option letter
+or be separated from it by spaces, but cannot be immediately
+followed by an option letter.
+
+
+\xp \o{t}: causes {\sl tree} to emit {\sl \TeX} code.
+
+\xp \o{u}: also produces {\sl \TeX} code, but with PostScript commands for
+diagonal lines.
+
+\xp \o{b} {\it num}: sets the blackness of triangles drawn under
+certain nodes (see below). For the \o{t} option, extra verticals fill
+in the base of ``triangles'', the spacing of them depending on {\it
+num}. For tty output, various characters are used to approximate
+connecting lines, again depending on {\it num}. Used with the \o{t}
+option or for tty output, this option has the same effect as giving a
+\c{B}{\it digit} command for each node, where {\it digit} is the first
+significant digit of {\it num}.
+
+\xp \o{v}: displays {\sl \TeX} commands for tty output --- normally they are
+suppressed.
+
+\xp \o{q}: suppresses warning messages that are otherwise issued when various
+circumstances suggest a possible problem with the definition of a tree.
+The warnings are given for blank lines, `\bs{tree}' commands, or text
+after a node name when any of these are found within a tree definition.
+
+\xp \o{g} {\it num}: uses {\it num} for gap separating subtrees in
+place of default value of 2.
+
+\xp \o{O}: causes the lines connecting node names to be omitted. This option
+has the same effect as giving the `\c{O}' command for each node.
+
+\xp \o{L}: omits the lines connecting nodes, leaving no vertical space where
+the lines would have been. This option has the same effect as giving
+the `\c{L}' command for each node.
+
+\xp \o{T}: draws triangles under nodes instead of branches. This option has
+the same effect as giving the `\c{T}' command for each node.
+
+\xp \o{I}: turns trees upside down. This option has the same effect as
+giving the `\c{I}' command for the top node (or the top nodes, in the
+case of side-by-side trees).
+
+\xp \o{F}: lowers terminals to lowest level found in the subtree whose top
+node is marked with `\c{E}', or else to the lowest level in the entire
+tree if `\c{E}' has not been used. If a terminal has a node immediately
+above it with the `\c{L}' lexical command, this is lowered too. This
+option has the same effect as giving the `\c{F}' command for each
+terminal node (or \c{L} lexical nodes above it).
+
+\xp \o{E}: restricts the context for lowering with `\c{F}' commands or the
+\o{F} option to each subtree under a branching node. This option has
+the same effect as giving the `\c{E}' command for every branching node.
+
+\xp \o{R}: places node names to the left of verticals. This option has the
+same effect as giving the `\c{R}' command for every non-terminal node.
+Nodes with `\c{L}' over terminal nodes are also unaffected.
+
+\beginsection Examples.
+
+% NAMELESS NODES
+\sect Nameless nodes
+
+Nodes do not need to have names:
+\x (proverb ((every)(dog)) ((has)(his)(day)) ):two nameless nodes.
+
+However, the case of a nameless root node is special.
+This means that two trees are to be displayed side-by-side and
+not connected:
+\x (((every)(dog)) ((has)(his)(day)) ):separate trees.
+
+If you want the trees to be connected, you have to add extra
+parentheses:
+\x ((((every)(dog)) ((has)(his)(day)) )):connected trees.
+\xthree (( ( (the) ( ( (giant) ( (who) ( (be) (green)))):
+ ( (who) ( (be) (jolly))))):
+ ( (wear) ( ( (shoes) ( (Gucci) ( (design) (which)))))))):
+ nameless trees connected.
+
+Nameless terminal nodes give vertical lines at the bottom.
+\x ((worms)(have)(two())(legs())):bottom verticals.
+
+Sometimes it is convenient to make a nameless node in order to
+minimize the width of a branching constituent which has one
+very wide daughter.
+\x (VP (send)(him)(the oldest sample of Cabernet we have)):
+ equally spaced sisters.
+The `send' and the `him' are far apart because the connecting
+lines over sister constituents are made equally spaced and the `him'
+line has to be so far from the following line.
+But if the long daughter is lowered by one level with an extra
+pair of parentheses, the whole thing gets much narrower:
+\x (VP (send)(him)((the oldest sample of Cabernet we have))):
+ lowering a node.
+The appearance of this example could be improved by putting a
+triangle over the long constituent, as in the examples following.
+
+% TRIANGLES
+\sect Triangles
+
+The \c{T} command makes a triangle under a node to indicate structure
+not explicitly shown.
+A triangle can be drawn over several daughter constituents or over
+a single daughter, however a single daughter must be at least
+three characters wide.
+\x (( (NP\T(Orville and Wilbur)) (P\T(had)(bikes)(galore)) )):
+ triangle over one node.
+Notice that the triangle over the single daughter has its
+base drawn out to the edges of what is below, unlike the other
+triangle. This difference might be considered a bug.
+\smallskip
+There are several options to apply commands in some global way.
+Triangles can be drawn under all nodes, without giving a
+\c{T} command for each (non-terminal) node.
+An example above with the {\tt -T} option and some extra parens
+comes out like this.
+\x -T (VP (send)(him)(((the oldest sample of Cabernet we have)))):
+ option versus command.
+\smallskip
+Options can be invoked when calling {\sl tree} also, using the same
+syntax.
+
+% HEADS
+\sect Heads
+
+One of multiple sisters can designated as head with \c{H} to align
+it under its mother.
+\xthree (( ((the\H) ( (old) (\H(grey)(mare\H)) ) ) (\H (ain't\H):
+ ( (what\H) ( (she) (\H (\H(used\H)(to)) (be) ) ):
+ )))):
+ alignment over head.
+I can tell what heads are about as well as what topics are,
+which is not very, so I probably got this example wrong.
+
+% RELATIONAL
+\sect Relations
+
+To suggest that a label is associated with a relation between nodes
+rather than being a node label, the \c{R} command can be used to
+place a label to the left of a vertical. In the following, case
+labels are treated as relational:
+
+\xfour (S (Agent\R(NP(John))) (VP(V\L(broke)):
+ (Patient\R(NP(the)(window))):
+ (Instrument\R(PP(P\L(with)):
+ (Patient\R(NP(the)(hammer))) )) ) ):.
+
+In some cases it may be possible to cobble together something
+resembling an RG arc-stratum diagram:
+
+\xfour -g0 (( (1\R(1\R(Mary))) (P\R(P\R(believe))):
+ (((2\R( ((((())))) )))) (2\R(Cho\R((:
+ (1\R(Victor\ \ \ \ )) (P\R(shoot)) (2\R(John)):
+ )))) )):.
+
+% OMIT
+\sect Omitting lines
+
+When part of a tree display is not actually a tree, but a rule
+name, for example, the lines that would otherwise appear above
+it can be suppressed with \c{O}.
+
+\xthree ( (VP(V(make))(headway)):
+ (\O(\O(\O(idiom decoration\O)))):
+ (VP(V(make)(for))(headway)) ): omitted lines over rule.
+
+Nodes that aren't attached by a line to their parent node just
+float below it --- they are not aligned in the same way as nodes that are
+attached.
+
+\xtwo (top (first (over\O)(the)(river)):
+ (second (and)(through)(the\O)(woods\O))):alignment of unattached nodes.
+
+% FLATTENING
+\sect Flattening
+
+Another style of tree one sometimes sees has terminal nodes all
+on one line.
+The \c{F} command allows flattening of selected constituents:
+\xtwo (S (NP\F(all)(NP\T(the workers))):
+ (VP(V\F(be)) (VP(V\F(praised))(PP\T(by the manager))) ) ):
+ flatten command.
+The corresponding {\tt -F} option flattens all terminals.
+\xtwo -F (S (NP(all)(NP\T(the workers))):
+ (VP(V(be)) (VP(V(praised))(PP\T(by the manager))) ) ):
+ flatten option.
+Flattened trees tend to have excessive horizontal spacing.
+The minimum space required between nodes that are next to
+each other is ordinarily 2, but this can be adjusted with
+the gap option {\tt -g}.
+Adjusting the above to a gap of one:
+\xtwo -F -g1 (S (NP(all)(NP\T(the workers))):
+ (VP(V(be)) (VP(V(praised))(PP\T(by the manager))) ) ):
+ gap between nodes.
+
+It's possible to compromise and just have most things flattened.
+The \c{E} ``even'' command selects certain constituents as the context
+of flattening, rather than the entire tree.
+\xtwo -F -g1 (S (NP\E(all)(NP\T(the workers))):
+ (VP\E(V(be)) (VP(V(praised))(PP\T(by the manager))) ) ):
+ evening.
+
+There is also an {\tt -E} option to select all subtrees dominated
+by branching nodes as flattening contexts.
+
+% LEXICAL
+\sect Lexical
+
+The above example was lifted from James McCawley's textbook
+{\it The Syntactic Phenomena of English.}
+McCawley has the idea that lexical labels have a different status
+than other node labels, and has such labels immediately above
+what they label in his trees.
+I don't think that's right, but nonetheless, {\sl tree} provides
+a command \c{L} to omit lines under a node.
+Redoing the previous example,
+\xtwo -F -g1 (S (NP\E(all)(NP\T(the workers))):
+ (VP\E(V\L(be)) (VP(V\L(praised))(PP\T(by the manager))) ) ):
+ no lines under nodes.
+Note that the flattening process moves the lexical labels downward,
+too.
+
+\sect Inversion
+
+Regular trees do not look very nice when inverted with the \c{I}
+command or the {\tt -I} option.
+\xthree -g1 (S\I (NP(Fred)) (V'(V\L(may)) (V'(V\L(have)):
+ (V'(V\L(be\(en\))) (V'(V\L(sing\(ing\))) (NP(songs)):
+ ))))):.
+But they're better when flattened.
+\xthree -g1 -F -I (S (NP(Fred)) (V'(V\L(may)) (V'(V\L(have)):
+ (V'(V\L(be\(en\))) (V'(V\L(sing\(ing\))) (NP(songs)):
+ ))))):
+ flatten and invert.
+
+Inversion can be done to subtrees, and in that event, the
+context for flattening is determined in a special way.
+Compare the next two examples, without and with the
+\c{E} commands on the top `S' nodes:
+\xtwo -F (S (Mary) (VP(V\L(selected)):
+ ((S\I(John) (VP(secretary)) )) ) ):.
+\xtwo -F (S\E (Mary) (VP(V\L(selected)):
+ ((S\E\I(John) (VP(secretary)) )) ) ):
+ evening and inversion.
+
+The evening produced by \c{E} ignores depth in the tree
+produced by inverted subtrees, so that leaves in the upper
+tree are flattened out down to the lowest level the tree would
+have had if the inverted constituent had not been present.
+\smallskip
+There are several ways for an inverted subtree to be attached
+to nodes in the higher tree.
+If there is a highest node in the inverted tree (lowest before
+inversion), that will be the attachment point.
+When there are several nodes at the top level after in version, as in the
+above example, the attachment point is ordinarily just the
+leftmost of them.
+But there are three other ways that such inverted trees
+can get attached: one concerns extra attachments to empty
+nodes in the top tree, a second involves empty nodes in the
+bottom tree, and thirdly, there can be no attachment point.
+\smallskip
+If there are dangling verticals, empty nodes that is,
+in the upper tree, then {\sl tree} tries to align the other
+nodes of the inverted tree with those verticals.
+Following is an example where there are three nodes at the
+top of the inverted tree, `Mary', `leave', and `yesterday'.
+The leftmost, `Mary', gets attached to the original position
+of the lower `S', as a sister of `saw', but there are two
+empty nodes in the right position in the upper `VP', so
+`leave' and `yesterday' are attached to these.
+\xthree (S\E (John\F) (VP(VP (saw):
+ (S\E\I (Mary\F) (VP (leave) (yesterday))):
+ () ) (\F) ) ):
+ attachment of empty nodes.
+
+Another possibility is for several empty nodes at the top of
+the inverted tree to be attached as daughters of a single
+node in the upper tree.
+Consider the phrase `a deep blue necktie', discussed in
+McCawley's text on pages 744-745.
+According to the following analysis, one would expect the
+adverb `deeply' instead of `deep':
+\xtwo (NP (Det\L(a)):
+ (N' (A' (?\L(deep)) (A\L(blue)) ) (N' (N\L(necktie)) ) )):.
+
+McCawley proposes that we get `deep' because of the
+possibility of `deep blue' having the structure:
+\x (N' (A' (A\L(deep)) ) (N' (N\L(blue)) ) ):.
+
+A diagram for both analyses simultaneously can be constructed
+by making a top piece:
+\x (NP (Det\L(a)) (N' (A') (N' (N\L(necktie)) )) ):.
+
+and a bottom piece with two empty nodes at the top:
+\xtwo (N'\I (A' (A\L(deep\L(?()))) ):
+ (N' (N\L(blue\L(A()))) )):.
+
+then putting them together:
+\xthree (NP (Det\L(a)) (N' (A':
+ (N'\I (A' (A\L(deep\L(?()))) ) (N' (N\L(blue\L(A()))) ):
+ ) ) (N' (N\L(necktie)) ))):
+ attachment of empty nodes.
+
+The empty nodes at the bottom have been connected to `A' ' in the top
+tree. (If `deep' is not attached upstairs at all, this comes closer
+to capturing the point, but the formatting is less interesting.)
+\smallskip
+Finally, it is also possible for there to be no attachment
+place for an inverted subtree.
+This case arises when the line above the inverted constituent
+has been omitted with the \c{O} command:
+\xtwo (S (Mary) (VP (selected):
+ (S\O\I (I)(think)) (John) ) (S\O\I(George)(says)) ):
+ omitted lines.
+
+Note that for determining above which constituent a line
+is to be omitted by \c{O} it is the situation before inversion
+that counts.
+
+Here is another example taken from Robert Hoberman, ``Emphasis harmony
+in Modern Aramaic'', Lg. March 1988, 64:1:17. There are two
+syllable diagrams, which we build up piece by piece.
+Note in this first try that
+with the `s's marked \c{O} (omit), no lines are drawn above them, and
+the `[+CP]' ``floats''.
+
+\xtwo ([+CP] (s\O (C(r))(V(i))(C(q)) ):
+ (s\O (C(q))(V(a)) ) ):.
+
+The `q' should actually appear only once at the bottom with converging
+branches. Begin by constructing a tree with root `q' and daughters
+`C' `C' and inverting it with \c{I}.
+
+\x (q\I(C)(C)):.
+
+Then substitute this for the first `(C(q))' in the first tree,
+and make the second `(C(q))' an empty node.
+
+\xtwo ([+CP] (s\O (C(r))(V(i))(q\I(C)(C))):
+ (s\O ()(V(a))) ):.
+
+This is not bad, but we want the `r', `i', and `a' down one level, so
+add parentheses around them.
+
+\xtwo ([+CP] (s\O (C((r)))(V((i)))(q\I(C)(C))):
+ (s\O ()(V((a)))) ):.
+
+The example of the Hoberman article has two similar trees
+side-by-side, but with the `[+CP]' attached to the first `s' below it in
+the second version, so that `s' should not have an \c{O}. Adding also the
+example numbers and letters with some ``hard'' spaces around them to get
+better alignment, and putting the \TeX\ \bs{sigma} command for `s',
+we wind up with:
+
+\xfour ( (\(31\) a.\ \ \ ) ([+CP] ($\sigma$\ \O:
+ (C((r)))(V((i)))(q\I(C)(C))) ($\sigma$\ \O ()(V((a))))):
+(\ \ \ b.) ([+CP] ($\sigma$\ (C((r)))(V((i)))(q\I(C)(C))):
+ ($\sigma$\ \O ()(V((a))))) ):.
+
+\sect Discontinuous constituents
+
+Provided you can use the {\tt -u} option for generating
+\TeX\ code with embedded PostScript, labeling one node
+\c{M} or \c{M0}, $\dots$, \c{M9} and one or more others
+with a matching \c{D}, \c{D0}, $\dots$, \c{D9} gets you
+curvy lines connecting the one with the others. Here is an
+example from Almerindo E. Ojeda, ``A linear precedence account
+of cross-serial dependencies'', Linguistics and Philosophy,
+Nov. 1988, 11:4:480.
+
+\xfour -F (S (NP(Jan)) (VP\M1 (NP(Piet)) (VP\M2 (NP(Marie)):
+ (VP\M3 (NP(Cecilia)) (\O(\O(V[2]\O\D1(zag)))):
+ (\O(\O(V[2]\O\D2(helpen)))) (\O(\O(V[2]\O\D3(laten)))):
+ (VP (V[1](zwemmen))))))):.
+
+
+\sect Boldness
+
+The \o{b} option and the \c{B} commands are related in what I guess
+is a rather confusing way.
+For tty-style screen output or for \TeX\ code generated with the \o{t}
+option, they do the same thing, except that \o{b} acts on whole
+trees and the \c{B} commands work node-by-node---both control the
+style of lines and other graphics used to connect nodes in the
+displayed tree.
+However, for \TeX code generated with the \o{u} option, although the
+\c{B} commands work the same way, the \o{b} option has a
+related but quite different effect---it controls the greyness level for
+triangles drawn under nodes with the \c{T} command.
+%The following examples will assume that this present text was
+%printed with the \o{u} option. In case that is not actually so,
+%please make due allowance.
+
+\smallskip
+This has instances of all the bold varieties of connecting graphics
+except for triangles.
+
+\xfour (S\B0(PP\B1(P1\B(P(on))(NP\B2(which)(N1\B(N\B2(table)))))):
+ (S/PP\B3(V(do))(NP\B3(you))(VP/PP\B4(V\B4(think))(S/PP\B5(NP\B5:
+ (Martha))(VP/PP\B6(V\B6(believes))(S/PP\B7(NP\B7(Irving))(VP/PP:
+ \B8(V\B8(put))(NP(Det\B9(the)(N1(N(book)))))(PP/PP(e))))))))):.
+
+For non-branching nodes, simple verticals are used under nodes with
+\c{B0} or \c{B9}. The verticals for the other \c{B} commands
+are as follows:
+
+\xp \c{B1}: $\big\Vert$
+
+\xp \c{B2}: $\big\downarrow$
+
+\xp \c{B3}: $\big\Downarrow$
+
+\xp \c{B4}: $\big\uparrow$
+
+\xp \c{B5}: $\big\Uparrow$
+
+\xp \c{B6}: $\big\updownarrow$
+
+\xp \c{B7}: $\diamondsuit$
+
+\xp \c{B8}: $\triangle$
+
+Those verticals that have a direction are inverted in inverted trees.
+
+\beginsection \TeX\ commands and the width of names.
+
+The width of the name assumed in formatting the tree is the number of
+characters in it, deducting for things assumed to be \TeX\ commands when
+one of the options -u or -t is in effect.
+The following do not count toward the width of the name when `tree' was
+given the -u or -t options, since they are assumed to be for \TeX\ and not
+to contribute to the actual printed width.
+\medskip
+{\advance\leftskip by36pt\advance\rightskip by36pt
+\item{(a)} backslash followed by a string of alphabetic characters then
+ white spaces (any number of space, tabs, and newlines),
+ except for the special combinations listed above; these are
+ assumed to be \TeX\ command names)
+\item{(b)} backslash followed by left-quote, right-quote, period, `{\tt=}',
+ `\up', `\tl' (\TeX\ diacritics)
+\item{(c)} left or right brace not preceded by backslash (\TeX\ grouping
+ commands)
+\item{(d)} dollar-sign not preceded by backslash (\TeX\ math mode)
+\item{(e)} backslash followed by any non-alphabetic character
+
+}
+\medskip
+Note that there is no provision for \TeX\ commands that do contribute to
+the print-width of a name (e.g. {\tt\bs{TeX}}), which will cause the
+actual width of a name to be underestimated sometimes, or for arguments
+to \TeX\ commands (e.g. {\tt\bs{hbox} to 2em$\{\dots\}$}), which will
+cause the width to be underestimated sometimes. The underestimation
+problem can be corrected for by padding with spaces (e.g.
+\bs{\ }\bs{\ }\bs{\ }\bs{TeX} instead of simply \bs{TeX}).
+
+For every three capital letters in a name (not counting `I'), the assumed
+print-width is increased by one-half em to compensate for the typical
+extra width of capitals in proportional fonts.
+\bigskip
+\rightline{---Greg Lee}
+\bye