home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume23 / abc / part08 < prev    next >
Text File  |  1991-01-08  |  56KB  |  2,649 lines

  1. Subject:  v23i087:  ABC interactive programming environment, Part08/25
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: a1ae9ff4 cd5ac149 b6653793 231756bf
  5.  
  6. Submitted-by: Steven Pemberton <steven@cwi.nl>
  7. Posting-number: Volume 23, Issue 87
  8. Archive-name: abc/part08
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  abc/bed/e1getc.c abc/bed/e1supr.c abc/bint3/i3sta.c
  17. # Wrapped by rsalz@litchi.bbn.com on Mon Dec 17 13:27:58 1990
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. echo If this archive is complete, you will see the following message:
  20. echo '          "shar: End of archive 8 (of 25)."'
  21. if test -f 'abc/bed/e1getc.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'abc/bed/e1getc.c'\"
  23. else
  24.   echo shar: Extracting \"'abc/bed/e1getc.c'\" \(12081 characters\)
  25.   sed "s/^X//" >'abc/bed/e1getc.c' <<'END_OF_FILE'
  26. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
  27. X
  28. X/* B editor -- read key definitions from file */
  29. X
  30. X#include "b.h"
  31. X#include "feat.h"
  32. X#include "bmem.h"
  33. X#include "bobj.h"
  34. X#include "bfil.h"
  35. X#include "keys.h"
  36. X#include "getc.h"
  37. X#include "args.h"
  38. X
  39. X#define ESC '\033'
  40. X
  41. X/*
  42. XThis file contains a little parser for key definition files.
  43. XTo allow sufficient freedom in preparing such a file, a simple
  44. Xgrammar has been defined according to which the file is parsed.
  45. XThe parsing process is extremely simple, as it can be done
  46. Xtop-down using recursive descent.
  47. X
  48. X
  49. XLexical conventions:
  50. X
  51. X- Blanks between lexical symbols are ignored.
  52. X- From '#' to end of line is comment (except inside strings).
  53. X- Strings are delimited by double quotes and
  54. X  use the same escape sequences as C strings, plus:
  55. X  \e or \E means an ESCape ('\033').
  56. X- Commandnames are like C identifiers ([a-zA-Z_][a-zA-Z0-9_]*).
  57. X  Upper/lower case distinction is significant.
  58. X- Key representations are delimited by double quotes, and may use
  59. X  any printable characters.
  60. X
  61. XSyntax in modified BNF ([] mean 0 or 1, * means 0 or more, + means 1 or more):
  62. X
  63. X   file: line*
  64. X   line: [def] [comment]
  65. X   def: '[' commandname ']' '=' definition  '=' representation
  66. X   definition: string
  67. X
  68. X
  69. XNotes:
  70. X
  71. X- A definition for command "[term-init]" defines a string to be sent
  72. X  TO the terminal at initialization time, e.g. to set programmable
  73. X  function key definitions.  Similar for "[term-done]" on exiting.
  74. X- Command names are conventional editor operations.
  75. X- Some bindings are taken from tty-settings, and should not be changed.
  76. X  (interrupt and suspend).
  77. X*/
  78. X
  79. X#define COMMENT '#' /* Not B-like but very UNIX-like */
  80. X#define QUOTE '"'
  81. X
  82. XHidden FILE *keysfp; /* File from which to read */
  83. XHidden char nextc; /* Next character to be analyzed */
  84. XHidden bool eof; /* EOF seen? */
  85. XHidden int lcount; /* Current line number */
  86. X#ifndef KEYS
  87. XHidden int errcount= 0; /* Number of errors detected */
  88. X#else
  89. XVisible int errcount= 0; /* Number of errors detected */
  90. X#endif
  91. X
  92. XVisible int ndefs;
  93. X
  94. XHidden Procedure err1(m)
  95. X    string m;
  96. X{
  97. X    static char errbuf[MESSBUFSIZE];
  98. X        /* since putmess() below overwrites argument m via getmess() */
  99. X
  100. X    sprintf(errbuf, "%s (%d): %s\n", keysfile, lcount, m);
  101. X                        
  102. X    if (errcount == 0) {
  103. X        putmess(errfile, MESS(6500, "Errors in key definitions file:\n"));
  104. X    }
  105. X    ++errcount;
  106. X
  107. X    putstr(errfile, errbuf);
  108. X}
  109. X
  110. XHidden Procedure err(m)
  111. X    int m;
  112. X{
  113. X    err1(getmess(m));
  114. X}
  115. X
  116. XHidden Procedure adv()
  117. X{
  118. X    int c;
  119. X
  120. X    if (eof)
  121. X        return;
  122. X    c= getc(keysfp);
  123. X    if (c == EOF) {
  124. X        nextc= '\n';
  125. X        eof= Yes;
  126. X    }
  127. X    else {
  128. X        nextc= c;
  129. X    }
  130. X}
  131. X
  132. XHidden Procedure skipspace()
  133. X{
  134. X    while (nextc == ' ' || nextc == '\t')
  135. X        adv();
  136. X}
  137. X
  138. XHidden int lookup(name)
  139. X    string name;
  140. X{
  141. X    int i;
  142. X
  143. X    for (i= 0; i < ndefs; ++i) {
  144. X        if (deftab[i].name != NULL && strcmp(name, deftab[i].name) == 0)
  145. X            return i;
  146. X    }
  147. X    return -1;
  148. X}
  149. X
  150. X/*
  151. X * Undefine conflicting definitions, i.e. strip them from other commands.
  152. X * Conflicts arise when a command definition is
  153. X * an initial subsequence of another, or vice versa.
  154. X * String definitions (code < 0) are not undefined.
  155. X * The special commands (like interrupt) should not be undefined.
  156. X */
  157. XVisible Procedure undefine(code, def)
  158. X    int code;
  159. X    string def;
  160. X{
  161. X    struct tabent *d, *last= deftab+ndefs;
  162. X    string p, q;
  163. X
  164. X    if (code < 0) 
  165. X        return;
  166. X    for (d= deftab; d < last; ++d) {
  167. X        if (d->code > 0 && d->def != NULL) {
  168. X            for (p= def, q= d->def; *p == *q; ++p, ++q) {
  169. X                if (*p == '\0') break;
  170. X            }
  171. X            if (*p == '\0' || *q == '\0') {
  172. X                d->def= NULL;
  173. X                d->rep= NULL;
  174. X#ifdef KEYS
  175. X                bind_changed(d->code);
  176. X#endif
  177. X            }
  178. X        }
  179. X    }
  180. X}
  181. X
  182. XHidden bool store(code, name, def, rep)        /* return whether stored */
  183. X    int code;
  184. X    string name;
  185. X    string def;
  186. X    string rep;
  187. X{
  188. X    struct tabent *d, *last= deftab+ndefs;
  189. X    char *pc;
  190. X
  191. X    if (code < 0) {
  192. X        /* find the place matching name to replace definition */
  193. X            for (d= deftab; d < last; ++d) {
  194. X            if (strcmp(name, d->name) == 0)
  195. X                            break;
  196. X        }
  197. X    }
  198. X    else {
  199. X        /* Check for illegal definition:
  200. X           If a command definition starts with a printable character
  201. X           OR it contains one of the special chars that are, or
  202. X              must be handled as signals (like interrupt, suspend, quit).
  203. X         */
  204. X        if (isascii(*def) && (isprint(*def) || *def==' ')) {
  205. X            sprintf(messbuf,
  206. X        GMESS(6501, "Definition for command %s starts with '%c'."),
  207. X                name, *def);
  208. X            err1(messbuf);
  209. X            return No;
  210. X        }
  211. X        for (pc= def; *pc != '\0'; pc++) {
  212. X            if (is_spchar(*pc)) {
  213. X                sprintf(messbuf,
  214. X#ifdef CANSUSPEND
  215. X
  216. XGMESS(6502, "Definition for command %s would produce an interrupt or suspend."),
  217. X
  218. X#else
  219. X
  220. XGMESS(6503, "Definition for command %s would produce an interrupt."),
  221. X
  222. X#endif
  223. X                name, *def);
  224. X                err1(messbuf);
  225. X                return No;
  226. X            }
  227. X        }
  228. X        
  229. X        undefine(code, def);
  230. X        /* New definitions are added at the end, so the last one can be 
  231. X           used in the HELP blurb. */
  232. X        d= last;
  233. X        /* Extend definition table */
  234. X        if (ndefs >= MAXDEFS) {
  235. X            err(MESS(6504, "Too many key definitions"));
  236. X            return No;
  237. X        }
  238. X        ndefs++;
  239. X    }
  240. X    d->code= code;
  241. X    d->name= name;
  242. X    d->def= def;
  243. X    d->rep= rep;
  244. X#ifdef MEMTRACE
  245. X    fixmem((ptr) name);
  246. X    fixmem((ptr) def);
  247. X    fixmem((ptr) rep);
  248. X#endif
  249. X    return Yes;
  250. X}
  251. X
  252. XHidden string getname()
  253. X{
  254. X    char buffer[20];
  255. X    string bp;
  256. X    
  257. X    if (nextc != '[') {
  258. X        err(MESS(6505, "no '[' before name"));
  259. X        return NULL;
  260. X    }
  261. X    bp= buffer;
  262. X    *bp++= nextc;
  263. X    adv();
  264. X    if (!isascii(nextc)
  265. X        ||
  266. X        (!isalpha(nextc) && nextc != '_' && nextc != '-')
  267. X       ) {
  268. X        err(MESS(6506, "No name after '['"));
  269. X        return NULL;
  270. X    }
  271. X    while ((isascii(nextc) && isalnum(nextc))
  272. X           || nextc == '_' || nextc == '-'
  273. X          ) {
  274. X        if (bp < buffer + sizeof buffer - 1)
  275. X            *bp++= (nextc == '_' ? '-' : nextc);
  276. X        adv();
  277. X    }
  278. X    if (nextc != ']') {
  279. X        err(MESS(6507, "no ']' after name"));
  280. X        return NULL;
  281. X    }
  282. X    *bp++= nextc;
  283. X    adv();
  284. X    *bp= '\0';
  285. X    return (string) savestr(buffer);
  286. X}
  287. X
  288. XHidden string getstring()
  289. X{
  290. X    char buf[256]; /* Arbitrary limit */
  291. X    char c;
  292. X    int len= 0;
  293. X
  294. X    if (nextc != QUOTE) {
  295. X        err(MESS(6508, "opening string quote not found"));
  296. X        return NULL;
  297. X    }
  298. X    adv();
  299. X    while (nextc != QUOTE) {
  300. X        if (nextc == '\n') {
  301. X            err(MESS(6509, "closing string quote not found in definition"));
  302. X            return NULL;
  303. X        }
  304. X        if (nextc != '\\') {
  305. X            c= nextc;
  306. X            adv();
  307. X        }
  308. X        else {
  309. X            adv();
  310. X            switch (nextc) {
  311. X
  312. X            case 'r': c= '\r'; adv(); break;
  313. X            case 'n': c= '\n'; adv(); break;
  314. X            case 'b': c= '\b'; adv(); break;
  315. X            case 't': c= '\t'; adv(); break;
  316. X            case 'f': c= '\f'; adv(); break;
  317. X
  318. X            case 'E':
  319. X            case 'e': c= ESC; adv(); break;
  320. X
  321. X            case '0': case '1': case '2': case '3':
  322. X            case '4': case '5': case '6': case '7':
  323. X                c= nextc-'0';
  324. X                adv();
  325. X                if (nextc >= '0' && nextc < '8') {
  326. X                    c= 8*c + nextc-'0';
  327. X                    adv();
  328. X                    if (nextc >= '0' && nextc < '8') {
  329. X                        c= 8*c + nextc-'0';
  330. X                        adv();
  331. X                    }
  332. X                }
  333. X                break;
  334. X
  335. X            default: c=nextc; adv(); break;
  336. X
  337. X            }
  338. X        }
  339. X        if (len >= sizeof buf) {
  340. X            err(MESS(6510, "definition string too long"));
  341. X            return NULL;
  342. X        }
  343. X        buf[len++]= c;
  344. X    }
  345. X    adv();
  346. X    buf[len]= '\0';
  347. X    return (string) savestr(buf);
  348. X}
  349. X
  350. XHidden string getrep()
  351. X{
  352. X    char buf[256]; /* Arbitrary limit */
  353. X    char c;
  354. X    int len= 0;
  355. X
  356. X    if (nextc != QUOTE) {
  357. X        err(MESS(6511, "opening string quote not found in representation"));
  358. X        return NULL;
  359. X    }
  360. X    adv();
  361. X    while (nextc != QUOTE) {
  362. X        if (nextc == '\\')
  363. X            adv();
  364. X        if (nextc == '\n') {
  365. X            err(MESS(6512, "closing string quote not found in representation"));
  366. X            return NULL;
  367. X        }
  368. X        c= nextc;
  369. X        adv();
  370. X        if (!isprint(c) && c != ' ') {
  371. X            err(MESS(6513, "unprintable character in representation"));
  372. X            return NULL;
  373. X        }
  374. X        if (len >= sizeof buf) {
  375. X            err(MESS(6514, "representation string too long"));
  376. X            return NULL;
  377. X        }
  378. X        buf[len++]= c;
  379. X    }
  380. X    adv();
  381. X    buf[len]= '\0';
  382. X    return savestr(buf);
  383. X}
  384. X
  385. XHidden Procedure get_definition()
  386. X{
  387. X    string name;
  388. X    int d;
  389. X    int code;
  390. X    string def;
  391. X    string rep;
  392. X    
  393. X    name= getname();
  394. X    if (name == NULL)
  395. X        return;
  396. X    skipspace();
  397. X    if (nextc != '=') {
  398. X        sprintf(messbuf, GMESS(6515, "Name %s not followed by '='"), name);
  399. X        err1(messbuf);
  400. X        freemem((ptr) name);
  401. X        return;
  402. X    }
  403. X    d = lookup(name);
  404. X    if (d < 0) {
  405. X        sprintf(messbuf,
  406. X            getmess(MESS(6516, "Unknown command name: %s")), name);
  407. X        err1(messbuf);
  408. X        freemem((ptr) name);
  409. X        return;
  410. X    }
  411. X    code = deftab[d].code;
  412. X    if (code == CANCEL || code == SUSPEND) {
  413. X        sprintf(messbuf,
  414. X            getmess(MESS(6517, "Cannot rebind %s in keysfile")), name);
  415. X        err1(messbuf);
  416. X        freemem((ptr) name);
  417. X        return;
  418. X    }
  419. X
  420. X    adv();
  421. X    skipspace();
  422. X    def= getstring();
  423. X    if (def == NULL) {
  424. X        freemem((ptr) name);
  425. X        return;
  426. X    }
  427. X    
  428. X    skipspace();
  429. X    if (nextc != '=') {
  430. X        sprintf(messbuf, GMESS(6518, "No '=' after definition for name %s"), name);
  431. X        err1(messbuf);
  432. X        freemem((ptr) name);
  433. X        freemem((ptr) def);
  434. X        return;
  435. X    }
  436. X
  437. X    adv();
  438. X    skipspace();
  439. X    rep= getrep();
  440. X    if (rep == NULL) {
  441. X        freemem((ptr) name);
  442. X        freemem((ptr) def);
  443. X        return;
  444. X    }
  445. X    
  446. X    if (!store(code, name, def, rep)) {
  447. X        freemem((ptr) name);
  448. X        freemem((ptr) def);
  449. X        freemem((ptr) rep);
  450. X    }
  451. X}
  452. X
  453. XHidden Procedure get_line()
  454. X{
  455. X    adv();
  456. X    skipspace();
  457. X    if (nextc != COMMENT && nextc != '\n')
  458. X        get_definition();
  459. X    while (nextc != '\n')
  460. X        adv();
  461. X}
  462. X
  463. X#ifdef DUMPKEYS
  464. XVisible Procedure dumpkeys(where)
  465. X    string where;
  466. X{
  467. X    int i;
  468. X    int w;
  469. X    string s;
  470. X
  471. X    putSstr(stdout, "\nDump of key definitions %s.\n\n", where);
  472. X    putstr(stdout, "Code    Name            Definition               Representation\n");
  473. X    for (i= 0; i < ndefs; ++i) {
  474. X        putDstr(stdout, "%04o    ", deftab[i].code);
  475. X        if (deftab[i].name != NULL)
  476. X            putSstr(stdout, "%-15s ", deftab[i].name);
  477. X        else
  478. X            putstr(stdout, "                ");
  479. X        s= deftab[i].def;
  480. X        w= 0;
  481. X        if (s != NULL) {
  482. X            for (; *s != '\0'; ++s) {
  483. X                if (isascii(*s) && (isprint(*s) || *s == ' ')) {
  484. X                    putchr(stdout, *s);
  485. X                    w++;
  486. X                }
  487. X                else {
  488. X                    putDstr(stdout, "\\%03o", (int)(*s&0377));
  489. X                    w+= 4;
  490. X                }
  491. X            }
  492. X        }
  493. X        else {
  494. X            putstr(stdout, "NULL");
  495. X            w= 4;
  496. X        }
  497. X        while (w++ < 25)
  498. X            putchr(stdout, ' ');
  499. X        s= deftab[i].rep;
  500. X        putSstr(stdout, "%s\n", s!=NULL ? s : "NULL");
  501. X    }
  502. X    putnewline(stdout);
  503. X    fflush(stdout);
  504. X}
  505. X#endif /* DUMPKEYS */
  506. X
  507. X#ifdef KEYS
  508. Xextern int nharddefs;
  509. X#endif
  510. X
  511. XVisible Procedure countdefs()
  512. X{
  513. X    struct tabent *d;
  514. X
  515. X    d= deftab;
  516. X    while (d->name != NULL) {
  517. X        ++d;
  518. X        if (d >= deftab+MAXDEFS)
  519. X            syserr(MESS(6519, "too many predefined keys"));
  520. X    }
  521. X    ndefs= d-deftab;
  522. X#ifdef KEYS
  523. X    nharddefs= ndefs;
  524. X#endif
  525. X}
  526. X
  527. XVisible Procedure rd_keysfile()
  528. X{
  529. X#ifdef KEYS
  530. X    saveharddefs();
  531. X#endif
  532. X    if (keysfile != NULL)
  533. X        keysfp= fopen(keysfile, "r");
  534. X    else
  535. X        keysfp= NULL;
  536. X    if (keysfp == NULL) {
  537. X        return;
  538. X    }
  539. X/* process: */
  540. X    errcount= 0;
  541. X    lcount= 1;
  542. X    eof= No;
  543. X    do {
  544. X        get_line();
  545. X        lcount++;
  546. X    } while (!eof);
  547. X/* */
  548. X    fclose(keysfp);
  549. X    if (errcount > 0)
  550. X        fflush(errfile);
  551. X#ifdef DUMPKEYS
  552. X    if (kflag)
  553. X        dumpkeys("after reading keysfile");
  554. X#endif
  555. X#ifdef KEYS
  556. X    savefiledefs();
  557. X#endif
  558. X}
  559. X
  560. X#ifndef KEYS
  561. X
  562. X/* Output a named string to the terminal */
  563. X
  564. XHidden Procedure outstring(name)
  565. X    string name;
  566. X{
  567. X    int i= lookup(name);
  568. X
  569. X    if (i >= 0) {
  570. X        string def= deftab[i].def;
  571. X        if (def != NULL && *def != '\0') {
  572. X            fputs(def, errfile);
  573. X            putnewline(errfile);
  574. X            fflush(errfile);
  575. X        }
  576. X    }
  577. X}
  578. X
  579. X/* Output the terminal's initialization sequence, if any. */
  580. X
  581. XVisible Procedure initgetc()
  582. X{
  583. X    outstring("[term-init]");
  584. X}
  585. X
  586. X
  587. X/* Output a sequence, if any, to return the terminal to a 'normal' state. */
  588. X
  589. XVisible Procedure endgetc()
  590. X{
  591. X    outstring("[term-done]");
  592. X}
  593. X
  594. X
  595. X/* Read a command from the keyboard, decoding composite key definitions. */
  596. X
  597. XVisible int inchar()
  598. X{
  599. X    int c;
  600. X    struct tabent *d, *last;
  601. X    char buffer[100];
  602. X    int len;
  603. X
  604. X    c= trminput();
  605. X    if (c == EOF)
  606. X        return c;
  607. X    c= cvchar(c);
  608. X    last= deftab+ndefs;
  609. X    for (d= deftab; d < last; ++d) {
  610. X        if (d->code > 0 && d->def != NULL && c == (d->def[0] & 0377))
  611. X            break;
  612. X    }
  613. X    if (d == last) {
  614. X        if (isascii(c) && (isprint(c) || c == ' '))
  615. X            return c;
  616. X        else
  617. X            return 0377;
  618. X    }
  619. X    if (d->def[1] == '\0')
  620. X        return d->code;
  621. X    buffer[0]= c;
  622. X    len= 1;
  623. X    for (;;) {
  624. X        c= trminput();
  625. X        if (c == EOF)
  626. X            return EOF;
  627. X        buffer[len]= c;
  628. X        if (len < sizeof buffer - 1)
  629. X            ++len;
  630. X        for (d= deftab; d < last; ++d) {
  631. X            if (d->code > 0 && d->def != NULL
  632. X                && strncmp(buffer, d->def, len) == 0)
  633. X                break;
  634. X        }
  635. X        if (d == last) {
  636. X            return 0377; /* Hope this rings a bell */
  637. X        }
  638. X        if (d->def[len] == '\0')
  639. X            return d->code;
  640. X    }
  641. X}
  642. X#endif /* !KEYS */
  643. END_OF_FILE
  644.   if test 12081 -ne `wc -c <'abc/bed/e1getc.c'`; then
  645.     echo shar: \"'abc/bed/e1getc.c'\" unpacked with wrong size!
  646.   fi
  647.   # end of 'abc/bed/e1getc.c'
  648. fi
  649. if test -f 'abc/bed/e1supr.c' -a "${1}" != "-c" ; then 
  650.   echo shar: Will not clobber existing file \"'abc/bed/e1supr.c'\"
  651. else
  652.   echo shar: Extracting \"'abc/bed/e1supr.c'\" \(19545 characters\)
  653.   sed "s/^X//" >'abc/bed/e1supr.c' <<'END_OF_FILE'
  654. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
  655. X
  656. X/*
  657. X * B editor -- Superroutines.
  658. X */
  659. X
  660. X#include "b.h"
  661. X#include "bedi.h"
  662. X#include "etex.h"
  663. X#include "feat.h"
  664. X#include "bobj.h"
  665. X#include "erro.h"
  666. X#include "node.h"
  667. X#include "supr.h"
  668. X#include "gram.h"
  669. X#include "tabl.h"
  670. X
  671. X/*
  672. X * Compute the length of the ep->s1'th item of node tree(ep->focus).
  673. X */
  674. X
  675. XVisible int
  676. Xlenitem(ep)
  677. X    register environ *ep;
  678. X{
  679. X    register node n = tree(ep->focus);
  680. X    register node nn;
  681. X
  682. X    if (ep->s1&1) { /* Fixed text */
  683. X        string *nr= noderepr(n);
  684. X        return fwidth(nr[ep->s1/2]);
  685. X    }
  686. X    /* Else, variable text or a whole node */
  687. X    nn = child(n, ep->s1/2);
  688. X    return nodewidth(nn);
  689. X}
  690. X
  691. X
  692. X/*
  693. X * Find the largest possible representation of the focus.
  694. X * E.g., a WHOLE can also be represented as a SUBSET of its parent,
  695. X * provided it has a parent.
  696. X * Also, a SUBSET may be extended with some empty left and right
  697. X * items and then look like a WHOLE, etc.
  698. X * This process is repeated until no more improvements can be made.
  699. X */
  700. X
  701. XVisible Procedure
  702. Xgrow(ep, deleting)
  703. X    environ *ep;
  704. X    bool deleting;
  705. X{
  706. X    subgrow(ep, Yes, deleting);
  707. X}
  708. X
  709. XVisible Procedure
  710. Xsubgrow(ep, ignorespaces, deleting)
  711. X    register environ *ep;
  712. X    bool ignorespaces;
  713. X    bool deleting;
  714. X{
  715. X    register node n;
  716. X    register int sym;
  717. X    register int i;
  718. X    register int len;
  719. X    register string repr;
  720. X
  721. X    switch (ep->mode) {
  722. X    case ATBEGIN:
  723. X    case ATEND:
  724. X    case VHOLE:
  725. X    case FHOLE:
  726. X        ritevhole(ep);
  727. X        if (ep->mode != FHOLE && ep->mode != VHOLE || lenitem(ep) == 0)
  728. X            leftvhole(ep);
  729. X        else if (ep->mode == FHOLE && ep->s2 == 0 && ep->s1 > 1) {
  730. X            n= tree(ep->focus);
  731. X            sym= symbol(n);
  732. X            repr= (noderepr(n))[ep->s1/2];
  733. X            if (symbol(child(n, ep->s1/2)) == Optional) {
  734. X                /* implicit extra widen from optional hole */
  735. X                /* e.g. {>?<} -> >{?}< */
  736. X                ep->mode= SUBSET;
  737. X                ep->s2= --ep->s1;
  738. X            }
  739. X            else if (!deleting
  740. X                || strchr("()[]{}\"'`:;.", repr[0]) != NULL
  741. X                || (repr[0] == ' ' && sym != Grouped
  742. X                    && sym != Grouped_ff && sym != Keyword_list)
  743. X            )
  744. X                /* widen/extend left before some delimiter */
  745. X                /* if deleting: only if this delimiter */
  746. X                /* is doomed undeletable */
  747. X                leftvhole(ep);
  748. X        }
  749. X    }
  750. X
  751. X    for (;;) {
  752. X        n = tree(ep->focus);
  753. X        sym = symbol(n);
  754. X
  755. X        switch (ep->mode) {
  756. X
  757. X        case VHOLE:
  758. X        case FHOLE:
  759. X            if ((sym == Optional || sym == Hole) && ep->s2 == 0) {
  760. X                ep->mode = WHOLE;
  761. X                continue;
  762. X            }
  763. X            if (lenitem(ep) <= 0) {
  764. X                ep->mode = SUBSET;
  765. X                ep->s2 = ep->s1;
  766. X                continue;
  767. X            }
  768. X            return;
  769. X
  770. X        case ATBEGIN:
  771. X        case ATEND:
  772. X            if (sym == Optional || sym == Hole) {
  773. X                ep->mode = WHOLE;
  774. X                continue;
  775. X            }
  776. X            return;
  777. X
  778. X        case SUBRANGE:
  779. X            if (ep->s1&1) {
  780. X                string *nr= noderepr(n);
  781. X                repr = nr[ep->s1/2];
  782. X                len = fwidth(repr);
  783. X                if (!ignorespaces) {
  784. X                  while (ep->s2 > 0 && repr[ep->s2-1] == ' ')
  785. X                    --ep->s2;
  786. X                  while (ep->s3 < len && repr[ep->s3+1] == ' ')
  787. X                    ++ep->s3;
  788. X                }
  789. X            }
  790. X            else {
  791. X                value chld= (value) firstchild(n);
  792. X                len = Length(chld);
  793. X            }
  794. X            if (ep->s2 == 0 && ep->s3 >= len - 1) {
  795. X                ep->mode = SUBSET;
  796. X                ep->s2 = ep->s1;
  797. X                continue;
  798. X            }
  799. X            return;
  800. X
  801. X        case SUBSET:
  802. X            subgrsubset(ep, ignorespaces);
  803. X            if (ep->s1 == 1) {
  804. X                if (ep->s2 == 2*nchildren(n) + 1) {
  805. X                    ep->mode = WHOLE;
  806. X                    continue;
  807. X                }
  808. X                if (ep->s2 == 2*nchildren(n) - 1 && issublist(sym)) {
  809. X                    ep->mode = SUBLIST;
  810. X                    ep->s3 = 1;
  811. X                    return;
  812. X                }
  813. X            }
  814. X            return;
  815. X
  816. X        case SUBLIST:
  817. X            for (i = ep->s3; i > 0; --i)
  818. X                n = lastchild(n);
  819. X            sym = symbol(n);
  820. X            if (sym == Optional) {
  821. X                ep->mode = WHOLE;
  822. X                continue;
  823. X            }
  824. X            return;
  825. X
  826. X        case WHOLE:
  827. X            ep->s1 = 2*ichild(ep->focus);
  828. X            if (up(&ep->focus)) {
  829. X                ep->mode = SUBSET;
  830. X                ep->s2 = ep->s1;
  831. X                higher(ep);
  832. X                continue;
  833. X            }
  834. X            return; /* Leave as WHOLE if there is no parent */
  835. X
  836. X        default:
  837. X            Abort();
  838. X            /* NOTREACHED */
  839. X
  840. X        }
  841. X
  842. X    }
  843. X    /* Not reached */
  844. X}
  845. X
  846. X
  847. X/*
  848. X * Ditto to find smallest possible representation.
  849. X */
  850. X
  851. XVisible Procedure
  852. Xshrink(ep)
  853. X    register environ *ep;
  854. X{
  855. X    register node n;
  856. X    register int sym;
  857. X
  858. X    for (;;) {
  859. X        n = tree(ep->focus);
  860. X        sym = symbol(n);
  861. X
  862. X        switch (ep->mode) {
  863. X
  864. X        case WHOLE:
  865. X            if (sym == Hole || sym == Optional)
  866. X                return;
  867. X            ep->mode = SUBSET;
  868. X            ep->s1 = 1;
  869. X            ep->s2 = 2*nchildren(n) + 1;
  870. X            continue;
  871. X
  872. X        case SUBLIST:
  873. X            if (sym == Hole || sym == Optional) {
  874. X                ep->mode = WHOLE;
  875. X                return;
  876. X            }
  877. X            if (ep->s3 == 1) {
  878. X                ep->mode = SUBSET;
  879. X                ep->s1 = 1;
  880. X                ep->s2 = 2*nchildren(n) - 1;
  881. X                continue;
  882. X            }
  883. X            return;
  884. X
  885. X        case SUBSET:
  886. X            if (sym == Hole || sym == Optional) {
  887. X                ep->mode = WHOLE;
  888. X                return;
  889. X            }
  890. X            shrsubset(ep);
  891. X            if (ep->s1 == ep->s2) {
  892. X                if (isunititem(ep)) {
  893. X                    ep->mode = SUBRANGE;
  894. X                    ep->s2 = 0;
  895. X                    ep->s3 = lenitem(ep) - 1;
  896. X                    return;
  897. X                }
  898. X                else {
  899. X                    s_downi(ep, ep->s1/2);
  900. X                    ep->mode = WHOLE;
  901. X                    continue;
  902. X                }
  903. X            }
  904. X            return;
  905. X
  906. X        case SUBRANGE:
  907. X            if (sym == Optional || sym == Hole)
  908. X                ep->mode = WHOLE;
  909. X            return;
  910. X
  911. X        case ATBEGIN:
  912. X            ritevhole(ep);
  913. X            if (ep->mode == ATBEGIN) {
  914. X                if (sym == Optional || sym == Hole)
  915. X                    ep->mode = WHOLE;
  916. X                return;
  917. X            }
  918. X            continue;
  919. X
  920. X        case FHOLE:
  921. X        case VHOLE:
  922. X            ritevhole(ep);
  923. X            if (ep->mode != VHOLE && ep->mode != FHOLE)
  924. X                continue;
  925. X            sym = symbol(tree(ep->focus));
  926. X            if (sym == Optional || sym == Hole && ep->s2 == 0)
  927. X                ep->mode = WHOLE;
  928. X            return;
  929. X
  930. X        case ATEND:
  931. X            return;
  932. X
  933. X        default:
  934. X            Abort();
  935. X            /* NOTREACHED */
  936. X
  937. X        }
  938. X    }
  939. X    /* Not reached */
  940. X
  941. X}
  942. X
  943. X
  944. X/*
  945. X * Subroutine to find the largest way to describe a SUBSET focus
  946. X * (modulo surrounding blanks and newlines).
  947. X */
  948. X
  949. X#ifdef NOT_USED
  950. XVisible Procedure
  951. Xgrowsubset(ep)
  952. X    environ *ep;
  953. X{
  954. X    subgrsubset(ep, Yes);
  955. X}
  956. X#endif
  957. X
  958. XVisible Procedure
  959. Xsubgrsubset(ep, ignorespaces)
  960. X    register environ *ep;
  961. X    bool ignorespaces;
  962. X{
  963. X    register node n = tree(ep->focus);
  964. X    register string *rp = noderepr(n);
  965. X    register nch21 = nchildren(n)*2 + 1;
  966. X    register int i;
  967. X
  968. X    Assert(ep->mode == SUBSET);
  969. X    for (i = ep->s1; i > 1 && subisnull(n, rp, i-1, ignorespaces); --i)
  970. X        ;
  971. X    ep->s1 = i;
  972. X    for (i = ep->s2; i < nch21 && subisnull(n, rp, i+1, ignorespaces); ++i)
  973. X        ;
  974. X    ep->s2 = i;
  975. X}
  976. X
  977. X
  978. X/*
  979. X * Ditto for the smallest way.
  980. X */
  981. X
  982. XVisible Procedure /* Ought to be Hidden */
  983. Xshrsubset(ep)
  984. X    register environ *ep;
  985. X{
  986. X    register node n = tree(ep->focus);
  987. X    register string *rp = noderepr(n);
  988. X    register int s1 = ep->s1;
  989. X    register int s2 = ep->s2;
  990. X
  991. X    for (; s1 < s2 && isnull(n, rp, s1); ++s1)
  992. X        ;
  993. X    ep->s1 = s1;
  994. X    for (; s2 > s1 && isnull(n, rp, s2); --s2)
  995. X        ;
  996. X    ep->s2 = s2;
  997. X}
  998. X
  999. X
  1000. X/*
  1001. X * Subroutine for grow/shrink to see whether item i is (almost) invisible.
  1002. X */
  1003. X
  1004. XHidden bool
  1005. Xsubisnull(n, rp, i, ignorespaces)
  1006. X    register node n;
  1007. X    register string *rp;
  1008. X    register int i;
  1009. X    bool ignorespaces;
  1010. X{
  1011. X    register string repr;
  1012. X    register node nn;
  1013. X
  1014. X    if (i&1) { /* Fixed text */
  1015. X        repr = rp[i/2];
  1016. X        return !Fw_positive(repr) || ignorespaces && allspaces(repr);
  1017. X    }
  1018. X    nn = child(n, i/2);
  1019. X    return nodewidth(nn) == 0;
  1020. X}
  1021. X
  1022. X
  1023. XHidden bool
  1024. Xisnull(n, rp, i)
  1025. X    node n;
  1026. X    string *rp;
  1027. X    int i;
  1028. X{
  1029. X    return subisnull(n, rp, i, Yes);
  1030. X}
  1031. X
  1032. X/*
  1033. X * Find the rightmost VHOLE which would look the same as the current one.
  1034. X */
  1035. X
  1036. XVisible Procedure
  1037. Xritevhole(ep)
  1038. X    register environ *ep;
  1039. X{
  1040. X    register node n;
  1041. X    register int ich;
  1042. X    register int len;
  1043. X    register int s1save;
  1044. X
  1045. X    for (;;) {
  1046. X        n = tree(ep->focus);
  1047. X        
  1048. X        switch (ep->mode) {
  1049. X
  1050. X        case WHOLE:
  1051. X            ep->mode = ATEND;
  1052. X            break;
  1053. X
  1054. X        case VHOLE:
  1055. X        case FHOLE:
  1056. X            len = lenitem(ep);
  1057. X            Assert(len >= 0);
  1058. X            if (ep->s2 < len)
  1059. X                return; /* Hole in middle of string */
  1060. X            s1save = ep->s1;
  1061. X            if (nextitem(ep)) {
  1062. X                if (isunititem(ep)) {
  1063. X                    ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
  1064. X                    ep->s2 = 0;
  1065. X                }
  1066. X                else if (fwidth(noderepr(child(n, ep->s1/2))[0]) < 0) {
  1067. X                    /* Next item begins with newline -- avoid */
  1068. X                    ep->s1 = s1save;
  1069. X                    return;
  1070. X                }
  1071. X                else {
  1072. X                    s_downi(ep, ep->s1/2);
  1073. X                    ep->mode = ATBEGIN;
  1074. X                }
  1075. X                break;
  1076. X            }
  1077. X            ep->mode = ATEND;
  1078. X            /* Fall through */
  1079. X        case ATEND:
  1080. X            if (!parent(ep->focus) || nodewidth(n) < 0)
  1081. X                return;
  1082. X            ich = ichild(ep->focus);
  1083. X            ep->s1 = 2*ich;
  1084. X            s_up(ep);
  1085. X            if (nextitem(ep)) {
  1086. X                                /* Note -- negative width cannot occur 
  1087. X                                 * (see test above) [says Guido]
  1088. X                                 */
  1089. X                if (isunititem(ep)) {
  1090. X                    ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
  1091. X                    ep->s2 = 0;
  1092. X                }
  1093. X                else {
  1094. X                    ep->mode = ATBEGIN;
  1095. X                    s_downi(ep, ep->s1/2);
  1096. X                }
  1097. X                break;
  1098. X            }
  1099. X            continue;
  1100. X
  1101. X        case ATBEGIN:
  1102. X            if (fwidth(noderepr(n)[0]) < 0)
  1103. X                return; /* Already at dangerous position */
  1104. X            ep->mode = FHOLE;
  1105. X            ep->s1 = 1;
  1106. X            ep->s2 = 0;
  1107. X            continue;
  1108. X
  1109. X        default:
  1110. X            Abort();
  1111. X            /* NOTREACHED */
  1112. X
  1113. X        }
  1114. X    }
  1115. X}
  1116. X
  1117. X
  1118. X/*
  1119. X * Ditto to the left.
  1120. X */
  1121. X
  1122. XVisible Procedure
  1123. Xleftvhole(ep)
  1124. X    register environ *ep;
  1125. X{
  1126. X    register int ich;
  1127. X
  1128. X    for (;;) {
  1129. X        switch (ep->mode) {
  1130. X
  1131. X        case WHOLE:
  1132. X            ep->mode = ATBEGIN;
  1133. X            break;
  1134. X
  1135. X        case VHOLE:
  1136. X        case FHOLE:
  1137. X            if (ep->s2 > 0)
  1138. X                return;
  1139. X            if (previtem(ep)) {
  1140. X                if (isunititem(ep)) {
  1141. X                    ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
  1142. X                    ep->s2 = lenitem(ep);
  1143. X                }
  1144. X                else {
  1145. X                    s_downi(ep, ep->s1/2);
  1146. X                    ep->mode = ATEND;
  1147. X                }
  1148. X            }
  1149. X            else if (fwidth(noderepr(tree(ep->focus))[0]) < 0)
  1150. X                return;
  1151. X            else
  1152. X                ep->mode = ATBEGIN;
  1153. X            continue;
  1154. X
  1155. X        case ATBEGIN:
  1156. X            ich = ichild(ep->focus);
  1157. X            if (!up(&ep->focus))
  1158. X                return;
  1159. X            higher(ep);
  1160. X            ep->s1 = 2*ich;
  1161. X            if (prevnnitem(ep)) {
  1162. X                if (isunititem(ep)) {
  1163. X                    ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
  1164. X                    ep->s2 = lenitem(ep);
  1165. X                }
  1166. X                else {
  1167. X                    s_downi(ep, ep->s1/2);
  1168. X                    ep->mode = ATEND;
  1169. X                }
  1170. X            }
  1171. X            else if (fwidth(noderepr(tree(ep->focus))[0]) < 0) {
  1172. X                s_downi(ep, ich); /* Undo up */
  1173. X                return;
  1174. X            }
  1175. X            else
  1176. X                ep->mode = ATBEGIN;
  1177. X            continue;
  1178. X
  1179. X        case ATEND:
  1180. X            lastnnitem(ep);
  1181. X            if (isunititem(ep)) {
  1182. X                ep->s2 = lenitem(ep);
  1183. X                ep->mode = (ep->s1&1) ? FHOLE : VHOLE;
  1184. X            }
  1185. X            else
  1186. X                s_downi(ep, ep->s1/2);
  1187. X            continue;
  1188. X
  1189. X        default:
  1190. X            Abort();
  1191. X
  1192. X        }
  1193. X    }
  1194. X}
  1195. X
  1196. X
  1197. X/*
  1198. X * Safe up, downi, left and rite routines:
  1199. X * 1) Rather die than fail;
  1200. X * 2) Update ep->highest properly.
  1201. X */
  1202. X
  1203. XVisible Procedure
  1204. Xs_up(ep)
  1205. X    register environ *ep;
  1206. X{
  1207. X    if (!up(&ep->focus))
  1208. X        syserr(MESS(7100, "s_up failed"));
  1209. X    higher(ep);
  1210. X}
  1211. X
  1212. XVisible Procedure
  1213. Xs_downi(ep, i)
  1214. X    register environ *ep;
  1215. X    register int i;
  1216. X{
  1217. X    if (!downi(&ep->focus, i))
  1218. X        syserr(MESS(7101, "s_downi failed"));
  1219. X}
  1220. X
  1221. XVisible Procedure
  1222. Xs_down(ep)
  1223. X    register environ *ep;
  1224. X{
  1225. X    if (!down(&ep->focus))
  1226. X        syserr(MESS(7102, "s_down failed"));
  1227. X}
  1228. X
  1229. XVisible Procedure
  1230. Xs_downrite(ep)
  1231. X    register environ *ep;
  1232. X{
  1233. X    if (!downrite(&ep->focus))
  1234. X        syserr(MESS(7103, "s_downrite failed"));
  1235. X}
  1236. X
  1237. X#ifdef NOT_USED
  1238. XVisible Procedure
  1239. Xs_left(ep)
  1240. X    register environ *ep;
  1241. X{
  1242. X    register int ich = ichild(ep->focus);
  1243. X
  1244. X    s_up(ep);
  1245. X    s_downi(ep, ich-1);
  1246. X}
  1247. X#endif
  1248. X
  1249. X#ifdef NOT_USED
  1250. XVisible Procedure
  1251. Xs_rite(ep)
  1252. X    register environ *ep;
  1253. X{
  1254. X    register int ich = ichild(ep->focus);
  1255. X
  1256. X    s_up(ep);
  1257. X    s_downi(ep, ich+1);
  1258. X}
  1259. X#endif
  1260. X
  1261. X/*
  1262. X * Find next item in a subset, using ep->s1 as index.
  1263. X * (This used to be less trivial, so it's still a subroutine rather than
  1264. X * coded in-line or as a macro.)
  1265. X */
  1266. X
  1267. XHidden bool
  1268. Xnextitem(ep)
  1269. X    register environ *ep;
  1270. X{
  1271. X    if (ep->s1 >= 2*nchildren(tree(ep->focus)) + 1)
  1272. X        return No; /* Already at last item */
  1273. X    ++ep->s1;
  1274. X    return Yes;
  1275. X}
  1276. X
  1277. X
  1278. X/*
  1279. X * Ditto for previous.
  1280. X */
  1281. X
  1282. XHidden bool
  1283. Xprevitem(ep)
  1284. X    register environ *ep;
  1285. X{
  1286. X    if (ep->s1 <= 1
  1287. X        || ep->s1 == 2 && fwidth(noderepr(tree(ep->focus))[0]) < 0)
  1288. X        return No; /* Already at first item */
  1289. X    --ep->s1;
  1290. X    return Yes;
  1291. X}
  1292. X
  1293. X
  1294. X/*
  1295. X * Test whether item ep->s1 is "small", i.e., fixed or varying text
  1296. X * but not a whole subtree.
  1297. X */
  1298. X
  1299. XHidden bool
  1300. Xisunititem(ep)
  1301. X    register environ *ep;
  1302. X{
  1303. X    if (ep->s1&1)
  1304. X        return Yes;
  1305. X    return Is_etext(child(tree(ep->focus), ep->s1/2));
  1306. X}
  1307. X
  1308. X
  1309. X/*
  1310. X * Check for consistent mode information.
  1311. X */
  1312. X
  1313. XVisible bool
  1314. Xcheckep(ep)
  1315. X    register environ *ep;
  1316. X{
  1317. X    switch (ep->mode) {
  1318. X
  1319. X    case FHOLE:
  1320. X        if (!(ep->s1&1))
  1321. X            break;
  1322. X        if (ep->s2 < 0 || ep->s2 > lenitem(ep))
  1323. X            break;
  1324. X        return Yes;
  1325. X
  1326. X    case VHOLE:
  1327. X        if (!(ep->s1&1)) {
  1328. X            if (!Is_etext(child(tree(ep->focus), ep->s1/2)))
  1329. X                break;
  1330. X        }
  1331. X        if (ep->s2 < 0 || ep->s2 > lenitem(ep))
  1332. X            break;
  1333. X        return Yes;
  1334. X
  1335. X    case SUBSET:
  1336. X        if (ep->s2 == ep->s1 && isunititem(ep) && lenitem(ep) <= 0)
  1337. X            break;
  1338. X        return Yes;
  1339. X
  1340. X    default:
  1341. X        return Yes;
  1342. X
  1343. X    }
  1344. X#ifndef NDEBUG
  1345. X    dbmess(ep);
  1346. X#endif /* NDEBUG */
  1347. X    return No;
  1348. X}
  1349. X
  1350. X
  1351. X/*
  1352. X * Like {next,prev,first,last}item, but with empty items skipped
  1353. X * (i.e., those with length <= 0).
  1354. X */
  1355. X
  1356. XVisible bool
  1357. Xnextnnitem(ep)
  1358. X    register environ *ep;
  1359. X{
  1360. X    register int s1save = ep->s1;
  1361. X
  1362. X    while (nextitem(ep)) {
  1363. X        if (lenitem(ep) != 0)
  1364. X            return Yes;
  1365. X    }
  1366. X    ep->s1 = s1save;
  1367. X    return No;
  1368. X}
  1369. X
  1370. XVisible bool
  1371. Xprevnnitem(ep)
  1372. X    register environ *ep;
  1373. X{
  1374. X    register int s1save = ep->s1;
  1375. X    register int len;
  1376. X
  1377. X    while (previtem(ep)) {
  1378. X        len = lenitem(ep);
  1379. X        if (len > 0 || len < 0 && ep->s1 > 1)
  1380. X            return Yes;
  1381. X    }
  1382. X    ep->s1 = s1save;
  1383. X    return No;
  1384. X}
  1385. X
  1386. X#ifdef NOT_USED
  1387. XVisible Procedure
  1388. Xfirstnnitem(ep)
  1389. X    register environ *ep;
  1390. X{
  1391. X    ep->s1 = fwidth(noderepr(tree(ep->focus))[0]) < 0 ? 2 : 1;
  1392. X    while (lenitem(ep) == 0) {
  1393. X        if (!nextitem(ep))
  1394. X            break;
  1395. X    }
  1396. X    return;
  1397. X}
  1398. X#endif
  1399. X
  1400. XVisible Procedure
  1401. Xlastnnitem(ep)
  1402. X    register environ *ep;
  1403. X{
  1404. X    ep->s1 = 2*nchildren(tree(ep->focus)) + 1;
  1405. X    while (lenitem(ep) == 0) {
  1406. X        if (!previtem(ep))
  1407. X            break;
  1408. X    }
  1409. X    return;
  1410. X}
  1411. X
  1412. X
  1413. X/*
  1414. X * Prepare the focus for insertion.
  1415. X * If the focus isn't a hole, make a hole just before it which becomes the
  1416. X * new focus.
  1417. X * Also repair strange statuses left by moves, so we may have more chance
  1418. X * to insert a character.
  1419. X */
  1420. X
  1421. XVisible Procedure
  1422. Xfixit(ep)
  1423. X    register environ *ep;
  1424. X{
  1425. X    /* First, make a hole if it's not already a hole. */
  1426. X
  1427. X    switch (ep->mode) {
  1428. X
  1429. X    case FHOLE:
  1430. X        break;
  1431. X
  1432. X    case VHOLE:
  1433. X        if (ep->s1&1)
  1434. X            ep->mode = FHOLE;
  1435. X        break;
  1436. X
  1437. X    case SUBRANGE:
  1438. X        if (ep->s1&1)
  1439. X            ep->mode = FHOLE;
  1440. X        else
  1441. X            ep->mode = VHOLE;
  1442. X        break;
  1443. X
  1444. X    case SUBSET:
  1445. X        if (ep->s1&1) {
  1446. X            if (ep->s1 == 1)
  1447. X                ep->mode = ATBEGIN;
  1448. X            else {
  1449. X                ep->mode = FHOLE;
  1450. X                ep->s2 = 0;
  1451. X            }
  1452. X        }
  1453. X        else if (Is_etext(child(tree(ep->focus), ep->s1/2))) {
  1454. X            ep->mode = VHOLE;
  1455. X            ep->s2 = 0;
  1456. X        }
  1457. X        else {
  1458. X            s_downi(ep, ep->s1/2);
  1459. X            ep->mode = ATBEGIN;
  1460. X        }
  1461. X        break;
  1462. X
  1463. X    case ATBEGIN:
  1464. X    case SUBLIST:
  1465. X    case WHOLE:
  1466. X        ep->mode = ATBEGIN;
  1467. X        break;
  1468. X
  1469. X    case ATEND:
  1470. X        break;
  1471. X
  1472. X    default:
  1473. X        Abort();
  1474. X    }
  1475. X
  1476. X    leftvhole(ep);
  1477. X    if (ep->mode == ATEND && symbol(tree(ep->focus)) == Hole)
  1478. X        ep->mode = WHOLE; /***** Experiment! *****/
  1479. X}
  1480. X
  1481. X
  1482. X/*
  1483. X * Small utility to see if a string contains only spaces
  1484. X * (this is true for the empty string "").
  1485. X * The string pointer must not be null!
  1486. X */
  1487. X
  1488. XVisible bool
  1489. Xallspaces(str)
  1490. X    register string str;
  1491. X{
  1492. X    Assert(str);
  1493. X    for (; *str; ++str) {
  1494. X        if (*str != ' ')
  1495. X            return No;
  1496. X    }
  1497. X    return Yes;
  1498. X}
  1499. X
  1500. X
  1501. X/*
  1502. X * Function to compute the actual width of the focus.
  1503. X */
  1504. X
  1505. XVisible int
  1506. Xfocwidth(ep)
  1507. X    register environ *ep;
  1508. X{
  1509. X    node nn;
  1510. X    register node n = tree(ep->focus);
  1511. X    register string *rp = noderepr(n);
  1512. X    register int i;
  1513. X    register int w;
  1514. X    int len = 0;
  1515. X
  1516. X    switch (ep->mode) {
  1517. X
  1518. X    case VHOLE:
  1519. X    case FHOLE:
  1520. X    case ATEND:
  1521. X    case ATBEGIN:
  1522. X        return 0;
  1523. X
  1524. X    case WHOLE:
  1525. X        return nodewidth(n);
  1526. X
  1527. X    case SUBRANGE:
  1528. X        return ep->s3 - ep->s2 + 1;
  1529. X
  1530. X    case SUBSET:
  1531. X        for (i = ep->s1; i <= ep->s2; ++i) {
  1532. X            if (i&1)
  1533. X                w = fwidth(rp[i/2]);
  1534. X            else {
  1535. X                nn = child(n, i/2);
  1536. X                w = nodewidth(nn);
  1537. X            }
  1538. X            if (w < 0 && len >= 0)
  1539. X                len = w;
  1540. X            else if (w >= 0 && len < 0)
  1541. X                ;
  1542. X            else
  1543. X                len += w;
  1544. X        }
  1545. X        return len;
  1546. X
  1547. X    case SUBLIST:
  1548. X        len = nodewidth(n);
  1549. X        for (i = ep->s3; i > 0; --i)
  1550. X            n = lastchild(n);
  1551. X        w = nodewidth(n);
  1552. X        if (w < 0 && len >= 0)
  1553. X            return w;
  1554. X        if (w >= 0 && len < 0)
  1555. X            return len;
  1556. X        return len - w;
  1557. X
  1558. X    default:
  1559. X        Abort();
  1560. X        /* NOTREACHED */
  1561. X    }
  1562. X}
  1563. X
  1564. X
  1565. X/*
  1566. X * Compute the offset of the focus from the beginning of the current node.
  1567. X * This may be input again to fixfocus to allow restoration of this position.
  1568. X */
  1569. X
  1570. XVisible int
  1571. Xfocoffset(ep)
  1572. X    register environ *ep;
  1573. X{
  1574. X    node nn;
  1575. X    register node n;
  1576. X    register string *rp;
  1577. X    register int w;
  1578. X    register int len;
  1579. X    register int i;
  1580. X
  1581. X    switch (ep->mode) {
  1582. X
  1583. X    case WHOLE:
  1584. X    case SUBLIST:
  1585. X        return 0;
  1586. X
  1587. X    case ATBEGIN:
  1588. X        return ep->spflag;
  1589. X
  1590. X    case ATEND:
  1591. X        w = nodewidth(tree(ep->focus));
  1592. X        if (w < 0)
  1593. X            return w;
  1594. X        return w + ep->spflag;
  1595. X
  1596. X    case SUBSET:
  1597. X    case FHOLE:
  1598. X    case VHOLE:
  1599. X    case SUBRANGE:
  1600. X        n = tree(ep->focus);
  1601. X        rp = noderepr(n);
  1602. X        len = 0;
  1603. X        for (i = 1; i < ep->s1; ++i) {
  1604. X            if (i&1)
  1605. X                w = Fwidth(rp[i/2]);
  1606. X            else {
  1607. X                nn = child(n, i/2);
  1608. X                w = nodewidth(nn);
  1609. X            }
  1610. X            if (w < 0) {
  1611. X                if (len >= 0)
  1612. X                    len = w;
  1613. X                else
  1614. X                    len += w;
  1615. X            }
  1616. X            else if (len >= 0)
  1617. X                len += w;
  1618. X        }
  1619. X        if (ep->mode == SUBSET || len < 0)
  1620. X            return len;
  1621. X        return len + ep->s2 + ep->spflag;
  1622. X
  1623. X    default:
  1624. X        Abort();
  1625. X        /* NOTREACHED */
  1626. X    }
  1627. X}
  1628. X
  1629. X/*
  1630. X * Return the first character of the focus (maybe '\n'; 0 if zero-width).
  1631. X */
  1632. X
  1633. XVisible int
  1634. Xfocchar(ep)
  1635. X    environ *ep;
  1636. X{
  1637. X    node n = tree(ep->focus);
  1638. X    string *rp;
  1639. X    int i;
  1640. X    int c;
  1641. X
  1642. X    switch (ep->mode) {
  1643. X
  1644. X    case VHOLE:
  1645. X    case FHOLE:
  1646. X    case ATBEGIN:
  1647. X    case ATEND:
  1648. X        return 0;
  1649. X
  1650. X    case WHOLE:
  1651. X    case SUBLIST:
  1652. X        return nodechar(n);
  1653. X
  1654. X    case SUBSET:
  1655. X        rp = noderepr(n);
  1656. X        for (i = ep->s1; i <= ep->s2; ++i) {
  1657. X            if (i&1) {
  1658. X                if (!Fw_zero(rp[i/2]))
  1659. X                return rp[i/2][0];
  1660. X            }
  1661. X            else {
  1662. X                c = nodechar(child(n, i/2));
  1663. X                if (c)
  1664. X                    return c;
  1665. X            }
  1666. X        }
  1667. X        return 0;
  1668. X
  1669. X    case SUBRANGE:
  1670. X        if (ep->s1&1) {
  1671. X            string *nr= noderepr(n);
  1672. X            return nr[ep->s1/2][ep->s2];
  1673. X        }
  1674. X        else {
  1675. X            Assert(Is_etext(child(n, ep->s1/2)));
  1676. X            return e_ncharval(ep->s2 + 1, (value) child(n, ep->s1/2));
  1677. X        }
  1678. X
  1679. X    default:
  1680. X        Abort();
  1681. X        /* NOTREACHED */
  1682. X
  1683. X    }
  1684. X}
  1685. X
  1686. X
  1687. X/*
  1688. X * Subroutine to return first character of node.
  1689. X */
  1690. X
  1691. XVisible int
  1692. Xnodechar(n)
  1693. X    node n;
  1694. X{
  1695. X    string *rp;
  1696. X    int nch;
  1697. X    int i;
  1698. X    int c;
  1699. X
  1700. X    if (Is_etext(n))
  1701. X/*        return strval((value)n)[0]; */
  1702. X        return e_ncharval(1, (value) n);
  1703. X    rp = noderepr(n);
  1704. X    if (!Fw_zero(rp[0]))
  1705. X        return rp[0][0];
  1706. X    nch = nchildren(n);
  1707. X    for (i = 1; i <= nch; ++i) {
  1708. X        c = nodechar(child(n, i));
  1709. X        if (c)
  1710. X            return c;
  1711. X        if (!Fw_zero(rp[i]))
  1712. X            return rp[i][0];
  1713. X    }
  1714. X    return 0;
  1715. X}
  1716. X
  1717. X
  1718. X/*
  1719. X * Function to compute the actual indentation level at the focus.
  1720. X */
  1721. X
  1722. XVisible int
  1723. Xfocindent(ep)
  1724. X    environ *ep;
  1725. X{
  1726. X    int y = Ycoord(ep->focus);
  1727. X    int x = Xcoord(ep->focus);
  1728. X    int level = Level(ep->focus);
  1729. X    node n = tree(ep->focus);
  1730. X
  1731. X    switch (ep->mode) {
  1732. X
  1733. X    case WHOLE:
  1734. X    case ATBEGIN:
  1735. X    case SUBLIST:
  1736. X        break;
  1737. X
  1738. X    case ATEND:
  1739. X        evalcoord(n, 1 + nchildren(n), &y, &x, &level);
  1740. X        break;
  1741. X
  1742. X    case SUBSET:
  1743. X    case FHOLE:
  1744. X    case VHOLE:
  1745. X        evalcoord(n, ep->s1/2, &y, &x, &level);
  1746. X        break;
  1747. X
  1748. X    default:
  1749. X        Abort();
  1750. X    }
  1751. X    return level;
  1752. X}
  1753. X
  1754. X
  1755. X/*
  1756. X * Routines to move 'environ' structures.
  1757. X */
  1758. X
  1759. Xemove(s, d)
  1760. X    environ *s;
  1761. X    environ *d;
  1762. X{
  1763. X#ifdef STRUCTASS
  1764. X    *d = *s;
  1765. X#else /* !STRUCTASS */
  1766. X    d->focus = s->focus;
  1767. X
  1768. X    d->mode = s->mode;
  1769. X    d->copyflag = s->copyflag;
  1770. X    d->spflag = s->spflag;
  1771. X    d->changed = s->changed;
  1772. X
  1773. X    d->s1 = s->s1;
  1774. X    d->s2 = s->s2;
  1775. X    d->s3 = s->s3;
  1776. X
  1777. X    d->highest = s->highest;
  1778. X
  1779. X    d->copybuffer = s->copybuffer;
  1780. X#ifdef RECORDING
  1781. X    d->oldmacro = s->oldmacro;
  1782. X    d->newmacro = s->newmacro;
  1783. X#endif /* RECORDING */
  1784. X
  1785. X    d->generation = s->generation;
  1786. X#endif /* !STRUCTASS */
  1787. X}
  1788. X
  1789. Xecopy(s, d)
  1790. X    environ *s;
  1791. X    environ *d;
  1792. X{
  1793. X    emove(s, d);
  1794. X    VOID pathcopy(d->focus);
  1795. X    VOID copy(d->copybuffer);
  1796. X#ifdef RECORDING
  1797. X    VOID copy(d->oldmacro);
  1798. X    VOID copy(d->newmacro);
  1799. X#endif /* RECORDING */
  1800. X}
  1801. X
  1802. Xerelease(e)
  1803. X    environ *e;
  1804. X{
  1805. X    pathrelease(e->focus);
  1806. X    release(e->copybuffer);
  1807. X#ifdef RECORDING
  1808. X    release(e->oldmacro);
  1809. X    release(e->newmacro);
  1810. X#endif /* RECORDING */
  1811. X}
  1812. X
  1813. X/*
  1814. X * Routines to move 'environ' structures.
  1815. X */
  1816. X
  1817. XVisible bool ev_eq(l, r)
  1818. X    environ *l;
  1819. X    environ *r;
  1820. X{
  1821. X    if (l->focus == r->focus
  1822. X        && l->mode == r->mode
  1823. X        && l->copyflag == r->copyflag
  1824. X        && l->spflag == r->spflag
  1825. X        && l->changed == r->changed
  1826. X        && l->s1 == r->s1
  1827. X        && l->s2 == r->s2
  1828. X        && l->s3 == r->s3
  1829. X        && (l->highest == r->highest || l->highest == Maxintlet)
  1830. X        && l->copybuffer == r->copybuffer
  1831. X#ifdef RECORDING
  1832. X        && l->oldmacro == r->oldmacro
  1833. X        && l->newmacro == r->newmacro
  1834. X#endif /* RECORDING */
  1835. X    )
  1836. X        return Yes;
  1837. X    else
  1838. X        return No;
  1839. X}
  1840. END_OF_FILE
  1841.   if test 19545 -ne `wc -c <'abc/bed/e1supr.c'`; then
  1842.     echo shar: \"'abc/bed/e1supr.c'\" unpacked with wrong size!
  1843.   fi
  1844.   # end of 'abc/bed/e1supr.c'
  1845. fi
  1846. if test -f 'abc/bint3/i3sta.c' -a "${1}" != "-c" ; then 
  1847.   echo shar: Will not clobber existing file \"'abc/bint3/i3sta.c'\"
  1848. else
  1849.   echo shar: Extracting \"'abc/bint3/i3sta.c'\" \(18967 characters\)
  1850.   sed "s/^X//" >'abc/bint3/i3sta.c' <<'END_OF_FILE'
  1851. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
  1852. X
  1853. X/* Stacks used by the interpreter */
  1854. X
  1855. X#include "b.h"
  1856. X#include "bint.h"
  1857. X#include "feat.h"     /* for EXT_RANGE */
  1858. X#include "bmem.h"
  1859. X#include "bobj.h"
  1860. X#include "i0err.h"
  1861. X#include "i1num.h"
  1862. X#include "i2nod.h"
  1863. X#include "i3env.h"
  1864. X#include "i3int.h"
  1865. X#include "i3in2.h"
  1866. X#include "i3sou.h"
  1867. X
  1868. X/* Fundamental registers: (shared only between this file and b3int.c) */
  1869. X
  1870. XVisible parsetree pc; /* 'Program counter', current parsetree node */
  1871. XVisible parsetree next; /* Next parsetree node (changed by jumps) */
  1872. XVisible bool report; /* 'Condition code register', outcome of last test */
  1873. X
  1874. XHidden env boundtags; /* Holds bound tags chain */
  1875. X
  1876. X/* Value stack: */
  1877. X
  1878. X/* The run-time value stack grows upward, sp points to the next free entry.
  1879. X   Allocated stack space lies between st_base and st_top.
  1880. X   In the current invocation, the stack pointer (sp) must lie between
  1881. X   st_bottom and st_top.
  1882. X   Stack overflow is corrected by growing st_top, underflow is a fatal
  1883. X   error (generated code is wrong).
  1884. X*/
  1885. X
  1886. XHidden value *st_base, *st_bottom, *st_top, *sp;
  1887. XVisible int call_level; /* While run() can be called recursively */
  1888. X
  1889. X#define EmptyStack() (sp == st_bottom)
  1890. X#define BotOffset() (st_bottom - st_base)
  1891. X#define SetBotOffset(n) (st_bottom= st_base + (n))
  1892. X
  1893. X#define INCREMENT 100
  1894. X
  1895. XHidden Procedure st_grow(incr) int incr; {
  1896. X    if (st_base == Pnil) { /* First time ever */
  1897. X        st_bottom= sp= st_base=
  1898. X            (value*) getmem((unsigned) incr * sizeof(value *));
  1899. X        st_top= st_base + incr;
  1900. X    }
  1901. X    else {
  1902. X        int syze= (st_top - st_base) + incr;
  1903. X        int n_bottom= BotOffset();
  1904. X        int n_sp= sp - st_base;
  1905. X        regetmem((ptr*) &st_base, (unsigned) syze * sizeof(value *));
  1906. X        sp = st_base + n_sp;
  1907. X        SetBotOffset(n_bottom);
  1908. X        st_top= st_base + syze;
  1909. X    }
  1910. X}
  1911. X
  1912. XVisible value pop() {
  1913. X    if (sp <= st_bottom) {
  1914. X        syserr(MESS(4100, "stack underflow"));
  1915. X        return Vnil;
  1916. X    }
  1917. X    return *--sp;
  1918. X}
  1919. X
  1920. XVisible Procedure push(v) value v; {
  1921. X    if (sp >= st_top) st_grow(INCREMENT);
  1922. X    *sp++ = (v);
  1923. X}
  1924. X
  1925. X/* - - - */
  1926. X
  1927. X/* Various call types, used as index in array: */
  1928. X
  1929. X#define C_howto 0
  1930. X#define C_yield 1
  1931. X#define C_test 2
  1932. X
  1933. X#define C_refcmd 3
  1934. X#define C_refexp 4
  1935. X#define C_reftest 5
  1936. X
  1937. X
  1938. X/* What can happen to a thing: */
  1939. X
  1940. X#define Old 'o'
  1941. X#define Cpy 'c'
  1942. X#define New 'n'
  1943. X#define Non '-'
  1944. X
  1945. Xtypedef struct {
  1946. X    literal do_cur;
  1947. X    literal do_prm;
  1948. X    literal do_bnd;
  1949. X    literal do_for;
  1950. X    literal do_resexp;
  1951. X} dorecord;
  1952. X
  1953. X
  1954. X/* Table encoding what to save/restore for various call/return types: */
  1955. X/* (Special cases are handled elsewhere.) */
  1956. X
  1957. XHidden dorecord doo[] = {
  1958. X    /*         cur  prm  bnd  for  resexp */
  1959. X
  1960. X    /* HOW-TO */    {New, Old, Non, New, Voi},
  1961. X    /* YIELD */    {New, Cpy, Non, Non, Ret},
  1962. X    /* TEST */    {New, Cpy, Non, Non, Rep},
  1963. X
  1964. X    /* REF-CMD */    {Old, Old, Old, Old, Voi},
  1965. X    /* ref-expr */    {Cpy, Cpy, Non, Old, Ret},
  1966. X    /* ref-test */    {Cpy, Cpy, New, Old, Rep}
  1967. X};
  1968. X
  1969. X#define MAXTYPE ((sizeof doo) / (sizeof doo[0]))
  1970. X
  1971. X#define Checksum(type) (12345 - (type)) /* Reversible */
  1972. X
  1973. X
  1974. X#define Ipush(n) push(MkSmallInt(n))
  1975. X#define Ipop() SmallIntVal(pop())
  1976. X
  1977. X
  1978. XHidden env newenv(tab, inv_env) envtab tab; env inv_env; {
  1979. X    env ev= (env) getmem(sizeof(envchain));
  1980. X    ev->tab= tab; /* Eats a reference to tab! */
  1981. X    ev->inv_env= inv_env;
  1982. X    return ev;
  1983. X}
  1984. X
  1985. XHidden Procedure pushenv(pe) env *pe; {
  1986. X    env ev= (env) getmem(sizeof(envchain));
  1987. X    ev->tab= copy((*pe)->tab);
  1988. X    ev->inv_env= *pe;
  1989. X    *pe= ev;
  1990. X}    
  1991. X
  1992. XHidden Procedure popenv(pe) env *pe; {
  1993. X    env ev= *pe;
  1994. X    *pe= ev->inv_env;
  1995. X    release(ev->tab);
  1996. X    freemem((ptr) ev);
  1997. X}
  1998. X
  1999. X
  2000. XHidden Procedure call(type, new_pc) intlet type; parsetree new_pc; {
  2001. X    if (type < 0 || type >= MAXTYPE) syserr(MESS(4101, "bad call type"));
  2002. X
  2003. X    /* Push other stacks */
  2004. X
  2005. X    if (doo[type].do_bnd != Old) {
  2006. X        boundtags= newenv(
  2007. X            (doo[type].do_bnd == New) ? mk_elt() : Vnil,
  2008. X            boundtags);
  2009. X        bndtgs= &boundtags->tab;
  2010. X    }
  2011. X    switch (doo[type].do_cur) {
  2012. X
  2013. X    case New:
  2014. X        curnv= newenv(Vnil, curnv);
  2015. X        break;
  2016. X
  2017. X    case Cpy:
  2018. X        pushenv(&curnv);
  2019. X        break;
  2020. X
  2021. X    }
  2022. X    switch (doo[type].do_prm) {
  2023. X
  2024. X    case Old:
  2025. X        break;
  2026. X
  2027. X    case Cpy:
  2028. X        pushenv(&prmnv);
  2029. X        break;
  2030. X    }
  2031. X
  2032. X    /* Push those things that depend on the call type: */
  2033. X
  2034. X    if (doo[type].do_for != Old) {
  2035. X        push(copy(uname));
  2036. X    }
  2037. X
  2038. X    /* Push miscellaneous context info: */
  2039. X    push(curline);
  2040. X    push(curlino);
  2041. X    Ipush(resexp); resexp= doo[type].do_resexp;
  2042. X    Ipush(cntxt);
  2043. X    resval= Vnil;
  2044. X
  2045. X    /* Push vital data: */
  2046. X    push(next);
  2047. X    Ipush(BotOffset()); ++call_level;
  2048. X    Ipush(Checksum(type)); /* Kind of checksum */
  2049. X
  2050. X    /* Set st_bottom and jump: */
  2051. X    st_bottom= sp;
  2052. X    next= new_pc;
  2053. X}
  2054. X
  2055. X
  2056. XVisible Procedure ret() {
  2057. X    int type; value rv= resval; literal re= resexp;
  2058. X    value oldcurnvtab= Vnil, oldbtl= Vnil;
  2059. X
  2060. X    /* Clear stack: */
  2061. X    while (!EmptyStack()) release(pop());
  2062. X
  2063. X    /* Pop type and hope it's good: */
  2064. X    st_bottom= st_base; /* Trick to allow popping the return info */
  2065. X    type= Checksum(Ipop());
  2066. X    if (type < 0 || type >= MAXTYPE) syserr(MESS(4102, "stack clobbered"));
  2067. X
  2068. X    /* Pop vital data: */
  2069. X    SetBotOffset(Ipop()); --call_level;
  2070. X    next= pop();
  2071. X
  2072. X    /* Pop context info: */
  2073. X    cntxt= Ipop();
  2074. X    resexp= Ipop();
  2075. X    curlino= pop();
  2076. X    curline= pop();
  2077. X
  2078. X    /* Variable part: */
  2079. X    if (doo[type].do_for != Old) {
  2080. X        release(uname); uname= pop();
  2081. X        /* FP removed */
  2082. X    }
  2083. X    if (doo[type].do_prm != Old)
  2084. X        popenv(&prmnv);
  2085. X    switch (doo[type].do_cur) {
  2086. X
  2087. X    case Cpy:    
  2088. X    case New:
  2089. X        oldcurnvtab= copy(curnv->tab);
  2090. X        popenv(&curnv);
  2091. X        break;
  2092. X
  2093. X    }
  2094. X    if (doo[type].do_bnd != Old) {
  2095. X        oldbtl= copy(*bndtgs);
  2096. X        popenv(&boundtags);
  2097. X        bndtgs= &boundtags->tab;
  2098. X    }
  2099. X
  2100. X    /* Fiddle bound tags */
  2101. X    if (Valid(oldbtl)) {
  2102. X        extbnd_tags(oldbtl, oldcurnvtab);
  2103. X        release(oldbtl);
  2104. X    }
  2105. X    
  2106. X    /* Put back arguments for commands: */
  2107. X    if (type == C_howto && still_ok) putbackargs(oldcurnvtab);
  2108. X
  2109. X    if (Valid(oldcurnvtab)) release(oldcurnvtab);
  2110. X    if (call_level == 0) re_env(); /* Resets bndtgs */
  2111. X
  2112. X    /* Push return value (if any): */
  2113. X    if (re == Ret && still_ok) push(rv);
  2114. X}
  2115. X
  2116. X/* - - - */
  2117. X
  2118. XVisible Procedure call_refinement(name, def, test)
  2119. X        value name; parsetree def; bool test; {
  2120. X    call(test ? C_reftest : C_refexp,
  2121. X        *Branch(Refinement(def)->rp, REF_START));
  2122. X}
  2123. X
  2124. X#define YOU_TEST MESS(4103, "You haven't told me HOW TO REPORT %s")
  2125. X#define YOU_YIELD MESS(4104, "You haven't told me HOW TO RETURN %s")
  2126. X
  2127. XHidden Procedure udfpr(nd1, name, nd2, isfunc)
  2128. X        value nd1, name, nd2; bool isfunc; {
  2129. X    value *aa;
  2130. X    bool bad = No;
  2131. X    parsetree u; int k, nlocals; funprd *fpr;
  2132. X    int adicity;
  2133. X
  2134. X    if (isfunc) adicity= nd1 ? Dfd : nd2 ? Mfd : Zfd;
  2135. X    else adicity= nd1 ? Dpd : nd2 ? Mpd : Zpd;
  2136. X
  2137. X    if (!is_unit(name, adicity, &aa)) bad = Yes;
  2138. X    else if (isfunc) bad = !Is_function(*aa);
  2139. X    else bad= !Is_predicate(*aa);
  2140. X    if (bad) {
  2141. X        interrV(isfunc ? YOU_YIELD : YOU_TEST, name);
  2142. X        return;
  2143. X    }
  2144. X    fpr= Funprd(*aa);
  2145. X
  2146. X    if (fpr->adic==Zfd || fpr->adic==Zpd) {
  2147. X        if (Valid(nd2)) bad = Yes;
  2148. X    }
  2149. X    else if (fpr->adic==Mfd || fpr->adic==Mpd) {
  2150. X        if (Valid(nd1)) bad = Yes;
  2151. X    }
  2152. X
  2153. X    if (bad) syserr(MESS(4105, "invoked how-to has other adicity than invoker"));
  2154. X    if (fpr->pre != Use) syserr(MESS(4106, "udfpr with predefined how-to"));
  2155. X
  2156. X    u= fpr->unit;
  2157. X    if (fpr->unparsed) fix_nodes(&u, &fpr->code);
  2158. X    if (!still_ok) { rem_unit(u); return; }
  2159. X    fpr->unparsed= No;
  2160. X    nlocals= intval(*Branch(u, FPR_NLOCALS));
  2161. X    call(isfunc ? C_yield : C_test, fpr->code);
  2162. X    curnv->tab= mk_compound(nlocals);
  2163. X    for (k= 0; k < nlocals; ++k) *Field(curnv->tab, k)= Vnil;
  2164. X    if (Valid(nd1)) push(copy(nd1));
  2165. X    if (Valid(nd2)) push(copy(nd2));
  2166. X}
  2167. X
  2168. XVisible Procedure formula(nd1, name, nd2, tor) value nd1, name, nd2, tor; {
  2169. X    if (!Valid(tor)) udfpr(nd1, name, nd2, Yes);
  2170. X    else {
  2171. X        if (!Is_function(tor))
  2172. X            syserr(MESS(4107, "formula called with non-function"));
  2173. X        push(pre_fun(nd1, Funprd(tor)->pre, nd2));
  2174. X    }
  2175. X}
  2176. X
  2177. XVisible Procedure proposition(nd1, name, nd2, pred) value nd1, name, nd2, pred; {
  2178. X    if (!Valid(pred)) udfpr(nd1, name, nd2, No);
  2179. X    else {
  2180. X        if (!Is_predicate(pred))
  2181. X            syserr(MESS(4108, "proposition called with non-predicate"));
  2182. X        report= pre_prop(nd1, Funprd(pred)->pre, nd2);
  2183. X    }
  2184. X}
  2185. X
  2186. X/* Temporary code to hack copy/restore parameters.
  2187. X   Note -- this needs extension to the case where an actuals can be
  2188. X   a compound mixture of expressions and locations. */
  2189. X
  2190. XHidden bool is_location(v) value v; {
  2191. X    while (Valid(v) && Is_compound(v))
  2192. X        v= *Field(v, 0);
  2193. X    return Valid(v) && (Is_simploc(v) || Is_tbseloc(v) || Is_trimloc(v));
  2194. X}
  2195. X
  2196. XHidden value n_trim(v, B, C) value v; value B, C; {
  2197. X    /* Return v|(#v-C)@(B+1) */
  2198. X    value B_plus_1= sum(B, one);
  2199. X    value res1= behead(v, B_plus_1);
  2200. X    value sz= size(res1);
  2201. X    value tail= diff(sz, C);
  2202. X    value res= curtail(res1, tail);
  2203. X    release(B_plus_1), release(res1), release(sz), release(tail);
  2204. X    return res;
  2205. X}
  2206. X
  2207. X/* Extract a value from something that may be a location or a value.
  2208. X   If it's a value, return No.
  2209. X   If it's a non-empty location,
  2210. X       return Yes and put a copy of its content in *pv;
  2211. X   if it's an empty location, return Yes and put Vnil in *pv. */
  2212. X
  2213. XHidden bool extract(l, pv) loc l; value *pv; {
  2214. X    value *ll, lv;
  2215. X    *pv= Vnil;
  2216. X    if (l == Lnil)
  2217. X        return No;
  2218. X    else if (Is_simploc(l)) {
  2219. X        lv= locvalue(l, &ll, No);
  2220. X        if (Valid(lv))
  2221. X            *pv= copy(lv);
  2222. X        return Yes;
  2223. X    }
  2224. X    else if (Is_tbseloc(l)) {
  2225. X        tbseloc *tl= Tbseloc(l);
  2226. X        lv= locvalue(tl->R, &ll, Yes);
  2227. X        if (still_ok) {
  2228. X            if (!Is_table(lv))
  2229. X                interr(SEL_NO_TABLE);
  2230. X            else {
  2231. X                ll= adrassoc(lv, tl->K);
  2232. X                if (ll != Pnil)
  2233. X                    *pv= copy(*ll);
  2234. X            }
  2235. X        }
  2236. X        return Yes;
  2237. X    }
  2238. X    else if (Is_trimloc(l)) {
  2239. X        trimloc *rr= Trimloc(l);
  2240. X        lv= locvalue(rr->R, &ll, Yes);
  2241. X        if (still_ok)
  2242. X            *pv= n_trim(lv, rr->B, rr->C);
  2243. X        return Yes;
  2244. X    }
  2245. X    else if (Is_compound(l)) {
  2246. X        /* Assume that if one field is a location, they all are.
  2247. X           That's not really valid, but for now it works
  2248. X           (until someone fixes the code generation...) */
  2249. X        value v;
  2250. X        if (!extract(*Field(l, 0), &v))
  2251. X            return No;
  2252. X        if (Valid(v)) {
  2253. X            bool ok= Yes;
  2254. X            int i;
  2255. X            *pv= mk_compound(Nfields(l));
  2256. X            *Field(*pv, 0)= v;
  2257. X            for (i= 1; i < Nfields(l) && still_ok; ++i) {
  2258. X                if (!extract(*Field(l, i), Field(*pv, i))
  2259. X                        && still_ok)
  2260. X                    syserr(MESS(4109, "extract"));
  2261. X                if (!Valid(*Field(*pv, i)))
  2262. X                    ok= No;
  2263. X            }
  2264. X            if (!ok) {
  2265. X                release(*pv);
  2266. X                *pv= Vnil;
  2267. X            }
  2268. X        }
  2269. X        return Yes;
  2270. X    }
  2271. X    return No;
  2272. X}
  2273. X
  2274. X/* Return a copy of the value of something that may be a location or a
  2275. X   value.  If it's a location, return a copy of its content
  2276. X   (or Vnil if it's empty); if it's a value, return a copy of it. */
  2277. X
  2278. XHidden value n_content(l) loc l; {
  2279. X    value v;
  2280. X    if (extract(l, &v))
  2281. X        return v;
  2282. X    else
  2283. X        return copy(l);
  2284. X}
  2285. X
  2286. X/* Put the actuals in the locals representing formals;
  2287. X   save the locations of the actuals, and save their values.
  2288. X   Also (actually, first of all), save the parse tree for the formals.
  2289. X   Return a compound for the initialized locals.
  2290. X   
  2291. X   Input: the actuals are found on the stack;
  2292. X   they have been pushed from left to right so have to be popped off
  2293. X   in reverse order.  Each actual corresponds to one 'slot' for a
  2294. X   formal parameter, which may be a multiple identifier.  It has to be
  2295. X   unraveled and put in the individual locals.  There are a zillion
  2296. X   reasons why this might fail.
  2297. X   
  2298. X   This routine is called 'epibreer' after a famous Dutch nonsense word,
  2299. X   the verb 'epibreren', coined by the Amsterdam writer S. Carmiggelt (?),
  2300. X   which has taken on the meaning or any complicated processing job
  2301. X   (at least in the ABC group). */
  2302. X
  2303. XHidden value epibreer(formals, argcnt, nlocals)
  2304. X    parsetree formals;            /* Parse tree for formals */
  2305. X    int argcnt;                /* Nr. of argument slots */
  2306. X    int nlocals;                /* Nr. of local variables */
  2307. X{
  2308. X    value locals= mk_compound(nlocals);    /* Local variables */
  2309. X    value actuals= mk_compound(argcnt);    /* Actuals (locs/values) */
  2310. X    int nextlocal= 0;            /* Next formal tag's number */
  2311. X    int slot;                /* Formal slot number */
  2312. X    
  2313. X    /* Pop actuals from stack, in reverse order. */
  2314. X    for (slot= argcnt; --slot >= 0; )
  2315. X        *Field(actuals, slot)= pop();    /* Hope the count's ok... */
  2316. X    
  2317. X    /* Save parse tree and actuals on stack.
  2318. X       Must push a *copy* of formals because when we stop after an
  2319. X       error, everything on the stack will be popped and released.
  2320. X       Normally the copy is cancelled by a release in putbackargs. */
  2321. X    push(copy((value)formals));
  2322. X    push(actuals);
  2323. X    slot= 0;
  2324. X    while (still_ok && Valid(formals)) {
  2325. X        parsetree argtree= *Branch(formals, FML_TAG);
  2326. X        if (Valid(argtree)) { /* Process one parameter slot: */
  2327. X            sub_epibreer(
  2328. X                argtree,
  2329. X                *Field(actuals, slot),
  2330. X                &locals,
  2331. X                &nextlocal);
  2332. X            ++slot;
  2333. X        }
  2334. X        formals= *Branch(formals, FML_NEXT);
  2335. X    }
  2336. X    for (; nextlocal < nlocals; ++nextlocal)
  2337. X        *Field(locals, nextlocal)= Vnil;
  2338. X    push(copy(locals));
  2339. X    return locals;
  2340. X}
  2341. X
  2342. X#define NON_COMPOUND    MESS(4110, "putting non-compound in compound parameter")
  2343. X#define WRONG_LENGTH    MESS(4111, "parameter has wrong length")
  2344. X
  2345. X/* Unravel one actual parameter slot into possibly a collection of locals.
  2346. X   The parse tree has to be traversed in the same order as when
  2347. X   the numbers were assigned to local variables much earlier;
  2348. X   this is a simple left-to right tree traversal. */
  2349. X
  2350. XHidden Procedure sub_epibreer(argtree, vl, plocals, pnextlocal)
  2351. X    parsetree argtree;
  2352. X    value vl;        /* Value or location */
  2353. X    value *plocals;
  2354. X    int *pnextlocal;
  2355. X{
  2356. X    value v;
  2357. X    int k;
  2358. X    
  2359. X    switch (Nodetype(argtree)) {
  2360. X    
  2361. X    case TAG:
  2362. X        vl= n_content(vl);
  2363. X        *Field(*plocals, *pnextlocal)= mk_indirect(vl);
  2364. X        release(vl);
  2365. X        ++*pnextlocal;
  2366. X        break;
  2367. X    
  2368. X    case COLLATERAL:
  2369. X        v= *Branch(argtree, COLL_SEQ);
  2370. X        if (!Valid(v) || !Is_compound(v))
  2371. X            syserr(MESS(4112, "not a compound in sub_epibreer"));
  2372. X        if (Valid(vl) && !Is_compound(vl))
  2373. X            vl= n_content(vl);
  2374. X            /* If that isn't a simple or table-selection
  2375. X               location whose content is either Vnil or
  2376. X               a compound of the right size, we'll get an
  2377. X               error below. */
  2378. X        if (Valid(vl)) {
  2379. X            if (!Is_compound(vl))
  2380. X                interr(NON_COMPOUND);
  2381. X            else if (Nfields(vl) != Nfields(v))
  2382. X                interr(WRONG_LENGTH);
  2383. X        }
  2384. X        for (k= 0; still_ok && k < Nfields(v); ++k)
  2385. X            sub_epibreer(
  2386. X                *Field(v, k),
  2387. X                Valid(vl) ? *Field(vl, k) : Vnil,
  2388. X                plocals,
  2389. X                pnextlocal);
  2390. X        break;
  2391. X    
  2392. X    case COMPOUND:
  2393. X        sub_epibreer(
  2394. X            *Branch(argtree, COMP_FIELD),
  2395. X            vl,
  2396. X            plocals,
  2397. X            pnextlocal);
  2398. X        break;
  2399. X    
  2400. X    default:
  2401. X        syserr(MESS(4113, "bad nodetype in sub_epibreer"));
  2402. X        break;
  2403. X    
  2404. X    }
  2405. X}
  2406. X
  2407. X/* Put a value in a location, but empty it if the value is Vnil. */
  2408. X
  2409. XHidden Procedure n_put(v, l) value v; loc l; {
  2410. X    if (!Valid(v))
  2411. X        l_del(l);
  2412. X    else
  2413. X        put(v, l);
  2414. X}
  2415. X
  2416. X/* Put changed formal parameters back in the corresponding locations.
  2417. X   It is an error to put a changed value back in an expression. */
  2418. X
  2419. XHidden Procedure putbackargs(locenv) value locenv; {
  2420. X    value oldlocenv= pop();    /* Original contents of locenv */
  2421. X    value locs= pop();    /* Corresponding locations */
  2422. X    parsetree formals= (parsetree) pop();    /* Parse tree of formals */
  2423. X    
  2424. X    /* Cancel extra ref to formals caused by push(copy(formals))
  2425. X       in epibreer; this leaves enough refs so we can still use it. */
  2426. X    release(formals);
  2427. X    
  2428. X    if (locenv != oldlocenv) {
  2429. X        int slot= 0;
  2430. X        int nextlocal= 0;
  2431. X        
  2432. X        while (still_ok && Valid(formals)) {
  2433. X            parsetree argtree= *Branch(formals, FML_TAG);
  2434. X            if (Valid(argtree)) {
  2435. X                /* Process one parameter slot: */
  2436. X                sub_putback(
  2437. X                    argtree,
  2438. X                    *Field(locs, slot),
  2439. X                    locenv,
  2440. X                    &nextlocal);
  2441. X                ++slot;
  2442. X            }
  2443. X            formals= *Branch(formals, FML_NEXT);
  2444. X        }
  2445. X    }
  2446. X    
  2447. X    release(locs);
  2448. X    release(oldlocenv);
  2449. X}
  2450. X
  2451. XHidden Procedure sub_putback(argtree, lv, locenv, pnextlocal)
  2452. X    parsetree argtree;
  2453. X    /*loc-or*/value lv;
  2454. X    value locenv;
  2455. X    int *pnextlocal;
  2456. X{
  2457. X    value v;
  2458. X    int k;
  2459. X    
  2460. X    while (Nodetype(argtree) == COMPOUND)
  2461. X        argtree= *Branch(argtree, COMP_FIELD);
  2462. X    switch (Nodetype(argtree)) {
  2463. X    
  2464. X    case TAG:
  2465. X        if (*pnextlocal >= Nfields(locenv))
  2466. X            syserr(MESS(4114, "too many tags in sub_putback"));
  2467. X        v= *Field(locenv, *pnextlocal);
  2468. X        if (Changed_formal(v))
  2469. X            put_it_back(v, lv);
  2470. X        ++*pnextlocal;
  2471. X        break;
  2472. X    
  2473. X    case COLLATERAL:
  2474. X        v= *Branch(argtree, COLL_SEQ);
  2475. X        if (!Valid(v) || !Is_compound(v))
  2476. X            syserr(MESS(4115, "not a compound in sub_putback"));
  2477. X        if (Valid(lv) && Is_compound(lv)) {
  2478. X            if (Nfields(v) != Nfields(lv))
  2479. X                interr(WRONG_LENGTH);
  2480. X            for (k= 0; still_ok && k < Nfields(v); ++k)
  2481. X                sub_putback(
  2482. X                    *Field(v, k),
  2483. X                    *Field(lv, k),
  2484. X                    locenv,
  2485. X                    pnextlocal);
  2486. X        }
  2487. X        else {
  2488. X            if (collect_value(
  2489. X                    &v,
  2490. X                    v,
  2491. X                    locenv,
  2492. X                    pnextlocal))
  2493. X                put_it_back(v, lv);
  2494. X            release(v);
  2495. X        }
  2496. X        break;
  2497. X    
  2498. X    default:
  2499. X        syserr(MESS(4116, "bad node type in sub_putback"));
  2500. X    }
  2501. X}
  2502. X
  2503. X/* Construct the compound value corresponding to the compound of formal
  2504. X   parameters held in 'seq'.
  2505. X   Return Yes if any subvalue has changed.
  2506. X   It is possible that the value is to be deleted; in this case all
  2507. X   components must be Vnil.  A mixture of values and Vnil causes an
  2508. X   error. */
  2509. X
  2510. XHidden bool collect_value(pv, seq, locenv, pnextlocal)
  2511. X    value *pv;
  2512. X    value seq;
  2513. X    value locenv;
  2514. X    int *pnextlocal;
  2515. X{
  2516. X    bool changed= No;
  2517. X    int k;
  2518. X    int len= Nfields(seq);
  2519. X    int n_value= 0;
  2520. X    
  2521. X    if (!Valid(seq) || !Is_compound(seq))
  2522. X        syserr(MESS(4117, "not a compound in collect_value"));
  2523. X    *pv= mk_compound(len);
  2524. X    for (k= 0; k < len; ++k) {
  2525. X        parsetree tree= *Field(seq, k);
  2526. X        value v;
  2527. X        
  2528. X        while (Nodetype(tree) == COMPOUND)
  2529. X            tree= *Branch(tree, COMP_FIELD);
  2530. X        
  2531. X        switch (Nodetype(tree)) {
  2532. X        
  2533. X        case TAG:
  2534. X            v= copy(*Field(locenv, *pnextlocal));
  2535. X            if (Changed_formal(v))
  2536. X                changed= Yes;
  2537. X            if (Valid(v) && Is_indirect(v)) {
  2538. X                release(v);
  2539. X                v= copy(Indirect(v)->val);
  2540. X            }
  2541. X            ++*pnextlocal;
  2542. X            break;
  2543. X        
  2544. X        case COLLATERAL:
  2545. X            if (collect_value(
  2546. X                    &v,
  2547. X                    *Branch(tree, COLL_SEQ),
  2548. X                    locenv,
  2549. X                    pnextlocal))
  2550. X                changed= Yes;
  2551. X            break;
  2552. X        
  2553. X        default:
  2554. X            syserr(MESS(4118, "bad node type in collect_value"));
  2555. X        
  2556. X        }
  2557. X        *Field(*pv, k)= v;
  2558. X    }
  2559. X    
  2560. X    for (k= 0; k < len; ++k) {
  2561. X        if (Valid(*Field(*pv, k)))
  2562. X            n_value++;
  2563. X    }
  2564. X    
  2565. X    if (n_value < len && n_value > 0)
  2566. X          interr(MESS(4119, "on return, part of compound holds no value"));
  2567. X    if (n_value < len) {
  2568. X        release(*pv);
  2569. X        *pv= Vnil;
  2570. X    }
  2571. X    
  2572. X    return changed;
  2573. X}
  2574. X
  2575. X/* Put a value in something that may be a location or a value.
  2576. X   If it's a value, an error message is issued. */
  2577. X
  2578. XHidden Procedure put_it_back(v, l) value v; loc l; {
  2579. X    if (!is_location(l))
  2580. X        interr(MESS(4120, "value of expression parameter changed"));
  2581. X    if (still_ok)
  2582. X        n_put(v, l);
  2583. X}
  2584. X
  2585. XVisible Procedure x_user_command(name, actuals, def)
  2586. X value name; parsetree actuals; value def;
  2587. X{
  2588. X    how *h; parsetree u, formals; value *aa;
  2589. X    value v; int len, argcnt;
  2590. X    if (Valid(def)) {
  2591. X        if (!Is_refinement(def)) syserr(MESS(4121, "bad def in x_user_command"));
  2592. X        call(C_refcmd, *Branch(Refinement(def)->rp, REF_START));
  2593. X        return;
  2594. X    }
  2595. X    if (!is_unit(name, Cmd, &aa)) {
  2596. X        interrV(MESS(4122, "You haven't told me HOW TO %s"), name);
  2597. X        return;
  2598. X    }
  2599. X    u= (h= How_to(*aa))->unit;
  2600. X    if (h->unparsed) fix_nodes(&u, &h->code);
  2601. X    if (!still_ok) { rem_unit(u); return; }
  2602. X    h->unparsed= No;
  2603. X    formals= *Branch(u, HOW_FORMALS);
  2604. X    len= intval(*Branch(u, HOW_NLOCALS));
  2605. X    argcnt= 0;
  2606. X    while (Valid(actuals)) { /* Count actuals */
  2607. X        if (Valid(*Branch(actuals, ACT_EXPR)))
  2608. X            ++argcnt;
  2609. X        actuals= *Branch(actuals, ACT_NEXT);
  2610. X    } /* Could just as well count formals... */
  2611. X    
  2612. X    v= epibreer(formals, argcnt, len);
  2613. X    
  2614. X    call(C_howto, h->code);
  2615. X    
  2616. X    curnv->tab= v; 
  2617. X    release(uname); uname= permkey(name, Cmd);
  2618. X    cntxt= In_unit;
  2619. X}
  2620. X
  2621. XVisible Procedure endsta() {
  2622. X    if (st_base != Pnil) {
  2623. X        freemem((ptr) st_base);
  2624. X        st_base= Pnil;        
  2625. X    }
  2626. X}
  2627. END_OF_FILE
  2628.   if test 18967 -ne `wc -c <'abc/bint3/i3sta.c'`; then
  2629.     echo shar: \"'abc/bint3/i3sta.c'\" unpacked with wrong size!
  2630.   fi
  2631.   # end of 'abc/bint3/i3sta.c'
  2632. fi
  2633. echo shar: End of archive 8 \(of 25\).
  2634. cp /dev/null ark8isdone
  2635. MISSING=""
  2636. 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 ; do
  2637.     if test ! -f ark${I}isdone ; then
  2638.     MISSING="${MISSING} ${I}"
  2639.     fi
  2640. done
  2641. if test "${MISSING}" = "" ; then
  2642.     echo You have unpacked all 25 archives.
  2643.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2644. else
  2645.     echo You still must unpack the following archives:
  2646.     echo "        " ${MISSING}
  2647. fi
  2648. exit 0 # Just in case...
  2649.