diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/tree |
Initial commit
Diffstat (limited to 'graphics/tree')
-rw-r--r-- | graphics/tree/MANIFEST | 15 | ||||
-rw-r--r-- | graphics/tree/Makefile.kit | 86 | ||||
-rw-r--r-- | graphics/tree/README | 271 | ||||
-rw-r--r-- | graphics/tree/mdoc.l | 93 | ||||
-rw-r--r-- | graphics/tree/sample | 114 | ||||
-rw-r--r-- | graphics/tree/tex.c | 670 | ||||
-rw-r--r-- | graphics/tree/texsample | 228 | ||||
-rw-r--r-- | graphics/tree/texsample.tex | 406 | ||||
-rw-r--r-- | graphics/tree/tpar.l | 206 | ||||
-rw-r--r-- | graphics/tree/tpsample | 106 | ||||
-rw-r--r-- | graphics/tree/tree.1 | 449 | ||||
-rw-r--r-- | graphics/tree/tree.l | 1735 | ||||
-rw-r--r-- | graphics/tree/unpar.l | 158 | ||||
-rw-r--r-- | graphics/tree/use.raw | 740 |
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 |