|
|
1.1 root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2:
3: /*
4: $Header: b1tlt.c,v 1.4 85/08/22 16:53:20 timo Exp $
5: */
6:
7: /* generic routines for B texts, lists and tables */
8:
9: #include "b.h"
10: #include "b0fea.h"
11: #include "b1obj.h"
12: #ifndef INTEGRATION
13: #include "b0con.h"
14: #include "b1btr.h"
15: #include "b1val.h"
16: #endif
17: #include "b1tlt.h"
18: #include "b3err.h"
19:
20: #ifndef INTEGRATION
21:
22: /* From b1lta.c */
23: int l2size();
24: value l2min(), l2max();
25:
26: Visible value mk_elt() { /* {}, internal only */
27: value e = grab_tlt(ELT, Lt);
28: Root(e) = Bnil;
29: return e;
30: }
31:
32: Visible bool empty(v) value v; { /* #v=0, internal only */
33: switch (Type(v)) {
34: case ELT:
35: case Lis:
36: case Tex:
37: case Tab:
38: return Root(v) EQ Bnil;
39: default:
40: return No;
41: /* Some routines must test empty(t) end return an error
42: message if it fails, before testing Type(t).
43: In this way, they won't give the wrong error message. */
44: }
45: }
46:
47: /* return size of (number of items in) dependent tree */
48:
49: Hidden value treesize(pnode) btreeptr pnode; {
50: int psize;
51: value vsize, childsize, u;
52: intlet l;
53: psize = Size(pnode);
54: if (psize EQ Bigsize) {
55: switch (Flag(pnode)) {
56: case Inner:
57: vsize = mk_integer((int) Lim(pnode));
58: for (l = 0; l <= Lim(pnode); l++) {
59: childsize = treesize(Ptr(pnode, l));
60: u = vsize;
61: vsize = sum(vsize, childsize);
62: release(u);
63: release(childsize);
64: }
65: break;
66: case Irange:
67: u = diff(Upbval(pnode), Lwbval(pnode));
68: vsize = sum(u, one);
69: release(u);
70: break;
71: case Bottom:
72: case Crange:
73: syserr(MESS(1700, "Bigsize in Bottom or Crange"));
74: }
75: return(vsize);
76: }
77: return mk_integer(psize);
78: }
79:
80: Visible value size(t) value t; { /* #t */
81: int tsize;
82: switch (Type(t)) {
83: case ELT:
84: case Lis:
85: case Tex:
86: case Tab:
87: tsize = Tltsize(t);
88: if (tsize EQ Bigsize) return treesize(Root(t));
89: return mk_integer(tsize);
90: default:
91: reqerr(MESS(1701, "in #t, t is not a text, list or table"));
92: return zero;
93: }
94: }
95:
96: Visible value th_of(num, v) value num, v; { /* num th'of v */
97: value m= Vnil;
98: if (!Is_tlt(v))
99: error(MESS(1702, "in n th'of t, t is not a text, list or table"));
100: else if (!Is_number(num))
101: error(MESS(1703, "in n th'of t, n is not a number"));
102: else if (empty(v))
103: error(MESS(1704, "in n th'of t, t is empty"));
104: else if (numcomp(num, one) < 0)
105: error(MESS(1705, "in n th'of t, n is < 1"));
106: else {
107: /*RANGES?*/
108: m= thof(intval(num), v);
109: if (m == Vnil && still_ok)
110: error(MESS(1706, "in n th'of t, n exceeds #t"));
111: }
112: return m;
113: }
114:
115: /*
116: * 'Walktree' handles functions on texts and associates of tables.
117: * The actual function performed is determined by the 'visit' function.
118: * The tree is walked (possibly recursively) and all items are visited.
119: * The return value of walktree() and visit() is used to determine whether
120: * the walk should continue (Yes == continue, No == stop now).
121: * Global variables are used to communicate the result, and the parameters
122: * of the function. The naming convention is according to "e func t".
123: */
124:
125: Hidden intlet tt; /* type of walked value t */
126: Hidden intlet wt; /* width of items in walked value t */
127: Hidden value ve; /* value of e, if func is dyadic */
128: Hidden char ce; /* C char in e, if t is a text */
129:
130: Hidden int count; /* result of size2 */
131: Hidden bool found; /* result for in */
132: Hidden intlet m_char; /* result for min/max on texts */
133: Hidden value m_val; /* result for min/max on tables */
134:
135: #define Lowchar (-Maxintlet) /* -infinity for characters */
136: #define Highchar (Maxintlet) /* +infinity */
137:
138: Hidden bool walktree(p, visit) btreeptr p; bool (*visit)(); {
139: intlet l;
140:
141: if (p EQ Bnil) return Yes; /* i.e., not found (used by in() !) */
142: for (l=0; l < Lim(p); l++) {
143: switch (Flag(p)) {
144: case Inner:
145: if (!walktree(Ptr(p, l), visit) || !still_ok)
146: return No;
147: if (!(*visit)(Piitm(p, l, wt)) || !still_ok)
148: return No;
149: break;
150: case Bottom:
151: if (!(*visit)(Pbitm(p, l, wt)) || !still_ok)
152: return No;
153: }
154: }
155: return Flag(p) EQ Bottom || walktree(Ptr(p, l), visit);
156: }
157:
158: /* Common code for min/max-1/2, size2, in. */
159:
160: Hidden Procedure tlt_func(e, t, where, li_func, te_visit, ta_visit)
161: value e, t; /* [e] func t */
162: string where; /* "in [e] func_name t" */
163: value (*li_func)(); /* func for lists */
164: bool (*te_visit)(), (*ta_visit)(); /* 'visit' for walktree */
165: {
166: m_val = Vnil;
167: if (empty(t)) {
168: error3(MESSMAKE(where), Vnil, MESS(1707, ", t is empty"));
169: return;
170: }
171: wt = Itemwidth(Itemtype(t));
172: tt = Type(t);
173: switch (tt) {
174: case Lis:
175: m_val = (*li_func)(e, t);
176: break;
177: case Tex:
178: if (e NE Vnil) {
179: if (!Character(e)) {
180: error3(MESSMAKE(where), Vnil,
181: MESS(1708, ", t is a text, but e is not a character"));
182: return;
183: }
184: ce = Bchar(Root(e), 0);
185: }
186: found = !walktree(Root(t), te_visit);
187: if (m_char NE Lowchar && m_char NE Highchar)
188: m_val = mkchar(m_char);
189: break;
190: case Tab:
191: ve = e;
192: found = !walktree(Root(t), ta_visit);
193: break;
194: default:
195: error3(MESSMAKE(where), Vnil,
196: MESS(1709, ", t is not a text list or table"));
197: }
198: }
199:
200: Hidden value li2size(e, t) value e, t; {
201: count = l2size(e, t);
202: return Vnil;
203: }
204:
205: Hidden bool te2size(pitm) itemptr pitm; {
206: if (ce EQ Charval(pitm))
207: count++;
208: return Yes;
209: }
210:
211: Hidden bool ta2size(pitm) itemptr pitm; {
212: if (compare(ve, Ascval(pitm)) EQ 0)
213: count++;
214: return Yes;
215: }
216:
217: Visible value size2(e, t) value e, t; { /* e#t */
218: if (empty(t)) /* Must check here because tlt_func would complain */
219: return copy(zero);
220: m_char = Lowchar;
221: count = 0;
222: tlt_func(e, t, "in e#t", li2size, te2size, ta2size);
223: return mk_integer(count);
224: }
225:
226: Hidden value li_in(e, t) value e, t; {
227: found = in_keys(e, t);
228: return Vnil;
229: }
230:
231: Hidden bool te_in(pitm) itemptr pitm; {
232: return Charval(pitm) NE ce;
233: }
234:
235: Hidden bool ta_in(pitm) itemptr pitm; {
236: return compare(ve, Ascval(pitm)) NE 0;
237: }
238:
239: Visible bool in(e, t) value e, t; {
240: if (empty(t)) /* Must check here because tlt_func would complain */
241: return No;
242: m_char = Lowchar;
243: found = No;
244: tlt_func(e, t, "in the test e in t", li_in, te_in, ta_in);
245: return found;
246: }
247:
248: Hidden value li_min(e, t) value e, t; {
249: return th_of(one, t);
250: }
251:
252: Hidden bool te_min(pitm) itemptr pitm; {
253: if (m_char > Charval(pitm))
254: m_char = Charval(pitm);
255: return Yes;
256: }
257:
258: Hidden bool ta_min(pitm) itemptr pitm; {
259: if (m_val EQ Vnil || compare(m_val, Ascval(pitm)) > 0) {
260: release(m_val);
261: m_val = copy(Ascval(pitm));
262: }
263: return Yes;
264: }
265:
266: Visible value min1(t) value t; {
267: m_char = Highchar;
268: tlt_func(Vnil, t, "in min t", li_min, te_min, ta_min);
269: return m_val;
270: }
271:
272: Hidden value li_max(e, t) value e, t; {
273: value v= size(t);
274: m_val = th_of(v, t);
275: release(v);
276: return m_val;
277: }
278:
279: Hidden bool te_max(pitm) itemptr pitm; {
280: if (m_char < Charval(pitm))
281: m_char = Charval(pitm);
282: return Yes;
283: }
284:
285: Hidden bool ta_max(pitm) itemptr pitm; {
286: if (m_val EQ Vnil || compare(Ascval(pitm), m_val) > 0) {
287: release(m_val);
288: m_val = copy(Ascval(pitm));
289: }
290: return Yes;
291: }
292:
293: Visible value max1(t) value t; {
294: m_char = Lowchar;
295: tlt_func(Vnil, t, "in max t", li_max, te_max, ta_max);
296: return m_val;
297: }
298:
299: Hidden bool te2min(pitm) itemptr pitm; {
300: if (m_char > Charval(pitm) && Charval(pitm) > ce) {
301: m_char = Charval(pitm);
302: }
303: return Yes;
304: }
305:
306: Hidden bool ta2min(pitm) itemptr pitm; {
307: if (compare(Ascval(pitm), ve) > 0
308: &&
309: (m_val EQ Vnil || compare(m_val, Ascval(pitm)) > 0)) {
310: release(m_val);
311: m_val = copy(Ascval(pitm));
312: }
313: return Yes;
314: }
315:
316: Visible value min2(e, t) value e, t; {
317: m_char = Highchar;
318: tlt_func(e, t, "in e min t", l2min, te2min, ta2min);
319: if (m_val EQ Vnil && still_ok)
320: reqerr(MESS(1710, "in e min t, no element of t exceeds e"));
321: return m_val;
322: }
323:
324: /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
325:
326: Hidden bool te2max(pitm) itemptr pitm; {
327: if (ce > Charval(pitm) && Charval(pitm) > m_char) {
328: m_char = Charval(pitm);
329: }
330: return Yes;
331: }
332:
333: Hidden bool ta2max(pitm) itemptr pitm; {
334: if (compare(ve, Ascval(pitm)) > 0
335: &&
336: (m_val EQ Vnil || compare(Ascval(pitm), m_val) > 0)) {
337: release(m_val);
338: m_val = copy(Ascval(pitm));
339: }
340: return Yes;
341: }
342:
343: Visible value max2(e, t) value e, t; {
344: m_char = Lowchar;
345: tlt_func(e, t, "in e max t", l2max, te2max, ta2max);
346: if (m_val EQ Vnil && still_ok)
347: reqerr(MESS(1711, "in e max t, no element of t is less than e"));
348: return m_val;
349: }
350:
351: #else INTEGRATION
352:
353: Visible value mk_elt() { return grab_elt(); }
354:
355: Visible value size(x) value x; { /* monadic # operator */
356: if (!Is_tlt(x))
357: error(MESS(1712, "in #t, t is not a text, list or table"));
358: return mk_integer((int) Length(x));
359: }
360:
361: #define Lisent(tp,k) (*(tp+(k)))
362:
363: Visible value size2(v, t) value v, t; { /* Dyadic # operator */
364: intlet len= Length(t), n= 0, k; value *tp= Ats(t);
365: if (!Is_tlt(t)) {
366: error(MESS(1713, "in e#t, t is not a text, list or table"));
367: return mk_integer((int) n);
368: }
369: switch (Type(t)) {
370: case Tex:
371: {string cp= (string)tp; char c;
372: if (Type(v) != Tex)
373: error(MESS(1714, "in e#t, t is a text but e is not"));
374: if (Length(v) != 1)
375: error(MESS(1715, "in e#t, e is a text but not a character"));
376: c= *Str(v);
377: Overall if (*cp++ == c) n++;
378: } break;
379: case ELT:
380: break;
381: case Lis:
382: {intlet lo= -1, mi, xx, mm, hi= len; relation c;
383: bins: if (hi-lo < 2) break;
384: mi= (lo+hi)/2;
385: if ((c= compare(v, Lisent(tp,mi))) == 0) goto some;
386: if (c < 0) hi= mi; else lo= mi;
387: goto bins;
388: some: xx= mi;
389: while (xx-lo > 1) {
390: mm= (lo+xx)/2;
391: if (compare(v, Lisent(tp,mm)) == 0) xx= mm;
392: else lo= mm;
393: }
394: xx= mi;
395: while (hi-xx > 1) {
396: mm= (xx+hi)/2;
397: if (compare(v, Lisent(tp,mm)) == 0) xx= mm;
398: else hi= mm;
399: }
400: n= hi-lo-1;
401: } break;
402: case Tab:
403: Overall if (compare(v, Dts(*tp++)) == 0) n++;
404: break;
405: default:
406: syserr(MESS(1716, "e#t with non text, list or table"));
407: break;
408: }
409: return mk_integer((int) n);
410: }
411:
412: Hidden bool less(r) relation r; { return r<0; }
413: Hidden bool greater(r) relation r; { return r>0; }
414:
415: Hidden value mm1(t, rel) value t; bool (*rel)(); {
416: intlet len= Length(t), k; value m, *tp= Ats(t);
417: switch (Type(t)) {
418: case Tex:
419: {string cp= (string) tp; char mc= '\0', mm[2];
420: Overall {
421: if (mc == '\0' || ((*rel)(*cp < mc ? -1 : (*cp > mc ? 1 : 0))))
422: mc= *cp;
423: cp++;
424: }
425: mm[0]= mc; mm[1]= '\0';
426: m= mk_text(mm);
427: } break;
428: case Lis:
429: if ((*rel)(-1)) /*min*/ m= copy(*Ats(t));
430: else m= copy(*(Ats(t)+len-1));
431: break;
432: case Tab:
433: {value dm= Vnil;
434: Overall {
435: if (dm == Vnil || (*rel)(compare(Dts(*tp), dm)))
436: dm= Dts(*tp);
437: tp++;
438: }
439: m= copy(dm);
440: } break;
441: default:
442: syserr(MESS(1717, "min or max t, with non text, list or table"));
443: }
444: return m;
445: }
446:
447: #ifdef NO_ABS
448:
449: Hidden int abs(i) int i; {
450: return i >= 0 ? i : -i;
451: }
452:
453: #endif
454:
455: Hidden value mm2(v, t, rel) value v, t; bool (*rel)(); {
456: intlet len= Length(t), k; value m= Vnil, *tp= Ats(t);
457: switch (Type(t)) {
458: case Tex:
459: {string cp= (string) tp; char c, mc= '\0', mm[2];
460: c= *Str(v);
461: Overall {
462: if ((*rel)(c < *cp ? -1 : c > *cp ? 1 : 0)) {
463: if (mc == '\0' || (*rel)(*cp < mc ? -1 : *cp>mc ? 1 : 0))
464: mc= *cp;
465: }
466: cp++;
467: }
468: if (mc != '\0') {
469: mm[0]= mc; mm[1]= '\0';
470: m= mk_text(mm);
471: }
472: } break;
473: case Lis:
474: {intlet lim1, mid, lim2;
475: if ((*rel)(-1)) { /*min*/
476: lim1= 1; lim2= len-1;
477: } else {
478: lim2= 1; lim1= len-1;
479: }
480: if (!(*rel)(compare(v, Lisent(tp,lim2)))) break;
481: if (len == 1 || (*rel)(compare(v, Lisent(tp,lim1)))) {
482: m= copy(Lisent(tp,lim1));
483: break;
484: }
485: /* v rel tp[lim2] && !(v rel tp[lim1]) */
486: while (abs(lim2-lim1) > 1) {
487: mid= (lim1+lim2)/2;
488: if ((*rel)(compare(v, Lisent(tp,mid)))) lim2= mid;
489: else lim1= mid;
490: }
491: m= copy(Lisent(tp,lim2));
492: } break;
493: case Tab:
494: {value dm= Vnil;
495: Overall {
496: if ((*rel)(compare(v, Dts(*tp)))) {
497: if (dm == Vnil ||
498: (*rel)(compare(Dts(*tp), dm)))
499: dm= Dts(*tp);
500: }
501: tp++;
502: }
503: if (dm != Vnil) m= copy(dm);
504: } break;
505: default:
506: syserr(MESS(1718, "min2 or max2 with non text, list or table"));
507: break;
508: }
509: return m;
510: }
511:
512: Visible value min1(t) value t; { /* Monadic min */
513: value m= Vnil;
514: if (!Is_tlt(t))
515: error(MESS(1719, "in min t, t is not a text, list or table"));
516: else if (Length(t) == 0)
517: error(MESS(1720, "in min t, t is empty"));
518: else m= mm1(t, less);
519: return m;
520: }
521:
522: Visible value min2(v, t) value v, t; {
523: value m= Vnil;
524: if (!Is_tlt(t))
525: error(MESS(1721, "in e min t, t is not a text, list or table"));
526: else if (Length(t) == 0)
527: error(MESS(1722, "in e min t, t is empty"));
528: else if (Is_text(t)) {
529: if (!Is_text(v))
530: error(MESS(1723, "in e min t, t is a text but e is not"));
531: else if (Length(v) != 1)
532: error(MESS(1724, "in e min t, e is a text but not a character"));
533: }
534: if (still_ok) {
535: m= mm2(v, t, less);
536: if (m == Vnil)
537: error(MESS(1725, "in e min t, no element of t exceeds e"));
538: }
539: return m;
540: }
541:
542: Visible value max1(t) value t; {
543: value m= Vnil;
544: if (!Is_tlt(t))
545: error(MESS(1726, "in max t, t is not a text, list or table"));
546: else if (Length(t) == 0)
547: error(MESS(1727, "in max t, t is empty"));
548: else m= mm1(t, greater);
549: return m;
550: }
551:
552: Visible value max2(v, t) value v, t; {
553: value m= Vnil;
554: if (!Is_tlt(t))
555: error(MESS(1728, "in e max t, t is not a text, list or table"));
556: else if (Length(t) == 0)
557: error(MESS(1729, "in e max t, t is empty"));
558: else if (Is_text(t)) {
559: if (!Is_text(v))
560: error(MESS(1730, "in e max t, t is a text but e is not"));
561: else if (Length(v) != 1)
562: error(MESS(1731, "in e max t, e is a text but not a character"));
563: }
564: if (still_ok) {
565: m= mm2(v, t, greater);
566: if (m == Vnil)
567: error(MESS(1732, "in e max t, no element of t is less than e"));
568: }
569: return m;
570: }
571:
572: Visible value th_of(n, t) value n, t; {
573: return thof(intval(n), t);
574: }
575:
576: Visible value thof(n, t) int n; value t; {
577: intlet len= Length(t); value w= Vnil;
578: if (!Is_tlt(t))
579: error(MESS(1733, "in n th'of t, t is not a text, list or table"));
580: else if (n <= 0 || n > len)
581: error(MESS(1734, "in n th'of t, n is out of bounds"));
582: else {
583: switch (Type(t)) {
584: case Tex:
585: {char ww[2];
586: ww[0]= *(Str(t)+n-1); ww[1]= '\0';
587: w= mk_text(ww);
588: } break;
589: case Lis:
590: w= copy(*(Ats(t)+n-1));
591: break;
592: case Tab:
593: w= copy(Dts(*(Ats(t)+n-1)));
594: break;
595: default:
596: syserr(MESS(1735, "th'of with non text, list or table"));
597: }
598: }
599: return w;
600: }
601:
602: Visible bool found(elem, v, probe, where)
603: value (*elem)(), v, probe; intlet *where;
604: /* think of elem(v,lo-1) as -Infinity and elem(v,hi+1) as +Infinity.
605: found and where at the end satisfy:
606: SELECT:
607: SOME k IN {lo..hi} HAS probe = elem(v,k):
608: found = Yes AND where = k
609: ELSE: found = No AND elem(v,where-1) < probe < elem(v,where).
610: */
611: {relation c; intlet lo=0, hi= Length(v)-1;
612: if (lo > hi) { *where= lo; return No; }
613: if ((c= compare(probe, (*elem)(v, lo))) == 0) {*where= lo; return Yes; }
614: if (c < 0) { *where=lo; return No; }
615: if (lo == hi) { *where=hi+1; return No; }
616: if ((c= compare(probe, (*elem)(v, hi))) == 0) { *where=hi; return Yes; }
617: if (c > 0) { *where=hi+1; return No; }
618: /* elem(lo) < probe < elem(hi) */
619: while (hi-lo > 1) {
620: if ((c= compare(probe, (*elem)(v, (lo+hi)/2))) == 0) {
621: *where= (lo+hi)/2; return Yes;
622: }
623: if (c < 0) hi= (lo+hi)/2; else lo= (lo+hi)/2;
624: }
625: *where= hi; return No;
626: }
627:
628: Visible bool in(v, t) value v, t; {
629: intlet where, k, len= Length(t); value *tp= Ats(t);
630: if (!Is_tlt(t)) {
631: error(MESS(1736, "in the test e in t, t is not a text, list or table"));
632: return No;
633: }
634: switch (Type(t)) {
635: case Tex:
636: if (Type(v) != Tex)
637: error(MESS(1737, "in the test e in t, t is a text but e is not"));
638: else if (Length(v) != 1)
639: error(MESS(1738, "in the test e in t, e is a text but not a character"));
640: else return index((string) tp, *Str(v)) != 0;
641: return No;
642: case ELT:
643: return No;
644: case Lis:
645: return found(list_elem, t, v, &where);
646: case Tab:
647: Overall if (compare(v, Dts(*tp++)) == 0) return Yes;
648: return No;
649: default:
650: syserr(MESS(1739, "e in t with non text, list or table"));
651: return No;
652: }
653: }
654:
655: Visible bool empty(v) value v; {
656: switch (Type(v)) {
657: case Tex:
658: case Lis:
659: case Tab:
660: case ELT:
661: return (Length(v) == 0);
662: default:
663: syserr(MESS(1740, "empty() on non tlt value"));
664: return (No);
665: }
666: }
667:
668: #endif INTEGRATION
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.