|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
2: static char rcsid[] = "$Header: que2.c,v 2.3 84/07/23 13:02:38 guido Exp $";
3:
4: /*
5: * B editor -- Manipulate queues of nodes, higher levels.
6: */
7:
8: #include <ctype.h>
9:
10: #include "b.h"
11: #include "feat.h"
12: #include "bobj.h"
13: #include "node.h"
14: #include "supr.h"
15: #include "queu.h"
16: #include "gram.h"
17: #include "tabl.h"
18:
19:
20: extern bool lefttorite;
21: /* Set by edit() to signal we parse purely left-to-right */
22: extern bool dflag; /* Debug mode even if NDEBUG on */
23:
24:
25: /*
26: * Insert a queue of nodes at the focus
27: * (which had better be some kind of a hole).
28: * The nodes may also be a text, in which case the individual characters
29: * are inserted.
30: * Extensive changes to the parse tree may occur, and the node may be
31: * broken up in its constituent parts (texts and other nodes) which
32: * are then inserted individually.
33: */
34:
35: Visible bool
36: ins_queue(ep, pq, pq2)
37: register environ *ep;
38: register queue *pq;
39: register queue *pq2;
40: {
41: register bool ok = Yes;
42: register node n;
43: register queue oldq2;
44: environ saveenv;
45: int oldindentation = focindent(ep);
46: int indentation = oldindentation;
47:
48: leftvhole(ep);
49: while (ok && !emptyqueue(*pq)) {
50: n = queuebehead(pq);
51: if (Type(n) == Tex) {
52: ok = ins_string(ep, Str((value) n), pq2, 0);
53: switch (Str((value) n)[Length((value) n) - 1]) { /* Last char */
54: case '\t':
55: ++indentation;
56: break;
57: case '\b':
58: --indentation;
59: break;
60: case '\n':
61: while (focindent(ep) > indentation) {
62: if (!ins_newline(ep))
63: break;
64: }
65: break;
66: }
67: }
68: else {
69: Ecopy(*ep, saveenv);
70: oldq2 = qcopy(*pq2);
71: if (!ins_node(&saveenv, n, pq2)) {
72: Erelease(saveenv);
73: qrelease(*pq2);
74: *pq2 = oldq2;
75: if (symbol(n) == Hole)
76: ok = ins_string(ep, "?", pq2, 0);
77: else
78: splitnode(n, pq);
79: }
80: else {
81: Erelease(*ep);
82: Emove(saveenv, *ep);
83: qrelease(oldq2);
84: }
85: }
86: noderelease(n);
87: }
88: if (!ok)
89: qshow(*pq, "ins_queue");
90: qrelease(*pq);
91: for (indentation = focindent(ep);
92: indentation > oldindentation; --indentation)
93: stringtoqueue("\b", pq2); /* Pass on indentation to outer level */
94: return ok;
95: }
96:
97:
98: /*
99: * Subroutine to insert a queue to the right of the focus
100: * without affecting the focus position.
101: */
102:
103: Visible bool
104: app_queue(ep, pq)
105: environ *ep;
106: queue *pq;
107: {
108: int where;
109: static int markbit = 1; /* To properly handle recursive calls */
110:
111: if (emptyqueue(*pq))
112: return Yes;
113: where = focoffset(ep);
114: markbit <<= 1;
115: markpath(&ep->focus, markbit);
116: if (!ins_queue(ep, pq, pq)) {
117: markbit >>= 1;
118: return No;
119: }
120: firstmarked(&ep->focus, markbit) || Abort();
121: unmkpath(&ep->focus, markbit);
122: markbit >>= 1;
123: ep->spflag = No;
124: fixfocus(ep, where);
125: return Yes;
126: }
127:
128:
129: /*
130: * Advance to next thing after current position.
131: */
132:
133: Visible bool
134: move_on(ep)
135: register environ *ep;
136: {
137: register node n;
138: register string *rp;
139: register int sym;
140: register int ich = ichild(ep->focus);
141:
142: if (!up(&ep->focus))
143: return No;
144: higher(ep);
145: n = tree(ep->focus);
146: rp = noderepr(n);
147: if (Fw_positive(rp[ich])) {
148: ep->mode = FHOLE;
149: ep->s1 = 2*ich + 1;
150: ep->s2 = 0;
151: if (ep->spflag) {
152: ep->spflag = No;
153: if (rp[ich][0] == ' ') {
154: ++ep->s2;
155: if (fwidth(rp[ich]) > 1)
156: return Yes;
157: }
158: else
159: return Yes;
160: }
161: else
162: return Yes;
163: }
164: if (ich < nchildren(n)) {
165: s_downi(ep, ich+1);
166: sym = symbol(tree(ep->focus));
167: if (sym == Hole || sym == Optional)
168: ep->mode = WHOLE;
169: else
170: ep->mode = ATBEGIN;
171: return Yes;
172: }
173: ep->mode = ATEND;
174: return Yes;
175: }
176:
177:
178: /*
179: * Like move_on but moves through fixed texts, skipping only spaces
180: * and empty strings.
181: * <<<<< This code is a dinosaur and should be revised. >>>>>
182: */
183:
184: Visible bool
185: fix_move(ep)
186: register environ *ep;
187: {
188: register int ich;
189: register int i;
190: register string *rp;
191: register string cp;
192:
193: Assert(ep->mode == FHOLE);
194:
195: ich = ep->s1/2;
196: rp = noderepr(tree(ep->focus));
197: cp = rp[ich];
198: if (cp) {
199: i = ep->s2;
200: Assert(i <= Fwidth(cp));
201: if (cp[i] == ' ') {
202: do {
203: ++i;
204: } while (cp[i] == ' ');
205: }
206: if (cp[i] == '\b' || cp[i] == '\t') {
207: ++i;
208: Assert(!cp[i]);
209: }
210: else if (cp[i]) {
211: if (i == ep->s2)
212: return No;
213: ep->s2 = i;
214: return Yes;
215: }
216: }
217:
218: if (ich >= nchildren(tree(ep->focus)))
219: ep->mode = ATEND;
220: else {
221: s_downi(ep, ich+1);
222: if (symbol(tree(ep->focus)) == Hole
223: || symbol(tree(ep->focus)) == Optional)
224: ep->mode = WHOLE;
225: else
226: ep->mode = ATBEGIN;
227: }
228: return Yes;
229: }
230:
231:
232: /*
233: * Insert a node in the parse tree.
234: */
235:
236: Hidden bool
237: ins_node(ep, n, pq)
238: register environ *ep;
239: register node n;
240: register queue *pq;
241: {
242: register int sym;
243: register node nn;
244: register markbits x;
245: string *rp;
246:
247: if (symbol(n) == Optional)
248: return Yes;
249:
250: for (;;) {
251: switch (ep->mode) {
252:
253: case FHOLE:
254: if (ep->s2 < lenitem(ep) || !fix_move(ep))
255: return No;
256: continue;
257:
258: case VHOLE:
259: if (ep->s2 < lenitem(ep) || !move_on(ep))
260: return No;
261: continue;
262:
263: case ATBEGIN:
264: sym = symbol(tree(ep->focus));
265: if (sym == Optional || sym == Hole) {
266: ep->mode = WHOLE;
267: continue;
268: }
269: x = marks(tree(ep->focus));
270: if (joinnodes(&ep->focus, n, tree(ep->focus), No)) {
271: if (x) {
272: s_downi(ep, 2);
273: markpath(&ep->focus, x);
274: s_up(ep);
275: }
276: s_down(ep);
277: ep->mode = ATEND;
278: leftvhole(ep);
279: return Yes;
280: }
281: nn = tree(ep->focus);
282: rp = noderepr(nn);
283: if (nchildren(nn) >= 1 && Fw_zero(rp[0])) {
284: sym = symbol(firstchild(nn));
285: if (sym == Hole || sym == Optional) {
286: s_down(ep);
287: if (fitnode(&ep->focus, n)) {
288: ep->mode = ATEND;
289: leftvhole(ep);
290: return Yes;
291: }
292: s_up(ep);
293: }
294: }
295: nn = nodecopy(nn);
296: if (!fitnode(&ep->focus, n)) {
297: addtoqueue(pq, nn);
298: noderelease(nn);
299: delfocus(&ep->focus);
300: ep->mode = WHOLE;
301: continue;
302: }
303: if (downrite(&ep->focus)) {
304: if (Type(tree(ep->focus)) != Tex) {
305: sym = symbol(tree(ep->focus));
306: if (sym == Hole || sym == Optional) {
307: if (fitnode(&ep->focus, nn)) {
308: noderelease(nn);
309: nn = Nnil;
310: }
311: }
312: }
313: else
314: up(&ep->focus);
315: }
316: if (nn) {
317: addtoqueue(pq, nn);
318: noderelease(nn);
319: }
320: ep->mode = ATEND;
321: leftvhole(ep);
322: return Yes;
323:
324: case WHOLE:
325: sym = symbol(tree(ep->focus));
326: Assert(sym == Optional || sym == Hole);
327: do {
328: higher(ep); /* Only for second time around */
329: if (fitnode(&ep->focus, n)) {
330: ep->mode = ATEND;
331: leftvhole(ep);
332: return Yes;
333: }
334: } while (resttoqueue(&ep->focus, pq));
335: ep->mode = ATEND;
336: /* Fall through */
337: case ATEND:
338: do {
339: higher(ep); /* Only for second time around */
340: if (joinnodes(&ep->focus, tree(ep->focus), n, ep->spflag)) {
341: ep->spflag = No;
342: leftvhole(ep);
343: return Yes;
344: }
345: } while (resttoqueue(&ep->focus, pq)
346: || move_on(ep) && ep->mode == ATEND);
347: return No;
348:
349: default:
350: return No;
351:
352: }
353: }
354: }
355:
356:
357: /*
358: * Insert a string in the parse tree.
359: */
360:
361: #define NEXT (++str, alt_c = 0)
362:
363: Visible bool
364: ins_string(ep, str, pq, alt_c)
365: register environ *ep;
366: /*auto*/ string str;
367: register queue *pq;
368: int alt_c;
369: {
370: register node nn;
371: auto value v;
372: char buf[1024];
373: register string repr;
374: string oldstr;
375: register int sym;
376: register int len;
377: bool interactive = alt_c != 0;
378:
379: if (alt_c < 0)
380: alt_c = 0;
381: while (*str) {
382: switch (*str) {
383:
384: case '\n':
385: if (!ins_newline(ep))
386: return No;
387: /* Fall through */
388: case '\t':
389: case '\b':
390: NEXT;
391: continue;
392:
393: }
394: switch (ep->mode) {
395:
396: case ATBEGIN:
397: nn = tree(ep->focus);
398: if (Type(nn) == Tex) {
399: ep->s1 = 2*ichild(ep->focus);
400: ep->s2 = 0;
401: ep->mode = VHOLE;
402: s_up(ep);
403: continue;
404: }
405: sym = symbol(nn);
406: if (sym != Optional && sym != Hole) {
407: if (fwidth(noderepr(nn)[0]) == 0) {
408: if (down(&ep->focus))
409: break;
410: }
411: addtoqueue(pq, nn);
412: delfocus(&ep->focus);
413: }
414: ep->mode = WHOLE;
415: /* Fall through */
416: case WHOLE:
417: nn = tree(ep->focus);
418: sym = symbol(nn);
419: Assert(sym == Hole || sym == Optional);
420: while ((len = fitstring(&ep->focus, str, alt_c)) == 0) {
421: if (sym == Optional) {
422: if (!move_on(ep)) {
423: if (*str == ' ')
424: NEXT;
425: else
426: return No;
427: }
428: break;
429: }
430: if (!interactive && *str == '?') {
431: NEXT;
432: ep->mode = ATEND;
433: break;
434: }
435: if (resttoqueue(&ep->focus, pq))
436: higher(ep);
437: else if (spacefix(ep))
438: break;
439: else if (*str == ' ') {
440: NEXT;
441: break;
442: }
443: else if (interactive)
444: return No;
445: else {
446: ep->mode = ATEND;
447: break;
448: }
449: }
450: if (len > 0) {
451: str += len;
452: alt_c = 0;
453: fixfocus(ep, len);
454: }
455: break;
456:
457: case ATEND:
458: if (add_string(ep, &str, alt_c)) {
459: alt_c = 0;
460: break;
461: }
462: len = joinstring(&ep->focus, str, ep->spflag,
463: alt_c ? alt_c : interactive ? -1 : 0, Yes);
464: if (len > 0) {
465: s_downi(ep, 2);
466: ep->spflag = No;
467: fixfocus(ep, len);
468: }
469: else {
470: if (resttoqueue(&ep->focus, pq)) {
471: higher(ep);
472: break;
473: }
474: if (move_on(ep))
475: break;
476: if (*str == ' ') {
477: NEXT;
478: break;
479: }
480: return No;
481: }
482: str += len;
483: alt_c = 0;
484: break;
485:
486: case FHOLE:
487: nn = tree(ep->focus);
488: repr = noderepr(nn)[ep->s1/2];
489: if (ep->s2 >= fwidth(repr)
490: && (ep->s2 <= 0 || ep->spflag || !isalpha(repr[0])
491: || repr[ep->s2-1] == ' ')) { /* At end */
492: if (ep->s1/2 < nchildren(nn)) {
493: s_downi(ep, ep->s1/2 + 1);
494: ep->mode = ATBEGIN; /* Of next child */
495: }
496: else
497: ep->mode = ATEND;
498: break;
499: }
500: if ((*str == ':' || *str == ' ') && *str == repr[ep->s2]) {
501: /*****
502: * Quick hack for insertion of test-suites and refinements:
503: *****/
504: ++ep->s2;
505: NEXT;
506: continue;
507: }
508: if (!lefttorite)
509: nosuggtoqueue(ep, pq);
510: oldstr = str;
511: if (resuggest(ep, &str, alt_c) || soften(ep, &str, alt_c)) {
512: if (str > oldstr)
513: alt_c = 0;
514: continue;
515: }
516: if (fix_move(ep))
517: continue;
518: return No;
519:
520: case VHOLE:
521: Assert(!(ep->s1&1));
522: nn = tree(ep->focus);
523: #ifdef USERSUGG
524: if (symbol(nn) == Suggestion) {
525: if (newsugg(ep, &str, alt_c))
526: alt_c = 0;
527: else
528: killsugg(ep);
529: continue;
530: }
531: #endif USERSUGG
532: s_downi(ep, ep->s1/2);
533: v = copy((value) tree(ep->focus));
534: len = 0;
535: if (!ep->spflag) {
536: for (; len < sizeof buf - 1 && str[len]
537: && mayinsert(nn, ep->s1/2, !!(ep->s2 + len),
538: str[len]);
539: ++len) {
540: buf[len] = str[len];
541: }
542: if (len <= 0 && alt_c
543: && mayinsert(nn, ep->s1/2, !!(ep->s2 + len), alt_c)) {
544: buf[0] = alt_c;
545: len = 1;
546: }
547: }
548: if (len > 0) { /* Effectuate change */
549: str += len;
550: alt_c = 0;
551: Assert(Type(v) == Tex);
552: buf[len] = 0;
553: putintrim(&v, ep->s2, Length(v) - ep->s2, buf);
554: replace(&ep->focus, (node) v);
555: s_up(ep);
556: ep->spflag = No;
557: ep->s2 += len;
558: }
559: else { /* Nothing inserted */
560: if (ep->s2 == 0) { /* Whole string rejected */
561: addtoqueue(pq, (node)v);
562: release(v);
563: s_up(ep);
564: delfocus(&ep->focus);
565: ep->mode = WHOLE;
566: break;
567: }
568: if (ep->s2 < Length(v)) {
569: addstringtoqueue(pq, Str(v) + ep->s2);
570: putintrim(&v, ep->s2, 0, "");
571: replace(&ep->focus, (node) v);
572: }
573: else
574: release(v);
575: move_on(ep) || Abort(); /* ==> up, cancelling s_downi! */
576: }
577: break;
578:
579: default:
580: Abort();
581:
582: }
583: }
584:
585: return Yes;
586: }
587:
588:
589: /*
590: * See if two nodes can be joined in a hole.
591: * 'Spflag' indicates whether a space must be present between the nodes
592: * (required or forbidden).
593: * Either of n1, n2 may actually be the current contents of the hole.
594: */
595:
596: Hidden bool
597: joinnodes(pp, n1, n2, spflag)
598: path *pp;
599: node n1;
600: node n2;
601: bool spflag;
602: {
603: path pa = parent(*pp);
604: int sympa = pa ? symbol(tree(pa)) : Rootsymbol;
605: struct table *tp = &table[sympa];
606: struct classinfo *ci = tp->r_class[ichild(*pp) - 1];
607: classptr cp = ci->c_join;
608: int sym1 = symbol(n1);
609: int sym2 = symbol(n2);
610: int symcp;
611: int symfound = -1;
612:
613: if (!cp)
614: return No;
615: for (; *cp; cp += 2) {
616: if (cp[0] != spflag + 1)
617: continue;
618: symcp = cp[1];
619: tp = &table[symcp];
620: if (isinclass(sym1, tp->r_class[0])
621: && isinclass(sym2, tp->r_class[1])) {
622: symfound = symcp;
623: break;
624: }
625: }
626:
627: if (symfound < 0)
628: return No;
629: n1 = nodecopy(n1);
630: n2 = nodecopy(n2); /* 'Cause one of them may overlap tree(*pp) */
631: replace(pp, table[symfound].r_node);
632: down(pp) || Abort();
633: replace(pp, n1);
634: rite(pp) || Abort();
635: replace(pp, n2);
636: up(pp) || Abort();
637: return Yes;
638: }
639:
640:
641: /*
642: * Try to join a node (implicit as tree(*pp)) with some text.
643: * That is, try to replace the node by one with it as first child,
644: * (some of) the text as second child, and nothing or a space in between.
645: *
646: * 'Spflag' indicates whether a space is desirable between the nodes
647: * (but if No it is only used as advice).
648: *
649: * Returns the number of characters consumed from str.
650: */
651:
652: Visible int
653: joinstring(pp, str, spflag, alt_c, mayindent)
654: path *pp;
655: register string str;
656: register bool spflag;
657: int alt_c;
658: bool mayindent;
659: {
660: register struct table *tp;
661: path pa = parent(*pp);
662: node n1;
663: struct classinfo *ci;
664: register classptr cp;
665: int sympa = pa ? symbol(tree(pa)) : Rootsymbol;
666: register int sym1;
667: register int symcp;
668: int symfound;
669: int len;
670: char buf[2];
671: bool interactive = alt_c != 0;
672:
673: if (alt_c < 0)
674: alt_c = 0;
675: ci = table[sympa].r_class[ichild(*pp) - 1];
676: Assert(ci);
677: cp = ci->c_join;
678: if (!cp)
679: return 0;
680:
681: n1 = tree(*pp);
682: sym1 = symbol(n1);
683: symfound = -1;
684: for (; *cp; cp += 2) {
685: if (cp[0] < spflag + 1)
686: continue;
687: symcp = cp[1];
688: tp = &table[symcp];
689: if (!mayindent && tp->r_repr[1] && index(tp->r_repr[1], '\t'))
690: continue;
691: if (isinclass(sym1, tp->r_class[0])
692: && ((canfitchar(str[0], tp->r_class[1]))
693: || str[0] == '?' && !interactive)) {
694: if (cp[0] == spflag + 1) {
695: symfound = symcp;
696: break;
697: }
698: if (symfound < 0)
699: symfound = symcp;
700: }
701: }
702:
703: if (symfound < 0) { /* 1-level recursion */
704: if (!alt_c)
705: return 0;
706: buf[0] = alt_c;
707: buf[1] = 0;
708: return joinstring(pp, buf, spflag, 0, mayindent);
709: }
710: n1 = nodecopy(n1); /* 'Cause it overlaps tree(*pp) */
711: replace(pp, table[symfound].r_node);
712: down(pp) || Abort();
713: replace(pp, n1);
714: rite(pp) || Abort();
715: len = fitstring(pp, str, 0);
716: if (len == 0 && str[0] == '?')
717: len = 1;
718: Assert(len > 0); /* Disagreement between canfitchar and fitstring */
719: up(pp) || Abort();
720: return len;
721: }
722:
723:
724: /*
725: * Similar to joinstring, but now the string must match the delimiter
726: * rather than being acceptable as second child.
727: * (Interface has changed to resemble resuggest/soften.)
728: */
729:
730: Hidden bool
731: add_string(ep, pstr, alt_c)
732: environ *ep;
733: string *pstr;
734: int alt_c; /* Yet unused */
735: {
736: register struct table *tp;
737: path pa = parent(ep->focus);
738: node n1;
739: struct classinfo *ci;
740: register classptr cp;
741: int sympa = pa ? symbol(tree(pa)) : Rootsymbol;
742: register int sym1;
743: register int symcp;
744: register int c;
745:
746: ci = table[sympa].r_class[ichild(ep->focus) - 1];
747: Assert(ci);
748: cp = ci->c_append;
749: if (!cp)
750: return No;
751: n1 = tree(ep->focus);
752: sym1 = symbol(n1);
753: c = **pstr;
754: for (; *cp; cp += 2) {
755: if ((*cp&0177) != c)
756: continue;
757: symcp = cp[1];
758: tp = &table[symcp];
759: if (isinclass(sym1, tp->r_class[0]))
760: break;
761: }
762: if (!*cp)
763: return No;
764: ++*pstr;
765: if (c == ' ') {
766: ep->spflag = Yes;
767: return Yes;
768: }
769: n1 = nodecopy(n1); /* 'Cause it overlaps tree(ep->focus) */
770: replace(&ep->focus, table[symcp].r_node);
771: s_down(ep);
772: replace(&ep->focus, n1);
773: s_up(ep);
774: ep->mode = FHOLE;
775: ep->s1 = 3;
776: ep->s2 = (*cp&0200) ? 2 : 1;
777: ep->spflag = No;
778: return Yes;
779: }
780:
781:
782: /*
783: * See whether a character may start a new node in a hole with given class.
784: */
785:
786: Visible bool
787: canfitchar(c, ci)
788: int c;
789: struct classinfo *ci;
790: {
791: register classptr cp;
792: register int code = Code(c);
793:
794: Assert(ci);
795: cp = ci->c_insert;
796: Assert(cp);
797: for (; *cp; cp += 2) {
798: if (cp[0] == code)
799: return Yes;
800: }
801: return No;
802: }
803:
804:
805: /*
806: * Debug routine to print a queue.
807: */
808:
809: Visible Procedure
810: qshow(q, where)
811: queue q;
812: string where;
813: {
814: #ifndef NDEBUG
815: node n;
816: char buf[256];
817: string cp;
818: string sp;
819:
820: sprintf(buf, "%s:", where);
821: cp = buf + strlen(buf);
822: for (;q; q = q->q_link) {
823: n = q->q_data;
824: *cp++ = ' ';
825: if (Type(n) == Tex) {
826: *cp++ = '"';
827: for (sp = Str((value) n); *sp; ++sp) {
828: if (isprint(*sp) || *sp == ' ') {
829: *cp++ = *sp;
830: if (*sp == '"')
831: *cp++ = *sp;
832: }
833: else {
834: sprintf(cp, "\\%03o", *sp&0377);
835: cp += 4;
836: }
837: }
838: *cp++ = '"';
839: }
840: else {
841: strncpy(cp, table[symbol(n)].r_name, 80);
842: cp += strlen(cp);
843: }
844: if (cp >= buf+80) {
845: strcpy(buf+76, "...");
846: break;
847: }
848: }
849: *cp = 0;
850: debug(buf);
851: #endif NDEBUG
852: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.