home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume37 / lout / part11 < prev    next >
Encoding:
Text File  |  1993-06-19  |  81.0 KB  |  2,088 lines

  1. Newsgroups: comp.sources.misc
  2. From: jeff@joyce.cs.su.oz.au (Jeff Kingston)
  3. Subject: v37i109:  lout - Lout document formatting system, v2, Part11/30
  4. Message-ID: <1993Jun1.051859.25788@sparky.imd.sterling.com>
  5. X-Md4-Signature: 154a6fcfa8b9e41a867dbfc0f76526b0
  6. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Tue, 1 Jun 1993 05:18:59 GMT
  9. Approved: kent@sparky.imd.sterling.com
  10.  
  11. Submitted-by: jeff@joyce.cs.su.oz.au (Jeff Kingston)
  12. Posting-number: Volume 37, Issue 109
  13. Archive-name: lout/part11
  14. Environment: UNIX
  15.  
  16. #! /bin/sh
  17. # This is a shell archive.  Remove anything before this line, then feed it
  18. # into a shell via "sh file" or similar.  To overwrite existing files,
  19. # type "sh file -c".
  20. # Contents:  lout/doc/tr.lout/ch1.01 lout/z02.c lout/z15.c lout/z29.c
  21. # Wrapped by kent@sparky on Sun May 30 19:43:56 1993
  22. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  23. echo If this archive is complete, you will see the following message:
  24. echo '          "shar: End of archive 11 (of 30)."'
  25. if test -f 'lout/doc/tr.lout/ch1.01' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'lout/doc/tr.lout/ch1.01'\"
  27. else
  28.   echo shar: Extracting \"'lout/doc/tr.lout/ch1.01'\" \(6589 characters\)
  29.   sed "s/^X//" >'lout/doc/tr.lout/ch1.01' <<'END_OF_FILE'
  30. X@Section
  31. X  @Title { Objects }
  32. X  @Tag { objects }
  33. X@Begin
  34. X@PP
  35. XSince our aim is to produce neatly formatted documents, we should begin by
  36. Xlooking at a typical example of such a document:
  37. X@ID {
  38. Xnohyphen @Break @LittleDocument
  39. X//
  40. X@LittleText {
  41. X@DP
  42. X|0.5rt {@B PURCELL}{ 0.8f @Font 1 ^//0.2v}
  43. X@LittleFootNote
  44. X{ { 0.8f @Font 1 ^//0.2v}Blom, Eric.  @I {Some Great Composers.}  Oxford, 1944.
  45. X}
  46. X@DP
  47. XIn the world of music England is supposed to be a mere province.  If she
  48. Xproduces an indifferent composer or performer, that is regarded
  49. Xelsewhere as perfectly normal and natural; but if foreign students of
  50. Xmusical history have to acknowledge a British musical genius, he is
  51. Xconsidered a freak.
  52. X@PP
  53. XSuch a freak is Henry Purcell.  Yet if we make a choice of fifteen of
  54. Xthe world's musical classics, as here, we find that we cannot omit this
  55. XEnglish master.
  56. X}
  57. X//
  58. X@LittleEndRun
  59. X}
  60. XIt is a large rectangle made from three smaller rectangles -- its
  61. Xpages.  Each page is made of lines; each line is made of words,
  62. Xalthough it makes sense for any rectangle (even a complete document) to
  63. Xbe part of a line, provided it is not too large.
  64. X@PP
  65. XLout deals with something a little more complicated than rectangles:
  66. X@I objects.  An object
  67. Xobjec @Index { Object }
  68. Xis a rectangle with at least one @I {column mark}
  69. Xcolumn.mark @Index { Column mark }
  70. Xmark.alignment @Index { Mark alignment }
  71. Xalignment @RawIndex { Alignment @I see mark alignment }
  72. Xprotruding above and below it, and at least one @I {row mark}
  73. Xrow.mark @Index { Row mark }
  74. Xprotruding to the left and right.  The simplest objects contain words like
  75. Xmetempsychosis, and have one mark of each type:
  76. X@ID {
  77. X@ShowMarks metempsychosis
  78. X}
  79. XThe rectangle exactly encloses the word; its column mark is at the left
  80. Xedge, and its row mark passes through the middle of the lower-case
  81. Xletters.  The rectangle and marks do not appear on the printed page, but
  82. Xto understand what Lout is doing you have to imagine them.
  83. X@PP
  84. XTo place two objects side by side, we separate them by the
  85. Xsymbol @Code "|", which denotes the act of @I {horizontal
  86. Xconcatenation}.  So, if we write
  87. X@ID {
  88. X@Code "USA  |  Australia"
  89. X}
  90. Xthe result will be the object
  91. X@ID {
  92. X@ShowMarks USA | @ShowMarks Australia
  93. X}
  94. XNotice that this object has two column marks, but still only one row mark,
  95. Xbecause @Code "|" merges the two row marks
  96. Xtogether.  This merging of row marks fixes the vertical
  97. Xposition of each object with respect to the other, but it does not
  98. Xdetermine how far apart they are.  This distance, or {@I gap},
  99. Xmay be given just after the symbol, as in @Code "|0.5i" for example,
  100. Xwhich specifies horizontal concatenation with a gap of half an inch.  If
  101. Xno gap is given, it is assumed to be {@Code "0i"}.
  102. X@PP
  103. X@I {Vertical concatenation} & , denoted by the symbol {@Code "/"},
  104. Xis the same apart from the change of direction:
  105. X@ID {
  106. X@Code "Australia  /0.1i  USA"
  107. X}
  108. Xhas result
  109. X@ID {
  110. X@ShowMarks Australia /0.1i
  111. X@ShowMarks USA
  112. X}
  113. XThe usual merging of marks occurs, and now the gap determines the
  114. Xvertical separation.  Horizontal and vertical can be combined:
  115. X@ID  @Code {
  116. X             |1m  USA         |1m  "|0.2i" |1m   Australia
  117. X/1vx "/0.1i" |    Washington  |    "|"     |     Canberra
  118. X}
  119. Xhas result
  120. X@ID {
  121. X      @ShowMarks USA &
  122. X      { 0 ymark moveto xsize 10 pt add ymark lineto [ 3 pt ] 0 setdash stroke }
  123. X      @Graphic {1c @Wide }
  124. X      |0.2i @ShowMarks Australia
  125. X/0.1i @ShowMarks Washington  |     @ShowMarks Canberra
  126. X}
  127. Xtables @Index { Tables }
  128. XThere are several things to note carefully here.  White space (including
  129. Xtabs and newlines) adjacent to a concatenation symbol is ignored, so
  130. Xit may be used freely to lay out the expression clearly.  The symbol
  131. X@Code "|" takes precedence over {@Code "/"}, which means that the rows
  132. Xare formed first, then vertically concatenated.  The symbol @Code "/" will
  133. Xmerge two or more column marks, creating multiple
  134. Xcolumns (and @Code "|" will merge two or more row marks).  This
  135. Ximplies that the gap @Code "0.2i" used above is between
  136. Xcolumns, not individual items in columns; a gap in the second row
  137. Xwould therefore be redundant, and so is omitted.
  138. X@PP
  139. XA variant of @Code "/" called @Code "//" left-justifies
  140. Xtwo objects instead of merging their marks.
  141. X@PP
  142. XBy enclosing an object in braces, it is possible to override the
  143. Xbraces @Index { Braces }
  144. Xset precedences.  Here is another expression for the table
  145. Xabove, in which the columns are formed first:
  146. X@ID  @Code {
  147. X             |1m "{ USA"       |1m "/0.1i" |1m "Washington }"
  148. X/1vx "|0.2i" |   "{ Australia" |   "/"     |   "Canberra }"
  149. X}
  150. XBraces have no effect other than to alter the grouping.
  151. X@PP
  152. X@I {Paragraph breaking} occurs when an object is too wide to fit
  153. Xparagraph.breaking @Index { Paragraph breaking }
  154. Xinto the space available to it; by breaking its paragraphs into lines,
  155. Xits width is reduced to an acceptable amount.  The available
  156. Xspace is determined by the @@Wide symbol, whose form is
  157. X@ID  {
  158. X@I length  @@Wide  @I object
  159. X}
  160. Xand whose result is the given object modified to have exactly the given
  161. Xlength.  For example, the expression
  162. X@ID  @Code {
  163. X"5i @Wide {"
  164. X"Macbeth was very ambitious.  This led him to wish to become"
  165. X"king of Scotland.  The witches told him that this wish of"
  166. X"his would come true.  The king of Scotland at this time was"
  167. X"Duncan.  Encouraged by his wife, Macbeth murdered Duncan.  He"
  168. X"was thus enabled to succeed Duncan as king.  (51 words)"
  169. X"|0.5i"
  170. X"Encouraged by his wife, Macbeth achieved his ambition and"
  171. X"realized the prediction of the witches by murdering Duncan"
  172. X"and becoming king of Scotland in his place.  (26 words)"
  173. X"}"
  174. X}
  175. Xhas for its result the following five inch wide object [{@Ref strunk79}]:
  176. X@ID {
  177. X5i @Wide {
  178. XMacbeth was very ambitious.  This led him to wish to become king
  179. Xof Scotland.  The witches told him that this wish of his would
  180. Xcome true.  The king of Scotland at this time was Duncan.  Encouraged
  181. Xby his wife, Macbeth murdered Duncan.  He was thus enabled to succeed
  182. XDuncan as king.  (51 words)
  183. X|0.5i
  184. XEncouraged by his wife, Macbeth achieved his ambition and realized
  185. Xthe prediction of the witches by murdering Duncan and becoming king of
  186. XScotland in his place.  (26 words)
  187. X}
  188. X}
  189. XA paragraph of text can be included anywhere, and it will be broken
  190. Xautomatically if necessary to fit the available space.  The spaces
  191. Xbetween words are converted by Lout into concatenation symbols.
  192. X@PP
  193. XThese are the most significant of Lout's object-building symbols.  There
  194. Xare others, for changing fonts, controlling paragraph breaking, printing
  195. Xgraphical objects like boxes and circles, and so on, but
  196. Xthey do not add anything new in principle.
  197. X@End @Section
  198. END_OF_FILE
  199.   if test 6589 -ne `wc -c <'lout/doc/tr.lout/ch1.01'`; then
  200.     echo shar: \"'lout/doc/tr.lout/ch1.01'\" unpacked with wrong size!
  201.   fi
  202.   # end of 'lout/doc/tr.lout/ch1.01'
  203. fi
  204. if test -f 'lout/z02.c' -a "${1}" != "-c" ; then 
  205.   echo shar: Will not clobber existing file \"'lout/z02.c'\"
  206. else
  207.   echo shar: Extracting \"'lout/z02.c'\" \(23481 characters\)
  208.   sed "s/^X//" >'lout/z02.c' <<'END_OF_FILE'
  209. X/*@z02.c:Lexical Analyser:LexInit(), LexGetToken()@***************************/
  210. X/*                                                                           */
  211. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.03)       */
  212. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  213. X/*                                                                           */
  214. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  215. X/*  Basser Department of Computer Science                                    */
  216. X/*  The University of Sydney 2006                                            */
  217. X/*  AUSTRALIA                                                                */
  218. X/*                                                                           */
  219. X/*  This program is free software; you can redistribute it and/or modify     */
  220. X/*  it under the terms of the GNU General Public License as published by     */
  221. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  222. X/*  any later version.                                                       */
  223. X/*                                                                           */
  224. X/*  This program is distributed in the hope that it will be useful,          */
  225. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  226. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  227. X/*  GNU General Public License for more details.                             */
  228. X/*                                                                           */
  229. X/*  You should have received a copy of the GNU General Public License        */
  230. X/*  along with this program; if not, write to the Free Software              */
  231. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  232. X/*                                                                           */
  233. X/*  FILE:         z02.c                                                      */
  234. X/*  MODULE:       Lexical Analyser                                           */
  235. X/*  EXTERNS:      LexLegalName(), LexInit(), LexPush(), LexPop(),            */
  236. X/*                LexNextTokenPos(), LexGetToken()                           */
  237. X/*                                                                           */
  238. X/*  Implementation note:  this fast and cryptic lexical analyser is adapted  */
  239. X/*  from Waite, W. M.: The Cost of Lexical Analysis, in Software - Practice  */
  240. X/*  and Experience, v16, pp473-488 (May 1986).                               */
  241. X/*                                                                           */
  242. X/*****************************************************************************/
  243. X#include "externs"
  244. X
  245. X#define    BUFFER_SIZE    8192        /* size of buffer for block read     */
  246. X
  247. X#define    WEIRD        0        /* unknown character type            */
  248. X#define    LETTER        1        /* letter type                       */
  249. X#define    SPECIAL        2        /* special type                      */
  250. X#define    QUOTE        3        /* quoted string delimiter type      */
  251. X#define    ESCAPE        4        /* escape character inside strings   */
  252. X#define    COMMENT        5        /* comment delimiter type            */
  253. X#define    CSPACE        6        /* space character type              */
  254. X#define    TAB        7        /* tab character type                */
  255. X#define    NEWLINE        8        /* newline character type            */
  256. X#define    ENDFILE        9        /* end of file character type        */
  257. X
  258. Xstatic    unsigned char    chtbl[256];    /* character type table              */
  259. X
  260. X/* state variables of lexical analyser */
  261. Xstatic    unsigned char    *chpt;        /* pointer to current text character */
  262. Xstatic    unsigned char    *frst;        /* address of buffer's 1st character */
  263. Xstatic    unsigned char    *limit;        /* just past last char in buffer     */
  264. Xstatic    unsigned char    *buf;        /* the character buffer start pos    */
  265. Xstatic    int        blksize;    /* size of block read; others too    */
  266. Xstatic    unsigned char   *startline;    /* position in buff of last newline  */
  267. Xstatic    FILE_NUM    this_file;    /* number of currently open file     */
  268. Xstatic    FILE        *fp;        /* current input file                */
  269. Xstatic    FILE_POS    file_pos;    /* current file position             */
  270. Xstatic    short        ftype;        /* the type of the current file      */
  271. Xstatic    OBJECT        next_token;    /* next token if already read         */
  272. Xstatic    int        offset;        /* where to start reading in file    */
  273. Xstatic    unsigned char    *mem_block;    /* file buffer                       */
  274. X
  275. Xstatic int top_stack;        /* top of lexical analyser stack     */
  276. Xstatic struct {
  277. X  unsigned char    *chpt;        /* pointer to current text character */
  278. X  unsigned char    *frst;        /* address of buffer's 1st character */
  279. X  unsigned char    *limit;        /* just past last char in buffer     */
  280. X  unsigned char    *buf;        /* the character buffer start pos    */
  281. X  int        blksize;    /* size of block read; others too    */
  282. X  unsigned char    *startline;    /* position in buff of last newline  */
  283. X  FILE_NUM    this_file;    /* number of currently open file     */
  284. X  FILE        *fp;        /* current input file                */
  285. X  FILE_POS    file_pos;    /* current file position             */
  286. X  short        ftype;        /* the type of the current file      */
  287. X  OBJECT    next_token;    /* next token if already read         */
  288. X  int        offset;        /* where to start reading in file    */
  289. X  unsigned char    *mem_block;    /* file buffer                       */
  290. X} lex_stack[MAX_LEX_STACK];
  291. X
  292. X
  293. X/*@@**************************************************************************/
  294. X/*                                                                           */
  295. X/*  BOOLEAN LexLegalName(str)                                                */
  296. X/*                                                                           */
  297. X/*  Check whether str is a valid name for a symbol table entry.              */
  298. X/*  Valid names have the BNF form                                            */
  299. X/*                                                                           */
  300. X/*       <name> ::= <letter>  { <letter> }                                   */
  301. X/*       <name> ::= <special> { <special> }                                  */
  302. X/*       <name> ::= <escape>  { <letter> }                                   */
  303. X/*                                                                           */
  304. X/*  The third form is inaccessible to users and is for internal use only.    */
  305. X/*                                                                           */
  306. X/*****************************************************************************/
  307. X
  308. XBOOLEAN LexLegalName(str)
  309. Xunsigned char *str;
  310. X{ int i;  BOOLEAN res;
  311. X  debug1(DLA, DDD, "LexLegalName( %s )", str);
  312. X  if( chtbl[str[0]] == QUOTE )  FontStripQuotes(str, no_fpos);
  313. X  switch( chtbl[str[0]] )
  314. X  {
  315. X    case ESCAPE:
  316. X    case LETTER:
  317. X    
  318. X      for( i = 1;  chtbl[str[i]] == LETTER;  i++ );
  319. X      res = str[i] == '\0';
  320. X      break;
  321. X
  322. X
  323. X    case SPECIAL:
  324. X    
  325. X      for( i = 1;  chtbl[str[i]] == SPECIAL;  i++ );
  326. X      res = str[i] == '\0';
  327. X      break;
  328. X
  329. X
  330. X    default:
  331. X    
  332. X      res = FALSE;
  333. X      break;
  334. X
  335. X  }
  336. X  debug1(DLA, DDD, "LexLegalName returning %s", bool(res));
  337. X  return res;
  338. X} /* end LexLegalName */
  339. X
  340. X
  341. X/*****************************************************************************/
  342. X/*                                                                           */
  343. X/*  LexInit()                                                                */
  344. X/*                                                                           */
  345. X/*  Initialise character types.  Those not touched are 0 (WEIRD).            */
  346. X/*  The function initchtbl() assists in initializing the chtbl.              */
  347. X/*                                                                           */
  348. X/*****************************************************************************/
  349. X
  350. Xstatic initchtbl(val, str)
  351. Xint val;  unsigned char *str;
  352. X{ int i;
  353. X  for( i = 0;  str[i] != '\0';  i++ )
  354. X    chtbl[ str[i] ] = val;
  355. X} /* end initchtbl */
  356. X
  357. XLexInit()
  358. X{ initchtbl( LETTER,     "abcdefghijklmnopqrstuvwxyz"   );
  359. X  initchtbl( LETTER,     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"   );
  360. X  initchtbl( LETTER,     "@"                            );
  361. X  initchtbl( SPECIAL,    "!$%^&*()_-+=~`{[}]:;'|<,.>?/" );
  362. X  initchtbl( SPECIAL,    "0123456789"                   );
  363. X  initchtbl( QUOTE,      "\""                           );
  364. X  initchtbl( ESCAPE,     "\\"                           );
  365. X  initchtbl( COMMENT,    "#"                            );
  366. X  initchtbl( CSPACE,      " "                            );
  367. X  initchtbl( TAB,        "\t"                           );
  368. X  initchtbl( NEWLINE,    "\n"                           );
  369. X  chtbl['\0'] = ENDFILE;
  370. X} /* end LexInit */
  371. X
  372. X
  373. X/*@@**************************************************************************/
  374. X/*                                                                           */
  375. X/*  setword(res, file_pos, str, len)                                         */
  376. X/*                                                                           */
  377. X/*  Set variable res to a WORD token containing string str, etc.             */
  378. X/*                                                                           */
  379. X/*****************************************************************************/
  380. X
  381. X#define setword(res, file_pos, str, len)                \
  382. X{ res = NewWord(len, &file_pos);                    \
  383. X  FposCopy(fpos(res), file_pos);                    \
  384. X  for( c = 0;  c < len;  c++ ) string(res)[c] = str[c];            \
  385. X  string(res)[c] = '\0';                        \
  386. X}
  387. X
  388. X
  389. X/*****************************************************************************/
  390. X/*                                                                           */
  391. X/*  LexPush(x, offs, ftype)                                                  */
  392. X/*  LexPop()                                                                 */
  393. X/*                                                                           */
  394. X/*  Switch lexical analyser to or from (LexPop) reading from the file        */
  395. X/*  sequence whose first file is x (the other files are obtained from        */
  396. X/*  NextFile).  The first file of the sequence is to be fseeked to offs.     */
  397. X/*  When the sequence is exhausted, ftype determines how to continue:        */
  398. X/*                                                                           */
  399. X/*      ftype          action                                                */
  400. X/*                                                                           */
  401. X/*      SOURCE_FILE    last input file ends, return @End \Input              */
  402. X/*      DATABASE_FILE  database file, return @End \Input                     */
  403. X/*      INCLUDE_FILE   include file, must pop lexical analyser and continue  */
  404. X/*                                                                           */
  405. X/*****************************************************************************/
  406. X
  407. XLexPush(x, offs, ftyp)
  408. XFILE_NUM x;  int offs;  int ftyp;
  409. X{ char *malloc();
  410. X  debug3(DLA, D, "LexPush(%s, %d, %s)", FileName(x), offs,
  411. X    ftyp==SOURCE_FILE ? "source" : ftyp==INCLUDE_FILE ? "include" : "database");
  412. X  if( top_stack >= MAX_LEX_STACK - 1 )
  413. X    Error(FATAL, PosOfFile(x), "%s or %s file %s too deeply nested",
  414. X      KW_INCLUDE, KW_DATABASE, FileName(x));
  415. X  if( top_stack >= 0 )  /* save current state */
  416. X  { lex_stack[top_stack].chpt        = chpt;
  417. X    lex_stack[top_stack].frst        = frst;
  418. X    lex_stack[top_stack].limit        = limit;
  419. X    lex_stack[top_stack].buf        = buf;
  420. X    lex_stack[top_stack].blksize    = blksize;
  421. X    lex_stack[top_stack].startline    = startline;
  422. X    lex_stack[top_stack].this_file    = this_file;
  423. X    lex_stack[top_stack].fp        = fp;
  424. X    lex_stack[top_stack].ftype        = ftype;
  425. X    lex_stack[top_stack].next_token    = next_token;
  426. X    lex_stack[top_stack].offset        = offset;
  427. X    lex_stack[top_stack].mem_block    = mem_block;
  428. X    FposCopy( lex_stack[top_stack].file_pos, file_pos );
  429. X  }
  430. X  top_stack += 1;
  431. X  mem_block = (unsigned char *) malloc(MAX_LINE + BUFFER_SIZE + 2);
  432. X  if( mem_block == NULL )  Error(FATAL, PosOfFile(x),
  433. X      "run out of memory when opening file %s", FileName(x));
  434. X  buf = chpt = &mem_block[MAX_LINE];
  435. X  this_file = x;
  436. X  offset = offs;
  437. X  ftype = ftyp;
  438. X  next_token = nil;
  439. X  *chpt = '\0';
  440. X  fp = null;
  441. X} /* end LexPush */
  442. X
  443. XLexPop()
  444. X{ debug0(DLA, D, "LexPop()");
  445. X  assert( top_stack > 0, "LexPop: top_stack <= 0!" );
  446. X  if( fp != null )  fclose(fp);
  447. X  top_stack--;
  448. X  free(mem_block);
  449. X  mem_block    = lex_stack[top_stack].mem_block;
  450. X  chpt         = lex_stack[top_stack].chpt;
  451. X  frst         = lex_stack[top_stack].frst;
  452. X  limit        = lex_stack[top_stack].limit;
  453. X  buf          = lex_stack[top_stack].buf;
  454. X  blksize      = lex_stack[top_stack].blksize;
  455. X  startline    = lex_stack[top_stack].startline;
  456. X  this_file    = lex_stack[top_stack].this_file;
  457. X  fp           = lex_stack[top_stack].fp;
  458. X  ftype        = lex_stack[top_stack].ftype;
  459. X  next_token   = lex_stack[top_stack].next_token;
  460. X  offset       = lex_stack[top_stack].offset;
  461. X  FposCopy( file_pos, lex_stack[top_stack].file_pos );
  462. X} /* end LexPop */
  463. X
  464. X
  465. X/*@@**************************************************************************/
  466. X/*                                                                           */
  467. X/*  long LexNextTokenPos()                                                   */
  468. X/*                                                                           */
  469. X/*  Equivalent to ftell() on the current lex file.  Complicated because      */
  470. X/*  the file is buffered.                                                    */
  471. X/*                                                                           */
  472. X/*****************************************************************************/
  473. X
  474. Xlong LexNextTokenPos()
  475. X{ long res;
  476. X  if( next_token != nil )
  477. X    Error(FATAL, &fpos(next_token), "illegal macro invokation in database");
  478. X  res = ftell(fp) - (limit - chpt) - (buf - frst);
  479. X  debug1(DLA, D, "LexNextTokenPos() returning %ld", res);
  480. X  return res;
  481. X}
  482. X
  483. X
  484. X/*****************************************************************************/
  485. X/*                                                                           */
  486. X/*  static srcnext()                                                         */
  487. X/*                                                                           */
  488. X/*  Move to new line of input file.  May need to recharge buffer.            */
  489. X/*                                                                           */
  490. X/*****************************************************************************/
  491. X
  492. Xstatic srcnext()
  493. X{ register unsigned char *col;
  494. X  debug4(DLA, DDD, "srcnext();  buf: %d, chpt: %d, frst: %d, limit: %d",
  495. X    buf - mem_block, chpt - mem_block, frst - mem_block, limit - mem_block);
  496. X
  497. X  /* if time to transfer last line to area preceding buffer, do so */
  498. X  if( blksize != 0 && chpt < limit )
  499. X  { debug0(DLA, DDD, "srcnext: transferring.");
  500. X    col = buf;
  501. X    while( (*--col = *--limit) != '\n' );
  502. X    frst = col + 1;
  503. X    limit++;
  504. X    blksize = 0;
  505. X  }
  506. X
  507. X  /* if buffer is empty, read next block */
  508. X  /*** changed by JK 9/92 from "if( chpt == limit )" to fix long lines bug */
  509. X  if( chpt >= limit )
  510. X  { if( chpt > limit )
  511. X    { col_num(file_pos) = 1;
  512. X      Error(FATAL, &file_pos, "line is too long (or final newline missing)");
  513. X    }
  514. X    chpt = frst;
  515. X    blksize = fread( (char *) buf, sizeof(char), BUFFER_SIZE, fp);
  516. X    debug4(DLA, D, "srcnext: %d = fread(0x%x, %d, %d, fp)",
  517. X      blksize, buf, sizeof(char), BUFFER_SIZE);
  518. X    frst = buf;
  519. X    limit = buf + blksize;
  520. X    *limit = '\n';
  521. X  }
  522. X
  523. X  /* if nothing more to read, make this clear */
  524. X  if( chpt >= limit )
  525. X  { debug0(DLA, DDD, "srcnext: nothing more to read");
  526. X    chpt = limit = buf;
  527. X    *limit = '\0';
  528. X  }
  529. X  debug4(DLA, DDD, "srcnext returning;  buf: %d, chpt: %d, frst: %d, limit: %d",
  530. X    buf - mem_block, chpt - mem_block, frst - mem_block, limit - mem_block);
  531. X} /* end srcnext */
  532. X
  533. X
  534. X/*@@**************************************************************************/
  535. X/*                                                                           */
  536. X/*  OBJECT LexGetToken()                                                     */
  537. X/*                                                                           */
  538. X/*  Get next token from input.  Look it up in symbol table.                  */
  539. X/*                                                                           */
  540. X/*****************************************************************************/
  541. X
  542. XOBJECT LexGetToken()
  543. X{
  544. X       unsigned char *startpos;    /* where the latest token started    */
  545. X  register unsigned char *p;        /* pointer to current input char     */
  546. X  register int      c;            /* temporary character (really char) */
  547. X  OBJECT   res;                /* result token                      */
  548. X  int vcount, hcount;            /* no. of newlines and spaces seen   */
  549. X
  550. X  if( next_token != nil )
  551. X  { next_token = Delete(res = next_token, PARENT);
  552. X    debug2(DLA, DD, "LexGetToken%s (in macro) returning %s",
  553. X      EchoFilePos(&file_pos), EchoToken(res));
  554. X    return res;
  555. X  }
  556. X
  557. X  res = nil;  p = chpt;
  558. X  vcount = hcount = 0;
  559. X  do switch( chtbl[*p++] )
  560. X  {
  561. X      case WEIRD:
  562. X      
  563. X    debug1(DLA, DDD, "LexGetToken%s: WEIRD", EchoFilePos(&file_pos) );
  564. X    col_num(file_pos) = (startpos = p-1) - startline;
  565. X    Error(WARN, &file_pos, "unknown character (%o octal)", *startpos);
  566. X    break;
  567. X
  568. X
  569. X      case ESCAPE:
  570. X      
  571. X    col_num(file_pos) = (startpos = p-1) - startline;
  572. X    Error(WARN, &file_pos, "character %c outside quoted string", *startpos);
  573. X    break;
  574. X
  575. X
  576. X      case COMMENT:
  577. X      
  578. X    debug1(DLA, DDD, "LexGetToken%s: comment", EchoFilePos(&file_pos));
  579. X    while( (c = *p++) != '\n' && c != '\0' );
  580. X    --p;
  581. X    break;
  582. X
  583. X
  584. X      case CSPACE:
  585. X
  586. X    hcount++;
  587. X    break;
  588. X
  589. X
  590. X      case TAB:
  591. X
  592. X    hcount += 8;
  593. X    break;
  594. X
  595. X
  596. X      case NEWLINE:
  597. X      
  598. X    chpt = p;  srcnext();
  599. X    line_num(file_pos)++;
  600. X    col_num(file_pos) = 0;
  601. X    vcount++;  hcount = 0;
  602. X    startline = (p = chpt) - 1;
  603. X    break;
  604. X
  605. X
  606. X      case ENDFILE:
  607. X      
  608. X    /* close current file, if any */
  609. X    debug0(DLA, DDD, "LexGetToken: endfile");
  610. X    if( fp != null )
  611. X    { fclose(fp);  fp = null;
  612. X      this_file = ftype == SOURCE_FILE ? NextFile(this_file) : NO_FILE;
  613. X    }
  614. X
  615. X    /* open next file */
  616. X    while( this_file != NO_FILE )
  617. X    { file_num(file_pos) = this_file;
  618. X      line_num(file_pos) = 1;
  619. X      col_num(file_pos) = 0;
  620. X      fp = OpenFile(this_file, FALSE);
  621. X      if( fp != null )  break;
  622. X      Error(WARN, &file_pos, "cannot open %s", FileName(this_file));
  623. X      this_file = ftype == SOURCE_FILE ? NextFile(this_file) : NO_FILE;
  624. X    }
  625. X    if( fp != null )
  626. X    { if( offset != 0 )
  627. X      { fseek(fp, (long) offset, 0);
  628. X        offset = 0L;
  629. X      }
  630. X      frst = limit = chpt = buf;
  631. X      blksize = 0;  srcnext();
  632. X      startline = (p = chpt) - 1;
  633. X      hcount = 0;
  634. X    }
  635. X
  636. X    /* no next file, so take continuation */
  637. X    else switch( ftype )
  638. X    {
  639. X      case SOURCE_FILE:
  640. X      case DATABASE_FILE:
  641. X      
  642. X        /* input ends with "@End \Input" */
  643. X        res = NewToken(END, &file_pos, 0, 0, END_PREC, nil);
  644. X        next_token = NewToken(CLOSURE, &file_pos, 0,0, NO_PREC, StartSym);
  645. X        --p;  startline = p;
  646. X        break;
  647. X
  648. X      case INCLUDE_FILE:
  649. X
  650. X        LexPop();
  651. X        (p = chpt) - 1;
  652. X        hcount = 0;
  653. X        break;
  654. X
  655. X      default:  Error(INTERN, no_fpos, "ftype!");
  656. X
  657. X    } /* end switch */
  658. X    break;
  659. X
  660. X
  661. X      case SPECIAL:
  662. X      
  663. X    col_num(file_pos) = (startpos = p-1) - startline;
  664. X    while( chtbl[*p++] == SPECIAL );
  665. X    c = p - startpos - 1;
  666. X    do
  667. X    { res = SearchSym(startpos, c);
  668. X      --c; --p;
  669. X    } while( c > 0 && res == nil );
  670. X    goto MORE;  /* 7 lines down */
  671. X    break;
  672. X
  673. X
  674. X      case LETTER:
  675. X      
  676. X    col_num(file_pos) = (startpos = p-1) - startline;
  677. X    while( chtbl[*p++] == LETTER );  --p;
  678. X    res = SearchSym(startpos, p - startpos);
  679. X
  680. X    MORE: if( res == nil )
  681. X    { setword(res, file_pos, startpos, p-startpos);
  682. X    }
  683. X    else if( type(res) == MACRO )
  684. X    { if( recursive(res) )
  685. X      { Error(WARN, &file_pos, "recursion in macro");
  686. X        setword(res, file_pos, startpos, p-startpos);
  687. X      }
  688. X      else
  689. X      { res = CopyTokenList( sym_body(res), &file_pos );
  690. X        if( res != nil ) next_token = Delete(res, PARENT);
  691. X        else hcount = 0;
  692. X      }
  693. X    }
  694. X    else if( predefined(res) == 0 )
  695. X    { res = NewToken(CLOSURE, &file_pos, 0, 0, precedence(res), res);
  696. X    }
  697. X    else if( is_filecom(predefined(res)) )
  698. X    { OBJECT t, fname, symbs = nil;  FILE_NUM fnum;
  699. X      chpt = p;
  700. X      t = LexGetToken();
  701. X      p = chpt;
  702. X      if( predefined(res)==DATABASE || predefined(res) == SYS_DATABASE )
  703. X      { symbs = New(ACAT);
  704. X        while( type(t) == CLOSURE )
  705. X        { Link(symbs, t);
  706. X          chpt = p;  t = LexGetToken();  p = chpt;
  707. X        }
  708. X      }
  709. X      if( type(t) != LBR )
  710. X      { Error(WARN, &fpos(t), "%s expected after %s", KW_LBR, SymName(res));
  711. X        Dispose(t);
  712. X        res = nil;
  713. X        break;
  714. X      }
  715. X      Dispose(t);
  716. X      chpt = p; fname = LexGetToken(); p = chpt;
  717. X      if( type(fname) != WORD )
  718. X      { Error(WARN, &fpos(fname), "name of %s file expected here",
  719. X            SymName(res));
  720. X        Dispose(fname);
  721. X        res = nil;
  722. X        break;
  723. X      }
  724. X      chpt = p; t = LexGetToken(); p = chpt;
  725. X      if( type(t) != RBR )
  726. X      { Error(WARN, &fpos(t), "%s expected here", KW_RBR);
  727. X        Dispose(t);
  728. X        res = nil;
  729. X        break;
  730. X      }
  731. X      Dispose(t);
  732. X      if( string(fname)[0] == '"' )
  733. X        FontStripQuotes(string(fname), &fpos(fname));
  734. X      if( predefined(res)==INCLUDE  || predefined(res) == SYS_INCLUDE )
  735. X      { fnum = DefineFile(fname, INCLUDE_FILE,
  736. X            predefined(res)==INCLUDE ? INCLUDE_PATH : SYSINCLUDE_PATH);
  737. X        chpt = p;
  738. X        LexPush(fnum, 0, INCLUDE_FILE);
  739. X        res = LexGetToken();
  740. X        p = chpt;
  741. X      }
  742. X      else if( predefined(res)==DATABASE || predefined(res)==SYS_DATABASE )
  743. X      { OBJECT db, ifname;
  744. X        if( Down(symbs) == symbs )
  745. X          Error(FATAL, &fpos(fname), "symbols missing after %s",
  746. X            predefined(res) == DATABASE ? KW_DATABASE : KW_SYSDATABASE);
  747. X        if( strlen(string(fname)) + strlen(INDEX_SUFFIX) >= MAX_LINE )
  748. X          Error(FATAL,&file_pos, "file name %s is too long", string(fname));
  749. X        ifname = MakeWordTwo(string(fname), INDEX_SUFFIX, &fpos(fname));
  750. X        Dispose(fname);
  751. X        fnum = DefineFile(ifname, INDEX_FILE,
  752. X          predefined(res)==DATABASE ? DATABASE_PATH : SYSDATABASE_PATH );
  753. X        db = DbLoad(fnum, string(ifname), &fpos(ifname), TRUE, symbs);
  754. X        res = nil;
  755. X      }
  756. X      else if( predefined(res)==PREPEND || predefined(res)==SYS_PREPEND )
  757. X      { fnum = DefineFile(fname, PREPEND_FILE,
  758. X          predefined(res) == PREPEND ? INCLUDE_PATH : SYSINCLUDE_PATH);
  759. X        res = nil;
  760. X      }
  761. X      else Error(INTERN, &file_pos, "filecom!");
  762. X    }
  763. X    else res = NewToken(predefined(res), &file_pos,0,0,precedence(res),res);
  764. X    break;
  765. X
  766. X
  767. X      case QUOTE:
  768. X      
  769. X    col_num(file_pos) = (startpos = p-1) - startline;
  770. X    do switch( chtbl[*p++] )
  771. X    {
  772. X      case WEIRD:    Error(FATAL, &file_pos, "unknown character (%c octal)",
  773. X                *(p-1));
  774. X            break;
  775. X
  776. X      case ESCAPE:    if( chtbl[*p] == NEWLINE || chtbl[*p] == ENDFILE )
  777. X            { Error(WARN, &file_pos, "unterminated string");
  778. X              *(p-1) = '"';
  779. X              setword(res, file_pos, startpos, p-startpos);
  780. X            }
  781. X            else p++;
  782. X            break;
  783. X
  784. X      case NEWLINE:
  785. X      case ENDFILE:    --p;
  786. X            Error(WARN, &file_pos, "unterminated string");
  787. X            setword(res, file_pos, startpos, p-startpos);
  788. X            break;
  789. X
  790. X      case TAB:    Error(WARN, &file_pos, "tab character in string");
  791. X            *(p-1) = ' ';
  792. X            break;
  793. X
  794. X      case CSPACE:
  795. X      case COMMENT:
  796. X      case SPECIAL:
  797. X      case LETTER:    break;
  798. X
  799. X      case QUOTE:    setword(res, file_pos, startpos, p-startpos);
  800. X            break;
  801. X
  802. X      default:    Error(INTERN, &file_pos, "LexGetToken: quoted string");
  803. X            break;
  804. X
  805. X    } while( res == nil );
  806. X    break;
  807. X
  808. X
  809. X      default:
  810. X      
  811. X    Error(INTERN, &file_pos, "LexGetToken: bad chtbl[]");
  812. X    break;
  813. X
  814. X  } while( res == nil );
  815. X
  816. X  if( p - startline >= MAX_LINE )
  817. X  { col_num(file_pos) = 1;
  818. X    Error(FATAL, &file_pos, "line is too long (or final newline missing)");
  819. X  }
  820. X
  821. X  chpt = p;
  822. X  vspace(res) = vcount;
  823. X  hspace(res) = hcount;
  824. X  debug4(DLA, DD, "LexGetToken%s returning %s %s (@%d)",
  825. X    EchoFilePos(&file_pos), Image(type(res)), EchoToken(res), (int) res);
  826. X  return res;
  827. X} /* end LexGetToken */
  828. END_OF_FILE
  829.   if test 23481 -ne `wc -c <'lout/z02.c'`; then
  830.     echo shar: \"'lout/z02.c'\" unpacked with wrong size!
  831.   fi
  832.   # end of 'lout/z02.c'
  833. fi
  834. if test -f 'lout/z15.c' -a "${1}" != "-c" ; then 
  835.   echo shar: Will not clobber existing file \"'lout/z15.c'\"
  836. else
  837.   echo shar: Extracting \"'lout/z15.c'\" \(23826 characters\)
  838.   sed "s/^X//" >'lout/z15.c' <<'END_OF_FILE'
  839. X/*@z15.c:Size Constraints:EchoConstraint(), Constrained()@********************/
  840. X/*                                                                           */
  841. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.03)       */
  842. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  843. X/*                                                                           */
  844. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  845. X/*  Basser Department of Computer Science                                    */
  846. X/*  The University of Sydney 2006                                            */
  847. X/*  AUSTRALIA                                                                */
  848. X/*                                                                           */
  849. X/*  This program is free software; you can redistribute it and/or modify     */
  850. X/*  it under the terms of the GNU General Public License as published by     */
  851. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  852. X/*  any later version.                                                       */
  853. X/*                                                                           */
  854. X/*  This program is distributed in the hope that it will be useful,          */
  855. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  856. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  857. X/*  GNU General Public License for more details.                             */
  858. X/*                                                                           */
  859. X/*  You should have received a copy of the GNU General Public License        */
  860. X/*  along with this program; if not, write to the Free Software              */
  861. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  862. X/*                                                                           */
  863. X/*  FILE:         z15.c                                                      */
  864. X/*  MODULE:       Size Constraints                                           */
  865. X/*  EXTERNS:      EchoConstraint(), Constrained(), DebugConstrained()        */
  866. X/*                                                                           */
  867. X/*****************************************************************************/
  868. X#include <math.h>
  869. X#ifndef M_PI
  870. X#define M_PI       3.1415926535897931160E0
  871. X#endif
  872. X
  873. X#include "externs"
  874. X
  875. X
  876. X/*****************************************************************************/
  877. X/*                                                                           */
  878. X/*  MinConstraint(xc, yc)                                                    */
  879. X/*                                                                           */
  880. X/*  Replace *xc by the minimum of the two constraints *xc and *yc.           */
  881. X/*                                                                           */
  882. X/*****************************************************************************/
  883. X
  884. XMinConstraint(xc, yc)
  885. XCONSTRAINT *xc, *yc;
  886. X{ bc(*xc)  = min(bc(*xc),  bc(*yc));
  887. X  bfc(*xc) = min(bfc(*xc), bfc(*yc));
  888. X  fc(*xc)  = min(fc(*xc),  fc(*yc));
  889. X} /* end MinConstraint */
  890. X
  891. X
  892. X/*****************************************************************************/
  893. X/*                                                                           */
  894. X/*  EnlargeToConstraint(b, f, c)                                             */
  895. X/*                                                                           */
  896. X/*  Enlarge *b,*f to its largest possible value within constraint *c.        */
  897. X/*                                                                           */
  898. X/*****************************************************************************/
  899. X
  900. XEnlargeToConstraint(b, f, c)
  901. XLENGTH *b, *f;  CONSTRAINT *c;
  902. X{
  903. X  *f = min(bfc(*c) - *b, fc(*c));
  904. X} /* end EnlargeToConstraint */
  905. X
  906. X
  907. X/*****************************************************************************/
  908. X/*                                                                           */
  909. X/*  ReflectConstraint(xc, yc)                                                */
  910. X/*                                                                           */
  911. X/*  Set xc to the constraint which is yc with its back and forward reversed. */
  912. X/*                                                                           */
  913. X/*****************************************************************************/
  914. X
  915. X#define ReflectConstraint(xc, yc)  SetConstraint(xc, fc(yc), bfc(yc), bc(yc))
  916. X
  917. X
  918. X/*@@**************************************************************************/
  919. X/*                                                                           */
  920. X/*  static SemiRotateConstraint(xc, u, v, angle, yc)                         */
  921. X/*                                                                           */
  922. X/*  Used by RotateConstraint to calculate one rotated constraint.            */
  923. X/*                                                                           */
  924. X/*****************************************************************************/
  925. X
  926. Xstatic SemiRotateConstraint(xc, u, v, angle, yc)
  927. XCONSTRAINT *xc;  LENGTH u, v;  float angle; CONSTRAINT *yc;
  928. X{ float cs, sn;  unsigned char buff[20];
  929. X  ifdebug(DSC, D, sprintf(buff, "%.1f", angle * 360.0 / (2 * M_PI)));
  930. X  debug4(DSC, D, "SemiRotateConstraint(xc, %s, %s, %sd, %s",
  931. X    EchoLength(u), EchoLength(v), buff, EchoConstraint(yc));
  932. X  cs = cos(angle);  sn = sin(angle);
  933. X  if( fabs(cs) < 1e-6 )
  934. X    SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
  935. X  else
  936. X    SetConstraint(*xc,
  937. X      min(MAX_LEN, (bc(*yc) - u * sn) / cs),
  938. X      min(MAX_LEN, (bfc(*yc) - u * sn - v * sn) / cs),
  939. X      min(MAX_LEN, (fc(*yc) - v * sn) / cs) );
  940. X  debug1(DSC, D, "SemiRotateConstraint returning %s", EchoConstraint(xc));
  941. X} /* end SemiRotateConstraint */
  942. X
  943. X
  944. X/*@@**************************************************************************/
  945. X/*                                                                           */
  946. X/*  RotateConstraint(c, y, angle, hc, vc, dim)                               */
  947. X/*                                                                           */
  948. X/*  Take the object angle @Rotate y, which is supposed to be constrained     */
  949. X/*  horizontally by hc and vertically by vc, and determine a constraint      */
  950. X/*  (either horizontal or vertical, depending on dim) for y.                 */
  951. X/*                                                                           */
  952. X/*  The constraint returned is a trigonometric function of all these         */
  953. X/*  parameters, including the present size of y in dimension 1-dim.          */
  954. X/*                                                                           */
  955. X/*****************************************************************************/
  956. X
  957. XRotateConstraint(c, y, angle, hc, vc, dim)
  958. XCONSTRAINT *c;  OBJECT y;  LENGTH angle;  CONSTRAINT *hc, *vc;  int dim;
  959. X{ CONSTRAINT c1, c2, c3, dc;  float theta, psi;
  960. X  unsigned char buff[20];
  961. X  ifdebug(DSC, D, sprintf(buff, "%.1f", (float) angle / DG ));
  962. X  debug4(DSC, D, "RotateConstraint(c, y, %sd, %s, %s, %s)",
  963. X    buff, EchoConstraint(hc), EchoConstraint(vc), dimen(dim));
  964. X
  965. X  /* work out angle in radians between 0 and 2*PI */
  966. X  theta = (float) angle * 2 * M_PI / (float) (DG * 360);
  967. X  while( theta < 0 ) theta += 2 * M_PI;
  968. X  while( theta >= 2 * M_PI ) theta -= 2 * M_PI;
  969. X  assert( 0 <= theta && theta <= 2 * M_PI, "RotateConstraint: theta!" );
  970. X
  971. X  /* determine theta, c1, and c2 depending on which quadrant we're in */
  972. X  if( theta <= M_PI / 2.0 )   /* first quadrant */
  973. X  { theta = theta;
  974. X    CopyConstraint(c1, *hc);
  975. X    CopyConstraint(c2, *vc);
  976. X  }
  977. X  else if ( theta <= M_PI )   /* second quadrant */
  978. X  { theta -= M_PI / 2.0;
  979. X    ReflectConstraint(c1, *vc);
  980. X    CopyConstraint(c2, *hc);
  981. X  }
  982. X  else if ( theta <= 3.0 * M_PI / 2.0 )   /* third quadrant */
  983. X  { theta -= M_PI;
  984. X    ReflectConstraint(c1, *hc);
  985. X    ReflectConstraint(c2, *vc);
  986. X  }
  987. X  else /* fourth quadrant */
  988. X  { theta -= 3.0 * M_PI / 2.0;
  989. X    CopyConstraint(c1, *vc);
  990. X    ReflectConstraint(c2, *hc);
  991. X  }
  992. X  psi = M_PI / 2.0 - theta;
  993. X  debug2(DSC, D, "  c1: %s;  c2: %s", EchoConstraint(&c1), EchoConstraint(&c2));
  994. X
  995. X  /* return the minimum of the two constraints, rotated */
  996. X  if( dim == COL )
  997. X  { SemiRotateConstraint(c, back(y, ROW), fwd(y, ROW), theta, &c1);
  998. X    ReflectConstraint(c3, c2);
  999. X    SemiRotateConstraint(&dc, fwd(y, ROW), back(y, ROW), psi, &c3);
  1000. X    MinConstraint(c, &dc);
  1001. X  }
  1002. X  else
  1003. X  { SemiRotateConstraint(c, back(y, COL), fwd(y, COL), psi, &c1);
  1004. X    SemiRotateConstraint(&dc, fwd(y, COL), back(y, COL), theta, &c2);
  1005. X    MinConstraint(c, &dc);
  1006. X  }
  1007. X
  1008. X  debug1(DSC, D, "RotateConstraint returning %s", EchoConstraint(c));
  1009. X} /* end RotateConstraint */
  1010. X
  1011. X
  1012. X/*****************************************************************************/
  1013. X/*                                                                           */
  1014. X/*  InvScaleConstraint(yc, sf, xc)                                           */
  1015. X/*                                                                           */
  1016. X/*  Scale constraint xc to the inverse of the scale factor sf.               */
  1017. X/*                                                                           */
  1018. X/*****************************************************************************/
  1019. X
  1020. XInvScaleConstraint(yc, sf, xc)
  1021. XCONSTRAINT *yc;  LENGTH sf;  CONSTRAINT *xc;
  1022. X{ unsigned char buff[10];
  1023. X  ifdebug(DSC, D, sprintf(buff, "%.3f", (float) sf / SF));
  1024. X  debug2(DSC, D, "InvScaleConstraint(yc, %s, %s)", buff, EchoConstraint(xc));
  1025. X  assert( sf > 0, "InvScaleConstraint: sf <= 0!" );
  1026. X  bc(*yc)  = bc(*xc)  == MAX_LEN ? MAX_LEN : min(MAX_LEN, bc(*xc)  * SF / sf);
  1027. X  bfc(*yc) = bfc(*xc) == MAX_LEN ? MAX_LEN : min(MAX_LEN, bfc(*xc) * SF / sf);
  1028. X  fc(*yc)  = fc(*xc)  == MAX_LEN ? MAX_LEN : min(MAX_LEN, fc(*xc)  * SF / sf);
  1029. X  debug1(DSC, D, "InvScaleConstraint returning %s", EchoConstraint(yc));
  1030. X} /* end InvScaleConstraint */
  1031. X
  1032. X
  1033. X/*@@**************************************************************************/
  1034. X/*                                                                           */
  1035. X/*  static CatConstrained(x, xc, ratm, y, dim)                               */
  1036. X/*                                                                           */
  1037. X/*  Calculate the size constraint of object x, as for Constrained below.     */
  1038. X/*  y is the enclosing VCAT etc. object;  ratm is TRUE if a ^ lies after     */
  1039. X/*  x anywhere.  dim is COL or ROW.                                          */
  1040. X/*                                                                           */
  1041. X/*  The meaning of the key variables is as follows:                          */
  1042. X/*                                                                           */
  1043. X/*  be       The amount by which back(x, dim) can increase from zero         */
  1044. X/*           without having any impact on size(y, dim).  Thereafter,         */
  1045. X/*           any increase causes an equal increase in size(y, dim).          */
  1046. X/*                                                                           */
  1047. X/*  fe       The amount by which fwd(x, dim) can increase from zero          */
  1048. X/*           without having any impact on size(y, dim).  Thereafter,         */
  1049. X/*           any increase causes an equal increase in size(y, dim).          */
  1050. X/*                                                                           */
  1051. X/*  backy,   The value that back(y, dim) and fwd(y, dim) would have if x     */
  1052. X/*  fwdy     was definite with size 0,0.  They will in general be larger     */
  1053. X/*           than the present values if x is indefinite, and smaller         */
  1054. X/*           if x is definite, although it depends on marks and gaps.        */
  1055. X/*                                                                           */
  1056. X/*****************************************************************************/
  1057. X
  1058. Xstatic CatConstrained(x, xc, ratm, y, dim)
  1059. XOBJECT x;  CONSTRAINT *xc; BOOLEAN ratm;  OBJECT y;  int dim;
  1060. X{ int side;            /* x's side of add-set y: BACK, ON or FWD    */
  1061. X  CONSTRAINT yc;        /* constraints on y                          */
  1062. X  LENGTH backy, fwdy;        /* back(y), fwd(y) would be if x was (0, 0)  */
  1063. X  LENGTH be, fe;        /* amount back(x), fwd(x) can be for free    */
  1064. X  LENGTH beffect, feffect;    /* scratch variables for calculations        */
  1065. X  LENGTH seffect;        /* scratch variables for calculations        */
  1066. X  OBJECT link, sg, pg;    /* link to x, its successor and predecessor  */
  1067. X  OBJECT prec_def, sd;    /* definite object preceding (succeeding) x  */
  1068. X  int tb, tbf, tf, tbc, tbfc, tfc, mxy, myz;
  1069. X
  1070. X  Constrained(y, &yc, dim);
  1071. X  if( constrained(yc) )
  1072. X  {
  1073. X    /* find x's link, and its neighbours and their links */
  1074. X    link = UpDim(x, dim);
  1075. X
  1076. X    /* find neighbouring definite objects, if any */
  1077. X    SetNeighbours(link, ratm, &pg, &prec_def, &sg, &sd, &side);
  1078. X
  1079. X    /* amount of space available at x without changing the size of y */
  1080. X    be = pg == nil ? 0 : ExtraGap(fwd(prec_def, dim), 0, &gap(pg), BACK);
  1081. X    fe = sg == nil ? 0 : ExtraGap(0, back(sd, dim),      &gap(sg), FWD);
  1082. X
  1083. X    if( is_indefinite(type(x)) )
  1084. X    {
  1085. X      /* insert two lengths and delete one */
  1086. X      beffect = pg == nil ? 0 : MinGap(fwd(prec_def, dim), 0, 0, &gap(pg));
  1087. X      feffect = sg == nil ? 0 : MinGap(0, back(sd,dim), fwd(sd,dim), &gap(sg));
  1088. X      seffect = pg == nil ?
  1089. X      sg == nil ? 0 : back(sd, dim) :
  1090. X      sg == nil ? fwd(prec_def, dim) :
  1091. X        MinGap(fwd(prec_def, dim), back(sd, dim), fwd(sd, dim), &gap(sg));
  1092. X
  1093. X      switch( side )
  1094. X      {
  1095. X    case BACK:    backy = back(y, dim) + beffect + feffect - seffect;
  1096. X            fwdy  = fwd(y, dim);
  1097. X            break;
  1098. X
  1099. X    case ON:    /* must be first, other cases prohibited */
  1100. X            backy = 0;
  1101. X            fwdy = fwd(y, dim) + feffect;
  1102. X            break;
  1103. X
  1104. X    case FWD:    backy = back(y, dim);
  1105. X            fwdy  = fwd(y, dim) + beffect + feffect - seffect;
  1106. X            break;
  1107. X      }
  1108. X    }
  1109. X
  1110. X    else /* x is definite */
  1111. X
  1112. X    { beffect = pg == nil ? back(x, dim) :
  1113. X    MinGap(fwd(prec_def, dim), back(x,dim), fwd(x,dim), &gap(pg)) -
  1114. X    MinGap(fwd(prec_def, dim), 0,           0,          &gap(pg));
  1115. X
  1116. X      feffect = sg == nil ? fwd(x, dim) :
  1117. X    MinGap(fwd(x, dim), back(sd, dim), fwd(sd, dim), &gap(sg)) -
  1118. X    MinGap(0,           back(sd, dim), fwd(sd, dim), &gap(sg));
  1119. X
  1120. X      switch( side )
  1121. X      {
  1122. X    case BACK:    backy = back(y, dim) - beffect - feffect;
  1123. X            fwdy  = fwd(y, dim);
  1124. X            break;
  1125. X
  1126. X    case ON:    backy = back(y, dim) - beffect;
  1127. X            fwdy  = fwd(y, dim)  - feffect;
  1128. X            break;
  1129. X
  1130. X    case FWD:    backy = back(y, dim);
  1131. X            fwdy  = fwd(y, dim) - beffect - feffect;
  1132. X            break;
  1133. X      }
  1134. X    }
  1135. X
  1136. X    debug5(DSC, DDD, "side: %s, backy: %s, fwdy: %s, be: %s, fe: %s",
  1137. X        Image(side), EchoLength(backy), EchoLength(fwdy),
  1138. X        EchoLength(be), EchoLength(fe) );
  1139. X
  1140. X    if( !FitsConstraint(backy, fwdy, yc) )
  1141. X      SetConstraint(*xc, -1, -1, -1);
  1142. X    else switch( side )
  1143. X    {
  1144. X
  1145. X      case BACK:
  1146. X    
  1147. X    tbc = bc(yc) == MAX_LEN ? MAX_LEN : bc(yc) - backy;
  1148. X    tbfc = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - backy - fwdy;
  1149. X    mxy = min(tbc, tbfc);
  1150. X    tb  = min(MAX_LEN, be + mxy);
  1151. X    tbf = min(MAX_LEN, be + fe + mxy);
  1152. X    tf  = min(MAX_LEN, fe + mxy);
  1153. X    SetConstraint(*xc, tb, tbf, tf);
  1154. X    break;
  1155. X
  1156. X
  1157. X      case ON:
  1158. X    
  1159. X    tbc = bc(yc) == MAX_LEN ? MAX_LEN : bc(yc) - backy;
  1160. X    tbfc = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - backy - fwdy;
  1161. X    tfc = fc(yc) == MAX_LEN ? MAX_LEN : fc(yc) - fwdy;
  1162. X    mxy = min(tbc, tbfc);
  1163. X    myz = min(tfc, tbfc);
  1164. X    tb  = min(MAX_LEN, be + mxy);
  1165. X    tbf = min(MAX_LEN, be + fe + tbfc);
  1166. X    tf  = min(MAX_LEN, fe + myz);
  1167. X    SetConstraint(*xc, tb, tbf, tf);
  1168. X    break;
  1169. X    
  1170. X
  1171. X      case FWD:
  1172. X
  1173. X    tfc = fc(yc) == MAX_LEN ? MAX_LEN : fc(yc) - fwdy;
  1174. X    tbfc = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - backy - fwdy;
  1175. X    mxy = min(tfc, tbfc);
  1176. X    tb  = min(MAX_LEN, be + mxy);
  1177. X    tbf = min(MAX_LEN, be + fe + mxy);
  1178. X    tf  = min(MAX_LEN, fe + mxy);
  1179. X    SetConstraint(*xc, tb, tbf, tf);
  1180. X    break;
  1181. X    
  1182. X    }
  1183. X  } /* end if( constrained ) */
  1184. X  else SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
  1185. X} /* end CatConstrained */
  1186. X
  1187. X
  1188. X/*@@**************************************************************************/
  1189. X/*                                                                           */
  1190. X/*  Constrained(x, xc, dim)                                                  */
  1191. X/*                                                                           */
  1192. X/*  Calculate the size constraint of object x, and return it in *xc.         */
  1193. X/*                                                                           */
  1194. X/*****************************************************************************/
  1195. X
  1196. XConstrained(x, xc, dim)
  1197. XOBJECT x;  CONSTRAINT *xc;  int dim;
  1198. X{ OBJECT y, link, lp, rp, z, tlink, g;
  1199. X  CONSTRAINT yc, hc, vc;
  1200. X  BOOLEAN ratm;
  1201. X  LENGTH xback, xfwd;
  1202. X  int tb, tf, tbf, tbc, tfc;
  1203. X  debug2(DSC, DD, "[ Constrained( %s, xc, %s )", EchoObject(null,x),dimen(dim));
  1204. X  assert( Up(x) != x, "Constrained: x has no parent!" );
  1205. X
  1206. X  /* find x's parent, y */
  1207. X  link = UpDim(x, dim);  ratm = FALSE;
  1208. X  for( tlink = NextDown(link);  type(tlink) == LINK;  tlink = NextDown(tlink) )
  1209. X  { Child(g, tlink);
  1210. X    if( type(g) == GAP_OBJ && mark(gap(g)) )  ratm = TRUE;
  1211. X  }
  1212. X  y = tlink;
  1213. X  debug1(DSC, DDD, "x's parent y = %s", Image(type(y)));
  1214. X  ifdebug(DSC, DDD, EchoObject(stderr, y));
  1215. X
  1216. X  switch( type(y) )
  1217. X  {
  1218. X
  1219. X    case GRAPHIC:
  1220. X    case ONE_COL:
  1221. X    case ONE_ROW:
  1222. X    case HCONTRACT:
  1223. X    case VCONTRACT:
  1224. X    case HEXPAND:
  1225. X    case VEXPAND:
  1226. X    case PADJUST:
  1227. X    case HADJUST:
  1228. X    case VADJUST:
  1229. X    case SPLIT:
  1230. X    
  1231. X      Constrained(y, xc, dim);
  1232. X      break;
  1233. X
  1234. X
  1235. X    case VSCALE:
  1236. X    case HSCALE:
  1237. X    
  1238. X      if( (dim == COL) == (type(y) == HSCALE) )
  1239. X    SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
  1240. X      else Constrained(y, xc, dim);
  1241. X      break;
  1242. X
  1243. X
  1244. X    case SCALE:
  1245. X
  1246. X      Constrained(y, &yc, dim);
  1247. X      InvScaleConstraint(xc,
  1248. X    dim == COL ? bc(constraint(y)) : fc(constraint(y)), &yc);
  1249. X      break;
  1250. X
  1251. X
  1252. X    case ROTATE:
  1253. X    
  1254. X      Constrained(y, &hc, COL);
  1255. X      Constrained(y, &vc, ROW);
  1256. X      RotateConstraint(xc, x, sparec(constraint(y)), &hc, &vc, dim);
  1257. X      break;
  1258. X
  1259. X
  1260. X    case WIDE:
  1261. X    case HIGH:
  1262. X    
  1263. X      Constrained(y, xc, dim);
  1264. X      if( (type(y)==WIDE) == (dim==COL) )
  1265. X        MinConstraint(xc, &constraint(y));
  1266. X      break;
  1267. X
  1268. X
  1269. X    case HEAD:
  1270. X    
  1271. X      if( dim == ROW ) SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
  1272. X      else
  1273. X      {    CopyConstraint(yc, constraint(y));
  1274. X    debug1(DSC, DD, "  head: %s; val is:", EchoConstraint(&yc));
  1275. X    ifdebug(DSC, DD, EchoObject(stderr, y));
  1276. X    goto REST_OF_HEAD;   /* a few lines down */
  1277. X      }
  1278. X      break;
  1279. X
  1280. X
  1281. X    case COL_THR:
  1282. X    case ROW_THR:
  1283. X
  1284. X      assert( (type(y)==COL_THR) == (dim==COL), "Constrained: COL_THR!" );
  1285. X      Constrained(y, &yc, dim);
  1286. X      tb = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - fwd(y, dim);
  1287. X      tb = min(bc(yc), tb);
  1288. X      tf = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - back(y, dim);
  1289. X      tf = min(fc(yc), tf);
  1290. X      SetConstraint(*xc, tb, bfc(yc), tf);
  1291. X      break;
  1292. X
  1293. X
  1294. X    case VCAT:
  1295. X    case HCAT:
  1296. X    case ACAT:
  1297. X    
  1298. X      if( (type(y)==VCAT) == (dim==ROW) )
  1299. X      {    CatConstrained(x, xc, ratm, y, dim);
  1300. X    break;
  1301. X      }
  1302. X      Constrained(y, &yc, dim);
  1303. X      if( !constrained(yc) )  SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
  1304. X      else
  1305. X      {
  1306. X    REST_OF_HEAD:
  1307. X    /* let lp and rp be the links of the gaps delimiting */
  1308. X    /* the components joined to x (or parent if no such) */
  1309. X    for( lp = PrevDown(link);  lp != y;  lp = PrevDown(lp) )
  1310. X    { Child(z, lp);
  1311. X      if( type(z) == GAP_OBJ && !join(gap(z)) )  break;
  1312. X    }
  1313. X    for( rp = NextDown(link);  rp != y;  rp = NextDown(rp) )
  1314. X    { Child(z, rp);
  1315. X      if( type(z) == GAP_OBJ && !join(gap(z)) )  break;
  1316. X    }
  1317. X    if( lp == y && rp == y && !(type(y) == HEAD && seen_nojoin(y)) )
  1318. X    {
  1319. X      /* if whole object is joined, do this */
  1320. X          tb = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - fwd(y, dim);
  1321. X          tb = min(bc(yc), tb);
  1322. X          tf = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - back(y, dim);
  1323. X          tf = min(fc(yc), tf);
  1324. X          SetConstraint(*xc, tb, bfc(yc), tf);
  1325. X    }
  1326. X    else
  1327. X    {
  1328. X      /* if // or || is present, do this */
  1329. X      xback = xfwd = 0;
  1330. X      for(link = NextDown(lp); link != rp;  link = NextDown(link) )
  1331. X      { Child(z, link);
  1332. X        if( type(z) == GAP_OBJ || is_index(type(z)) )  continue;
  1333. X        xback = max(xback, back(z, dim));
  1334. X        xfwd  = max(xfwd,  fwd(z, dim));
  1335. X      }
  1336. X      debug2(DSC, DD, "  lp != rp; xback,xfwd = %s,%s",
  1337. X            EchoLength(xback), EchoLength(xfwd));
  1338. X      tbf = min(bfc(yc), fc(yc));
  1339. X      tbc = tbf == MAX_LEN ? MAX_LEN : tbf - xfwd;
  1340. X      tfc = tbf == MAX_LEN ? MAX_LEN : tbf - xback;
  1341. X      SetConstraint(*xc, tbc, tbf, tfc);
  1342. X    }
  1343. X      }
  1344. X      break;
  1345. X
  1346. X
  1347. X    default:
  1348. X    
  1349. X      Error(INTERN, &fpos(y), "Constrained: %s", Image(type(y)) );
  1350. X      break;
  1351. X
  1352. X  }
  1353. X
  1354. X  debug1(DSC, DD, "] Constrained returning %s", EchoConstraint(xc));
  1355. X} /* end Constrained */
  1356. X
  1357. X
  1358. X/*@@**************************************************************************/
  1359. X/*                                                                           */
  1360. X/*  unsigned char *EchoConstraint(c)                                         */
  1361. X/*                                                                           */
  1362. X/*  Returns a string showing constraint *c, in centimetres.                  */
  1363. X/*                                                                           */
  1364. X/*****************************************************************************/
  1365. X#if DEBUG_ON
  1366. X
  1367. Xunsigned char *EchoConstraint(c)
  1368. XCONSTRAINT *c;
  1369. X{ static unsigned char str[2][40];
  1370. X  static int i = 0;
  1371. X  i = (i+1) % 2;
  1372. X  sprintf(str[i], "<");
  1373. X  if( bc(*c)==MAX_LEN )  sprintf(&str[i][strlen(str[i])], "INF, ");
  1374. X  else sprintf(&str[i][strlen(str[i])], "%.3fc, ", (float) bc(*c)/CM);
  1375. X  if( bfc(*c)==MAX_LEN )  sprintf(&str[i][strlen(str[i])], "INF, ");
  1376. X  else sprintf(&str[i][strlen(str[i])], "%.3fc, ", (float) bfc(*c)/CM);
  1377. X  if( fc(*c)==MAX_LEN )  sprintf(&str[i][strlen(str[i])], "INF>");
  1378. X  else sprintf(&str[i][strlen(str[i])], "%.3fc>", (float) fc(*c)/CM);
  1379. X  return str[i];
  1380. X} /* end EchoConstraint */
  1381. X
  1382. X
  1383. X/*****************************************************************************/
  1384. X/*                                                                           */
  1385. X/*  DebugConstrained(x)                                                      */
  1386. X/*                                                                           */
  1387. X/*  Calculate and print the constraints of all closures lying within         */
  1388. X/*  object x.                                                                */
  1389. X/*                                                                           */
  1390. X/*****************************************************************************/
  1391. X
  1392. XDebugConstrained(x)
  1393. XOBJECT x;
  1394. X{ OBJECT y, link;
  1395. X  CONSTRAINT c;
  1396. X  debug1(DSC, DDD, "DebugConstrained( %s )", EchoObject(null, x) );
  1397. X  switch( type(x) )
  1398. X  {
  1399. X
  1400. X    case CROSS:
  1401. X    case ROTATE:
  1402. X    case INCGRAPHIC:
  1403. X    case SINCGRAPHIC:
  1404. X    case GRAPHIC:
  1405. X    case WORD:
  1406. X    
  1407. X      break;
  1408. X
  1409. X
  1410. X    case CLOSURE:
  1411. X    
  1412. X      Constrained(x, &c, COL);
  1413. X      debug2(DSC, D, "Constrained( %s, &c, COL ) = %s",
  1414. X    EchoObject(null, x), EchoConstraint(&c));
  1415. X      Constrained(x, &c, ROW);
  1416. X      debug2(DSC, D, "Constrained( %s, &c, ROW ) = %s",
  1417. X    EchoObject(null, x), EchoConstraint(&c));
  1418. X      break;
  1419. X
  1420. X
  1421. X    case SPLIT:
  1422. X    
  1423. X      link = DownDim(x, COL);  Child(y, link);
  1424. X      DebugConstrained(y);
  1425. X      break;
  1426. X
  1427. X
  1428. X    case HEAD:
  1429. X    case ONE_COL:
  1430. X    case ONE_ROW:
  1431. X    case HCONTRACT:
  1432. X    case VCONTRACT:
  1433. X    case HEXPAND:
  1434. X    case VEXPAND:
  1435. X    case PADJUST:
  1436. X    case HADJUST:
  1437. X    case VADJUST:
  1438. X    case HSCALE:
  1439. X    case VSCALE:
  1440. X    case SCALE:
  1441. X    case WIDE:
  1442. X    case HIGH:
  1443. X    
  1444. X      link = Down(x);  Child(y, link);
  1445. X      DebugConstrained(y);
  1446. X      break;
  1447. X
  1448. X
  1449. X    case COL_THR:
  1450. X    case VCAT:
  1451. X    case HCAT:
  1452. X    case ACAT:
  1453. X    
  1454. X      for( link = Down(x);  link != x;  link =NextDown(link) )
  1455. X      {    Child(y, link);
  1456. X    if( type(y) != GAP_OBJ && !is_index(type(y)) )  DebugConstrained(y);
  1457. X      }
  1458. X      break;
  1459. X
  1460. X
  1461. X    default:
  1462. X    
  1463. X      Error(INTERN, &fpos(x), "DebugConstrained: type(x)= %s", Image(type(x)) );
  1464. X      break;
  1465. X
  1466. X  }
  1467. X  debug0(DSC, DDD, "DebugConstrained returning.");
  1468. X} /* end DebugConstrained */
  1469. X#endif
  1470. END_OF_FILE
  1471.   if test 23826 -ne `wc -c <'lout/z15.c'`; then
  1472.     echo shar: \"'lout/z15.c'\" unpacked with wrong size!
  1473.   fi
  1474.   # end of 'lout/z15.c'
  1475. fi
  1476. if test -f 'lout/z29.c' -a "${1}" != "-c" ; then 
  1477.   echo shar: Will not clobber existing file \"'lout/z29.c'\"
  1478. else
  1479.   echo shar: Extracting \"'lout/z29.c'\" \(23936 characters\)
  1480.   sed "s/^X//" >'lout/z29.c' <<'END_OF_FILE'
  1481. X/*@z29.c:Symbol Table:SearchSym(), InsertSym(), PushScope()@******************/
  1482. X/*                                                                           */
  1483. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.03)       */
  1484. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  1485. X/*                                                                           */
  1486. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  1487. X/*  Basser Department of Computer Science                                    */
  1488. X/*  The University of Sydney 2006                                            */
  1489. X/*  AUSTRALIA                                                                */
  1490. X/*                                                                           */
  1491. X/*  This program is free software; you can redistribute it and/or modify     */
  1492. X/*  it under the terms of the GNU General Public License as published by     */
  1493. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  1494. X/*  any later version.                                                       */
  1495. X/*                                                                           */
  1496. X/*  This program is distributed in the hope that it will be useful,          */
  1497. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  1498. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  1499. X/*  GNU General Public License for more details.                             */
  1500. X/*                                                                           */
  1501. X/*  You should have received a copy of the GNU General Public License        */
  1502. X/*  along with this program; if not, write to the Free Software              */
  1503. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  1504. X/*                                                                           */
  1505. X/*  FILE:         z29.c                                                      */
  1506. X/*  MODULE:       Symbol Table                                               */
  1507. X/*  EXTERNS:      PushScope(), PopScope(), BodyParAllowed(), BodyParNotAll() */
  1508. X/*                InitSym(), SearchSym(), InsertSym(), DeleteEverySym(),     */
  1509. X/*                SymName(), FullSymName(), ChildSym()                       */
  1510. X/*                                                                           */
  1511. X/*****************************************************************************/
  1512. X#include "externs"
  1513. X
  1514. X#define    MAX_STACK     40        /* size of scope stack               */
  1515. X#define    MAX_TAB        1024        /* size of hash table                */
  1516. X#define    TAB_MASK    0x3FF        /* i & TAB_MASK == i % MAX_TAB       */
  1517. X
  1518. X#define    length(x)    word_font(x)
  1519. X
  1520. Xstatic    OBJECT        scope[MAX_STACK];        /* the scope stack   */
  1521. Xstatic    BOOLEAN        npars_only[MAX_STACK];        /* look for NPAR exc */
  1522. Xstatic    BOOLEAN        vis_only[MAX_STACK];        /* look for visibles */
  1523. Xstatic    BOOLEAN        body_ok[MAX_STACK];        /* look for body par */
  1524. Xstatic    BOOLEAN        suppress_scope;            /* suppress scoping  */
  1525. Xstatic    BOOLEAN        suppress_visible;        /* suppress visible  */
  1526. Xstatic    int        scope_top;            /* scope stack top   */
  1527. Xstatic    struct { OBJECT f1, f2; } symtab[MAX_TAB];    /* the hash table    */
  1528. X#if DEBUG_ON
  1529. Xstatic    int        sym_spread[MAX_TAB] = { 0 };    /* hash table spread */
  1530. Xstatic    int        sym_count = 0;            /* symbol count      */
  1531. X#endif
  1532. X
  1533. X
  1534. X/*****************************************************************************/
  1535. X/*                                                                           */
  1536. X/*  #define hash(str, len, val)                                              */
  1537. X/*                                                                           */
  1538. X/*  Set val to the hash value of string str, which has length len.           */
  1539. X/*  The hash function is just the character sum mod MAX_TAB.                 */
  1540. X/*  This definition assumes that working variables rlen and x exist.         */
  1541. X/*                                                                           */
  1542. X/*****************************************************************************/
  1543. X
  1544. X#define hash(str, len, val)                        \
  1545. X{ rlen = len;                                \
  1546. X  x    = str;                                \
  1547. X  val  = *x++;                                \
  1548. X  while( --rlen )  val += *x++;                        \
  1549. X  val  &= TAB_MASK;                            \
  1550. X}
  1551. X
  1552. X
  1553. X/*****************************************************************************/
  1554. X/*                                                                           */
  1555. X/*  InitSym()                                                                */
  1556. X/*                                                                           */
  1557. X/*  Initialize the symbol table to empty.                                    */
  1558. X/*                                                                           */
  1559. X/*****************************************************************************/
  1560. X
  1561. XInitSym()
  1562. X{ int i;
  1563. X  scope_top = 0;
  1564. X  suppress_scope = FALSE;
  1565. X  suppress_visible = FALSE;
  1566. X  for( i = 0;  i < MAX_TAB;  i++ )
  1567. X    symtab[i].f1 = symtab[i].f2 = (OBJECT) &symtab[i];
  1568. X} /* end InitSym */
  1569. X
  1570. X
  1571. X/*@@**************************************************************************/
  1572. X/*                                                                           */
  1573. X/*  PushScope(x, npars, vis)                                                 */
  1574. X/*  PopScope()                                                               */
  1575. X/*                                                                           */
  1576. X/*  Add or remove an OBJECT x (which must be in the symbol table) to or from */
  1577. X/*  the scope stack.  If npars is TRUE, only the named parameters of x are   */
  1578. X/*  added to scope.  If vis is TRUE, only visible locals and parameters are  */
  1579. X/*  added.                                                                   */
  1580. X/*                                                                           */
  1581. X/*****************************************************************************/
  1582. X
  1583. XPushScope(x, npars, vis)
  1584. XOBJECT x;  BOOLEAN npars, vis;
  1585. X{ debug2(DST, DD, "[ PushScope( %s, %s )", SymName(x), bool(npars));
  1586. X  assert( suppress_scope == FALSE, "PushScope: suppress_scope!" );
  1587. X  if( scope_top >= MAX_STACK )
  1588. X  { int i;
  1589. X    for( i = 0; i < scope_top; i++ )
  1590. X      debug2(DST, D, "  scope[%2d] = %s", i, SymName(scope[i]));
  1591. X    Error(INTERN, &fpos(x), "scope depth limit exceeded");
  1592. X  }
  1593. X  scope[scope_top]      = x;
  1594. X  npars_only[scope_top] = npars;
  1595. X  vis_only[scope_top]   = vis;
  1596. X  body_ok[scope_top]    = FALSE;
  1597. X  scope_top++;
  1598. X} /* end PushScope */
  1599. X
  1600. XPopScope()
  1601. X{ debug0(DST, DD, "] PopScope()");
  1602. X  assert( scope_top > 0, "tried to pop empty scope stack");
  1603. X  assert( suppress_scope == FALSE, "PopScope: suppress_scope!" );
  1604. X  scope_top--;
  1605. X} /* end PopScope */
  1606. X
  1607. X
  1608. X/*****************************************************************************/
  1609. X/*                                                                           */
  1610. X/*  SuppressVisible()                                                        */
  1611. X/*  UnSuppressVisible()                                                      */
  1612. X/*                                                                           */
  1613. X/*  Suppress all scopes (so that all calls to SearchSym fail); and undo it.  */
  1614. X/*                                                                           */
  1615. X/*****************************************************************************/
  1616. X
  1617. XSuppressVisible()
  1618. X{ debug0(DST, DD, "[ SuppressVisible()");
  1619. X  suppress_visible = TRUE;
  1620. X} /* end SuppressVisible */
  1621. X
  1622. XUnSuppressVisible()
  1623. X{ debug0(DST, DD, "] UnSuppressVisible()");
  1624. X  suppress_visible = FALSE;
  1625. X} /* end UnSuppressVisible */
  1626. X
  1627. X
  1628. X/*****************************************************************************/
  1629. X/*                                                                           */
  1630. X/*  SuppressScope()                                                          */
  1631. X/*  UnSuppressScope()                                                        */
  1632. X/*                                                                           */
  1633. X/*  Suppress all scopes (so that all calls to SearchSym fail); and undo it.  */
  1634. X/*                                                                           */
  1635. X/*****************************************************************************/
  1636. X
  1637. X
  1638. XSuppressScope()
  1639. X{ debug0(DST, DD, "[ SuppressScope()");
  1640. X  suppress_scope = TRUE;
  1641. X} /* end SuppressScope */
  1642. X
  1643. XUnSuppressScope()
  1644. X{ debug0(DST, DD, "] UnSuppressScope()");
  1645. X  suppress_scope = FALSE;
  1646. X} /* end UnSuppressScope */
  1647. X
  1648. X
  1649. X/*****************************************************************************/
  1650. X/*                                                                           */
  1651. X/*  SwitchScope(sym)                                                         */
  1652. X/*  UnSwitchScope(sym)                                                       */
  1653. X/*                                                                           */
  1654. X/*  Switch to the scope of sym (if nil, StartSym); and switch back again.    */
  1655. X/*                                                                           */
  1656. X/*****************************************************************************/
  1657. X
  1658. XSwitchScope(sym)
  1659. XOBJECT sym;
  1660. X{ int i;
  1661. X  OBJECT new_scopes[MAX_STACK];
  1662. X  if( sym == nil )  PushScope(StartSym, FALSE, FALSE);
  1663. X  else
  1664. X  { i = 0;
  1665. X    while( sym != StartSym )
  1666. X    { new_scopes[i++] = enclosing(sym);
  1667. X      sym = enclosing(sym);
  1668. X    }
  1669. X    while( i > 0 )  PushScope(new_scopes[--i], FALSE, FALSE);
  1670. X  }
  1671. X}
  1672. X
  1673. XUnSwitchScope(sym)
  1674. XOBJECT sym;
  1675. X{ if( sym == nil )  PopScope();
  1676. X  else
  1677. X  { while( sym != StartSym )
  1678. X    { PopScope();
  1679. X      sym = enclosing(sym);
  1680. X    }
  1681. X  }
  1682. X}
  1683. X
  1684. X
  1685. X/*****************************************************************************/
  1686. X/*                                                                           */
  1687. X/*  BodyParAllowed()                                                         */
  1688. X/*  BodyParNotAllowed()                                                      */
  1689. X/*                                                                           */
  1690. X/*  Allow or disallow invokations of the body parameter of the current tos.  */
  1691. X/*                                                                           */
  1692. X/*****************************************************************************/
  1693. X
  1694. XBodyParAllowed()
  1695. X{ debug0(DST, DD, "BodyParAllowed()");
  1696. X  body_ok[scope_top-1] = TRUE;
  1697. X} /* end BodyParAllowed */
  1698. X
  1699. XBodyParNotAllowed()
  1700. X{ debug0(DST, DD, "BodyParNotAllowed()");
  1701. X  body_ok[scope_top-1] = FALSE;
  1702. X} /* end BodyParNotAllowed */
  1703. X
  1704. X
  1705. X/*@@**************************************************************************/
  1706. X/*                                                                           */
  1707. X/*  OBJECT InsertSym(str, xtype, xfpos, xprecedence, indefinite, xrecursive, */
  1708. X/*                                         xpredefined, xenclosing, xbody)   */
  1709. X/*                                                                           */
  1710. X/*  Insert a new symbol into the table.  Its string value is str.            */
  1711. X/*  Initialise the symbol as the parameters indicate.                        */
  1712. X/*  Return a pointer to the new symbol.                                      */
  1713. X/*  If str is not a valid symbol name, InsertSym prints an error             */
  1714. X/*  message and does not insert the symbol.                                  */
  1715. X/*                                                                           */
  1716. X/*****************************************************************************/
  1717. X
  1718. XOBJECT InsertSym(str, xtype, xfpos, xprecedence, xindefinite, xrecursive,
  1719. X                         xpredefined, xenclosing, xbody)
  1720. Xunsigned char *str;  unsigned char xtype;
  1721. XFILE_POS *xfpos; unsigned char xprecedence;
  1722. XBOOLEAN xindefinite, xrecursive;  unsigned xpredefined;
  1723. XOBJECT xenclosing, xbody;
  1724. X{ register int sum, rlen;
  1725. X  register unsigned char *x;
  1726. X  OBJECT p, q, s, link, entry, plink;  int len;
  1727. X
  1728. X  debug3(DST, DD, "InsertSym( %s, %s, in %s )",
  1729. X    Image(xtype), str, SymName(xenclosing));
  1730. X  if( !LexLegalName(str) ) Error(WARN, xfpos, "invalid symbol name %s", str);
  1731. X
  1732. X  s = New(xtype);
  1733. X  FposCopy(fpos(s), *xfpos);
  1734. X  has_body(s)    = FALSE;
  1735. X  right_assoc(s) = TRUE;
  1736. X  precedence(s)  = xprecedence;
  1737. X  indefinite(s)  = xindefinite;
  1738. X  recursive(s)   = xrecursive;
  1739. X  predefined(s)  = xpredefined;
  1740. X  enclosing(s)   = xenclosing;
  1741. X  sym_body(s)    = xbody;
  1742. X  base_uses(s)   = nil;
  1743. X  uses(s)        = nil;
  1744. X  marker(s)      = nil;
  1745. X  cross_sym(s)   = nil;
  1746. X  is_extern_target(s) = FALSE;
  1747. X  uses_extern_target(s) = FALSE;
  1748. X  visible(s)     = FALSE;
  1749. X  uses_galley(s) = FALSE;
  1750. X
  1751. X  uses_count(s)  = 0;
  1752. X  dirty(s)       = FALSE;
  1753. X  if( enclosing(s) != nil && type(enclosing(s)) == NPAR )
  1754. X    dirty(enclosing(s)) = TRUE;
  1755. X
  1756. X  has_par(s)     = FALSE;
  1757. X  has_lpar(s)    = FALSE;
  1758. X  has_rpar(s)    = FALSE;
  1759. X  if( is_par(type(s)) )  has_par(enclosing(s))  = TRUE;
  1760. X  if( type(s) == LPAR )  has_lpar(enclosing(s)) = TRUE;
  1761. X  if( type(s) == RPAR )  has_rpar(enclosing(s)) = TRUE;
  1762. X
  1763. X  has_target(s)  = FALSE;
  1764. X  force_target(s) = FALSE;
  1765. X  if( strcmp(str, KW_TARGET) != 0 ) is_target(s) = FALSE;
  1766. X  else
  1767. X  { is_target(s) = has_target(enclosing(s)) = TRUE;
  1768. X    if( has_key(enclosing(s)) && xbody != nil && type(xbody) == CROSS )
  1769. X    { if( LastDown(xbody) != Down(xbody) )
  1770. X      { OBJECT sym;
  1771. X    Child(sym, Down(xbody));
  1772. X    if( type(sym) == CLOSURE )
  1773. X    { is_extern_target(actual(sym)) = TRUE;
  1774. X      uses_extern_target(actual(sym)) = TRUE;
  1775. X    }
  1776. X      }
  1777. X    }
  1778. X  }
  1779. X
  1780. X  has_tag(s)  = FALSE;
  1781. X  if( strcmp(str, KW_TAG) != 0 ) is_tag(s) = FALSE;
  1782. X  else is_tag(s) = has_tag(enclosing(s)) = dirty(enclosing(s)) = TRUE;
  1783. X
  1784. X  has_key(s)  = FALSE;
  1785. X  if( strcmp(str, KW_KEY) != 0 ) is_key(s) = FALSE;
  1786. X  else is_key(s) = has_key(enclosing(s)) = TRUE;
  1787. X
  1788. X  if( type(s) == RPAR && has_body(enclosing(s)) && (is_tag(s) || is_key(s)) )
  1789. X    Error(WARN, &fpos(s), "a body parameter may not be named %s", str);
  1790. X
  1791. X  len = strlen(str);
  1792. X  hash(str, len, sum);
  1793. X
  1794. X  ifdebug(DST, D, sym_spread[sum]++;  sym_count++);
  1795. X  entry = (OBJECT) &symtab[sum];
  1796. X  for( plink = Down(entry);  plink != entry;  plink = NextDown(plink) )
  1797. X  { Child(p, plink);
  1798. X    if( length(p) == len && strcmp(str, string(p)) == 0 )
  1799. X    { for( link = Down(p);  link != p;  link = NextDown(link) )
  1800. X      {    Child(q, link);
  1801. X    if( enclosing(s) == enclosing(q) )
  1802. X    { Error(WARN, &fpos(s), "symbol %s previously defined at%s",
  1803. X        str, EchoFilePos(&fpos(q)) );
  1804. X      break;
  1805. X    }
  1806. X      }
  1807. X      goto wrapup;
  1808. X    }
  1809. X  }
  1810. X
  1811. X  /* need a new OBJECT as well as s */
  1812. X  p = NewWord(len, xfpos);
  1813. X  length(p) = len;
  1814. X  strcpy(string(p), str);
  1815. X  Link(entry, p);
  1816. X
  1817. X wrapup:
  1818. X  Link(p, s);
  1819. X  if( enclosing(s) != nil ) Link(enclosing(s), s);
  1820. X  debug2(DST, DD, "InsertSym Link(%s, %s) and returning.",
  1821. X        SymName(enclosing(s)), SymName(s));
  1822. X  return s;
  1823. X} /* end InsertSym */
  1824. X
  1825. X
  1826. X/*****************************************************************************/
  1827. X/*                                                                           */
  1828. X/*  OBJECT SearchSym(str, len)                                               */
  1829. X/*                                                                           */
  1830. X/*  Search the symbol table for str, with length len, and return an          */
  1831. X/*  OBJECT referencing the entry if found.  Otherwise return nil.            */
  1832. X/*                                                                           */
  1833. X/*****************************************************************************/
  1834. X
  1835. XOBJECT SearchSym(str, len)
  1836. Xunsigned char *str;  int len;
  1837. X{ register int rlen, sum;
  1838. X  register unsigned char *x, *y;
  1839. X  OBJECT p, q, link, plink, entry;
  1840. X  int s;
  1841. X
  1842. X  debug2(DST, DDD, "SearchSym( %c..., %d )", str[0], len);
  1843. X
  1844. X  hash(str, len, sum);
  1845. X  rlen = len;
  1846. X  entry = (OBJECT) &symtab[sum];
  1847. X  for( plink = Down(entry);  plink != entry;  plink = NextDown(plink) )
  1848. X  { Child(p, plink);
  1849. X    if( rlen == length(p) )
  1850. X    { x = str;  y = string(p);
  1851. X      do; while( *x++ == *y++ && --rlen );
  1852. X      if( rlen == 0 )
  1853. X      {    s = scope_top;
  1854. X    do
  1855. X    { s--;
  1856. X      for( link = Down(p);  link != p;  link = NextDown(link) )
  1857. X      { Child(q, link);
  1858. X        if( enclosing(q) == scope[s]
  1859. X          && (!npars_only[s] || type(q) == NPAR)
  1860. X          && (!vis_only[s] || visible(q) || suppress_visible )
  1861. X          && (body_ok[s] || type(q)!=RPAR || !has_body(enclosing(q)) )
  1862. X          && !suppress_scope )
  1863. X        {    debug1(DST, DDD, "SearchSym returning %s", Image(type(q)));
  1864. X        return q;
  1865. X        }
  1866. X      }
  1867. X    } while( scope[s] != StartSym );
  1868. X      }
  1869. X    }
  1870. X    rlen = len;
  1871. X  }
  1872. X  debug0(DST, DDD, "SearchSym returning <nil>");
  1873. X  return nil;
  1874. X} /* end SearchSym */
  1875. X
  1876. X
  1877. X/*@@**************************************************************************/
  1878. X/*                                                                           */
  1879. X/*  unsigned char *SymName(s)                                                */
  1880. X/*                                                                           */
  1881. X/*  Return the string value of the name of symbol s.                         */
  1882. X/*                                                                           */
  1883. X/*****************************************************************************/
  1884. X
  1885. Xunsigned char *SymName(s)
  1886. XOBJECT s;
  1887. X{ OBJECT p;
  1888. X  if( s == nil )  return (unsigned char *) "<nil>";
  1889. X  Parent(p, Up(s));
  1890. X  assert( type(p) == WORD, "SymName: type(p) != WORD!" );
  1891. X  return string(p);
  1892. X} /* end SymName */
  1893. X    
  1894. X
  1895. X/*****************************************************************************/
  1896. X/*                                                                           */
  1897. X/*  unsigned char *FullSymName(x, str)                                       */
  1898. X/*                                                                           */
  1899. X/*  Return the path name of symbol x. with str separating each entry.        */
  1900. X/*                                                                           */
  1901. X/*****************************************************************************/
  1902. X
  1903. Xunsigned char *FullSymName(x, str)
  1904. XOBJECT x;  unsigned char *str;
  1905. X{ OBJECT stack[20];  int i;
  1906. X  static unsigned char buff[MAX_LINE], *sname;
  1907. X  if( x == nil )  return (unsigned char *) "<nil>";
  1908. X  assert( enclosing(x) != nil, "FullSymName: enclosing(x) == nil!" );
  1909. X  for( i = 0;  enclosing(x) != nil && i < 20;  i++ )
  1910. X  { stack[i] = x;
  1911. X    x = enclosing(x);
  1912. X  }
  1913. X  strcpy(buff, "");
  1914. X  for( i--;  i > 0;  i-- )
  1915. X  { sname = SymName(stack[i]);
  1916. X    if( strlen(sname) + strlen(str) + strlen(buff) >= MAX_LINE )
  1917. X      Error(FATAL, &fpos(x), "full name of symbol is too long");
  1918. X    strcat(buff, sname);
  1919. X    strcat(buff, str);
  1920. X  }
  1921. X  sname = SymName(stack[0]);
  1922. X  if( strlen(sname) + strlen(buff) >= MAX_LINE )
  1923. X    Error(FATAL, &fpos(x), "full name of symbol is too long");
  1924. X  strcat(buff, sname);
  1925. X  return buff;
  1926. X} /* end FullSymName */
  1927. X
  1928. X
  1929. X/*****************************************************************************/
  1930. X/*                                                                           */
  1931. X/*  OBJECT ChildSym(s, typ)                                                  */
  1932. X/*                                                                           */
  1933. X/*  Find the child of symbol s of type typ, either LPAR or RPAR.             */
  1934. X/*                                                                           */
  1935. X/*****************************************************************************/
  1936. X
  1937. XOBJECT ChildSym(s, typ)
  1938. XOBJECT s;  unsigned typ;
  1939. X{ OBJECT link, y;
  1940. X  for( link = Down(s);  link != s;  link = NextDown(link) )
  1941. X  { Child(y, link);
  1942. X    if( type(y) == typ && enclosing(y) == s )  return y;
  1943. X  }
  1944. X  Error(INTERN, &fpos(s), "Symbol %s has missing %s", SymName(s), Image(typ));
  1945. X  return nil;
  1946. X} /* end ChildSym */
  1947. X
  1948. X
  1949. X#if DEBUG_ON
  1950. X/*****************************************************************************/
  1951. X/*                                                                           */
  1952. X/*  CheckSymSpread()                                                         */
  1953. X/*                                                                           */
  1954. X/*  Check the spread of symbols through the hash table.                      */
  1955. X/*                                                                           */
  1956. X/*****************************************************************************/
  1957. X
  1958. XCheckSymSpread()
  1959. X{ int i, j, sum, usum;  OBJECT entry, plink;
  1960. X  debug2(DST, D, "Symbol table spread (table size = %d, symbols = %d):",
  1961. X    MAX_TAB, sym_count);
  1962. X  usum = sum = 0;
  1963. X  for( i = 0;  i < MAX_TAB;  i++ )
  1964. X  { fprintf(stderr, "%4d: ", i);
  1965. X    for( j = 1;  j <= sym_spread[i];  j++ )
  1966. X    { fprintf(stderr, ".");
  1967. X      sum += j;
  1968. X    }
  1969. X    entry = (OBJECT) &symtab[i];
  1970. X    for( plink=Down(entry), j=1;  plink != entry;  plink=NextDown(plink), j++ )
  1971. X    { fprintf(stderr, "+");
  1972. X      usum += j;
  1973. X    }
  1974. X    fprintf(stderr, "\n");
  1975. X  }
  1976. X  fprintf(stderr, "average length counting duplicate names = %.1f\n",
  1977. X    (float) sum / sym_count);
  1978. X  fprintf(stderr, "average length not counting duplicate names = %.1f\n",
  1979. X    (float) usum / sym_count);
  1980. X} /* end CheckSymSpread */
  1981. X
  1982. X
  1983. X/*****************************************************************************/
  1984. X/*                                                                           */
  1985. X/*  static DeleteSymBody(s)                                                  */
  1986. X/*                                                                           */
  1987. X/*  Delete the body of symbol s.                                             */
  1988. X/*                                                                           */
  1989. X/*****************************************************************************/
  1990. X
  1991. Xstatic DeleteSymBody(s)
  1992. XOBJECT s;
  1993. X{ debug1(DST, DDD, "DeleteSymBody( %s )", SymName(s));
  1994. X  switch( type(s) )
  1995. X  {
  1996. X    case MACRO:    while( sym_body(s) != nil )
  1997. X          sym_body(s) = DeleteAndDispose(sym_body(s), PARENT);
  1998. X        break;
  1999. X    
  2000. X    case LPAR:
  2001. X    case NPAR:
  2002. X    case RPAR:
  2003. X    case LOCAL:    if( sym_body(s) != nil ) DisposeObject(sym_body(s));
  2004. X        break;
  2005. X
  2006. X    default:    Error(INTERN,no_fpos, "unknown symbol type %s",Image(type(s)));
  2007. X        break;
  2008. X  }
  2009. X  debug0(DST, DDD, "DeleteSymBody returning.");
  2010. X} /* end DeleteSymBody */
  2011. X
  2012. X
  2013. X/*****************************************************************************/
  2014. X/*                                                                           */
  2015. X/*  DeleteEverySym()                                                         */
  2016. X/*                                                                           */
  2017. X/*  Delete every symbol in the symbol table.                                 */
  2018. X/*  Note that we first delete all bodies, then the symbols themselves.       */
  2019. X/*  This is so that the closures within the bodies have well-defined         */
  2020. X/*  actual() pointers, even while the symbol table is being disposed.        */
  2021. X/*  If this is not done, debug output during the disposal gets confused.     */
  2022. X/*                                                                           */
  2023. X/*****************************************************************************/
  2024. X
  2025. XDeleteEverySym()
  2026. X{ int i, j, load, cost;  OBJECT p, plink, link, x, entry;
  2027. X  debug0(DST, D, "DeleteEverySym()");
  2028. X
  2029. X  /* dispose the bodies of all symbols */
  2030. X  for( i = 0;  i < MAX_TAB;  i++ )
  2031. X  { entry = (OBJECT) &symtab[i];
  2032. X    for( plink = Down(entry);  plink != entry;  plink = NextDown(plink) )
  2033. X    { Child(p, plink);
  2034. X      for( link = Down(p);  link != p;  link = NextDown(link) )
  2035. X      {    Child(x, link);  DeleteSymBody(x);
  2036. X    /* *** won't work now
  2037. X    while( base_uses(x) != nil )
  2038. X    { tmp = base_uses(x);  base_uses(x) = next(tmp);
  2039. X      PutMem(tmp, USES_SIZE);
  2040. X    }
  2041. X    while( uses(x) != nil )
  2042. X    { tmp = uses(x);  uses(x) = next(tmp);
  2043. X      PutMem(tmp, USES_SIZE);
  2044. X    }
  2045. X    *** */
  2046. X      }
  2047. X    }
  2048. X  }
  2049. X
  2050. X  /* dispose the symbol name strings, gather statistics, and print them */
  2051. X  load = cost = 0;
  2052. X  for( i = 0;  i < MAX_TAB;  i++ )
  2053. X  { j = 1; entry = (OBJECT) &symtab[i];
  2054. X    while( Down(entry) != entry )
  2055. X    { load += 1;  cost += j;  j += 1;
  2056. X      DisposeChild(Down(entry));
  2057. X    }
  2058. X  }
  2059. X  if( load > 0 ) debug4(DST, D, "size = %d, items = %d (%d%%), probes = %.1f",
  2060. X    MAX_TAB, load, (100*load)/MAX_TAB, (float) cost/load);
  2061. X  else debug1(DST, D, "table size = %d, no entries in table", MAX_TAB);
  2062. X  debug0(DST, D, "DeleteEverySym returning.");
  2063. X} /* end DeleteEverySym */
  2064. X#endif
  2065. END_OF_FILE
  2066.   if test 23936 -ne `wc -c <'lout/z29.c'`; then
  2067.     echo shar: \"'lout/z29.c'\" unpacked with wrong size!
  2068.   fi
  2069.   # end of 'lout/z29.c'
  2070. fi
  2071. echo shar: End of archive 11 \(of 30\).
  2072. cp /dev/null ark11isdone
  2073. MISSING=""
  2074. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ; do
  2075.     if test ! -f ark${I}isdone ; then
  2076.     MISSING="${MISSING} ${I}"
  2077.     fi
  2078. done
  2079. if test "${MISSING}" = "" ; then
  2080.     echo You have unpacked all 30 archives.
  2081.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2082. else
  2083.     echo You still must unpack the following archives:
  2084.     echo "        " ${MISSING}
  2085. fi
  2086. exit 0
  2087. exit 0 # Just in case...
  2088.