1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ 2: static char rcsid[] = "$Header: bobj.c,v 2.5 85/08/22 15:59:59 timo Exp $"; 3: 4: /* 5: * B editor -- A shrunken version of the B interpreter's run-time system. 6: */ 7: 8: #include "b.h" 9: #include "bobj.h" 10: #include "node.h" 11: 12: #define COMPOUNDS 13: 14: string malloc(); 15: string calloc(); 16: string realloc(); 17: string strcpy(); 18: 19: extern bool dflag; 20: 21: struct head { 22: char type; 23: intlet refcnt; 24: intlet len; 25: }; 26: #define Intsize (sizeof(int)) 27: #define Hsize (sizeof(struct head)) 28: #define Headsize (((Hsize-1)/Intsize + 1) * Intsize) 29: 30: #define Field(v, i) (((value *)&(v)->cts)[i]) 31: 32: #ifndef NDEBUG 33: 34: /* Statistics on allocation/sharing */ 35: 36: int nobjs; 37: int nrefs; 38: 39: #define Increfs ++nrefs 40: #define Decrefs --nrefs 41: 42: #else NDEBUG 43: 44: #define Increfs 45: #define Decrefs 46: 47: #endif NDEBUG 48: 49: 50: #define Copy(v) if ((v) && Refcnt(v) < Maxintlet) { ++Refcnt(v); Increfs; } 51: #define Release(v) if (!(v) || Refcnt(v) == Maxintlet) ; else RRelease(v) 52: #define RRelease(v) \ 53: if (Refcnt(v) > 1) { --Refcnt(v); Decrefs; } else release(v) 54: 55: 56: /* 57: * Allocate a value with nbytes of data after the usual type, len, refcnt 58: * fields. 59: */ 60: 61: value 62: grabber(nbytes) 63: register int nbytes; 64: { 65: register value v = (value) malloc((unsigned) (Headsize + nbytes)); 66: 67: if (!v) 68: syserr("grabber: malloc"); 69: #ifndef NDEBUG 70: if (dflag) 71: newval(v); 72: #endif 73: #ifndef NDEBUG 74: ++nobjs; 75: #endif 76: Increfs; 77: v->refcnt = 1; 78: return v; 79: } 80: 81: 82: /* 83: * Reallocate a value with nbytes of data after the usual type, len, refcnt 84: * fields. 85: */ 86: 87: value 88: regrabber(v, nbytes) 89: register value v; 90: register int nbytes; 91: { 92: Assert(v && v->refcnt == 1); 93: v = (value) realloc((char*)v, (unsigned) (Headsize + nbytes)); 94: if (!v) 95: syserr("regrabber: realloc"); 96: return v; 97: } 98: 99: 100: /* 101: * Set an object's refcnt to infinity, so it will never be released. 102: */ 103: 104: fix(v) 105: register value v; 106: { 107: register int i; 108: register node n; 109: register path p; 110: 111: Assert(v->refcnt > 0); 112: #ifndef NDEBUG 113: if (v->refcnt < Maxintlet) 114: nrefs -= v->refcnt; 115: #endif 116: v->refcnt = Maxintlet; 117: #if OBSOLETE 118: switch (v->type) { 119: case Tex: 120: break; 121: case Nod: 122: n = (node)v; 123: for (i = v->len - 1; i >= 0; --i) 124: if (n->n_child[i]) 125: fix((value)(n->n_child[i])); 126: break; 127: case Pat: 128: p = (path)v; 129: if (p->p_parent) 130: fix((value)(p->p_parent)); 131: if (p->p_tree) 132: fix((value)(p->p_tree)); 133: break; 134: #ifdef COMPOUNDS 135: case Com: 136: for (i = v->len-1; i >= 0; --i) 137: if (Field(v, i)) 138: fix(Field(v, i)); 139: break; 140: #endif COMPOUNDS 141: #ifdef SLOW_INTS 142: case Num: 143: #endif SLOW_INTS 144: default: 145: Abort(); 146: } 147: #endif OBSOLETE 148: } 149: 150: 151: #ifdef COMPOUNDS 152: /* 153: * Allocate a compound with n fields. 154: */ 155: 156: Visible value 157: grab_com(n) 158: int n; 159: { 160: value v = grabber(n*sizeof(value)); 161: 162: v->type = Com; 163: v->len = n; 164: for (--n; n >= 0; --n) 165: Field(v, n) = Vnil; 166: return v; 167: } 168: #endif COMPOUNDS 169: 170: 171: /* 172: * Allocate a node with nch children. 173: */ 174: 175: node 176: grab_node(nch) 177: register int nch; 178: { 179: register node n = (node) grabber( 180: sizeof(struct node) - Headsize + 181: sizeof(value) * (nch-1)); 182: register int i; 183: 184: n->type = Nod; 185: n->len = nch; 186: n->n_marks = 0; 187: n->n_width = 0; 188: n->n_symbol = 0; 189: for (i = nch-1; i >= 0; --i) 190: n->n_child[i] = Nnil; 191: return n; 192: } 193: 194: 195: /* 196: * Allocate a path. 197: */ 198: 199: path 200: grab_path() 201: { 202: register path p = (path) grabber( 203: sizeof(struct path) - Headsize); 204: 205: p->type = Pat; 206: p->p_parent = Pnil; 207: p->p_tree = Nnil; 208: p->p_ichild = 0; 209: p->p_ycoord = 0; 210: p->p_xcoord = 0; 211: p->p_level = 0; 212: p->p_addmarks = 0; 213: p->p_delmarks = 0; 214: return p; 215: } 216: 217: 218: #ifdef SLOW_INTS 219: /* 220: * Make an integer. 221: */ 222: 223: value 224: mk_integer(i) 225: int i; 226: { 227: value v; 228: static value tab[128]; 229: 230: if (!i) 231: return Vnil; 232: if (!(i&~127) && tab[i]) 233: return tab[i]; 234: 235: v = grabber(sizeof(value)); 236: v->type = Num; 237: Field(v, 0) = (value) i; 238: if (!(i&~127)) { 239: tab[i] = v; 240: v->refcnt = Maxintlet; 241: } 242: return v; 243: } 244: #endif SLOW_INTS 245: 246: 247: /* 248: * Make a text object out of a C string. 249: */ 250: 251: value 252: mk_text(str) 253: register string str; 254: { 255: register int len = strlen(str); 256: register value v = grabber(len+1); 257: 258: v->type = Tex; 259: v->len = len; 260: strcpy(Str(v), str); 261: return v; 262: } 263: 264: 265: /* 266: * Concatenate a C string to a text object (at the end). 267: */ 268: 269: concato(pv, str) 270: register value *pv; 271: register string str; 272: { 273: register value v = *pv; 274: register int vlen = v->len; 275: register int len = strlen(str); 276: 277: Assert(v && v->refcnt > 0); 278: if (!len) 279: return; 280: 281: len += vlen; 282: if (v->refcnt == 1) 283: v = regrabber(v, len+1); 284: else { 285: v = grabber(len+1); 286: v->type = Tex; 287: strcpy(Str(v), Str(*pv)); 288: Release(*pv); 289: } 290: strcpy(Str(v) + vlen, str); 291: v->len = len; 292: *pv = v; 293: } 294: 295: 296: /* 297: * Return a substring (trim) of a text object. 298: */ 299: 300: value 301: trim(v, behead, curtail) 302: register value v; 303: register int behead; 304: register int curtail; 305: { 306: register value w; 307: register int c; 308: 309: Assert(v && v->refcnt > 0); 310: Assert(behead >= 0 && curtail >= 0 && behead+curtail <= v->len); 311: if (behead + curtail == 0) { 312: Copy(v); 313: return v; 314: } 315: 316: c = Str(v)[v->len - curtail]; 317: Str(v)[v->len - curtail] = 0; /* TEMPORARILY */ 318: w = mk_text(Str(v) + behead); 319: Str(v)[v->len - curtail] = c; 320: return w; 321: } 322: 323: 324: #ifdef SLOW_INTS 325: /* 326: * Return the C value if an integer object. 327: */ 328: 329: int 330: intval(v) 331: register value v; 332: { 333: if (!v) 334: return 0; 335: return (int) Field(v, 0); 336: } 337: #endif SLOW_INTS 338: 339: 340: /* 341: * Make sure a location (pointer variable) contains a unique object. 342: */ 343: 344: uniql(pv) 345: register value *pv; 346: { 347: register value v = *pv; 348: register value w; 349: register path p; 350: register node n; 351: register int i; 352: 353: Assert(v && v->refcnt > 0); 354: if (v->refcnt == 1) 355: return; 356: 357: switch (v->type) { 358: 359: case Nod: 360: n = grab_node(v->len); 361: for (i = v->len - 1; i >= 0; --i) { 362: w = (value) (n->n_child[i] = ((node)v)->n_child[i]); 363: Copy(w); /* This is ugly */ 364: } 365: n->n_marks = ((node)v)->n_marks; 366: n->n_width = ((node)v)->n_width; 367: n->n_symbol = ((node)v)->n_symbol; 368: w = (value)n; 369: break; 370: 371: case Pat: 372: p = grab_path(); 373: p->p_parent = ((path)v)->p_parent; 374: Copy(p->p_parent); 375: p->p_tree = ((path)v)->p_tree; 376: Copy(p->p_tree); 377: p->p_ichild = ((path)v)->p_ichild; 378: p->p_ycoord = ((path)v)->p_ycoord; 379: p->p_xcoord = ((path)v)->p_xcoord; 380: p->p_level = ((path)v)->p_level; 381: w = (value)p; 382: break; 383: 384: #ifdef SLOW_INTS 385: case Num: 386: w = mk_integer(intval(v)); 387: break; 388: #endif SLOW_INTS 389: 390: #ifdef COMPOUNDS 391: case Com: 392: w = grab_com(v->len); 393: for (i = v->len - 1; i >= 0; --i) { 394: n = (node) (Field(w, i) = Field(v, i)); 395: Copy(n); /* This is uglier */ 396: } 397: break; 398: #endif COMPOUNDS 399: 400: case Tex: 401: w = mk_text(Str(v)); 402: break; 403: 404: default: 405: Abort(); 406: 407: } 408: Release(v); 409: *pv = w; 410: } 411: 412: 413: /* 414: * Increase the reference count of an object, unless it is infinite. 415: */ 416: 417: value 418: copy(v) 419: value v; 420: { 421: if (!v) 422: return v; 423: 424: Assert(v->refcnt > 0); 425: if (v->refcnt < Maxintlet) { 426: ++v->refcnt; 427: Increfs; 428: } 429: return v; 430: } 431: 432: 433: /* 434: * Decrease the reference count of an object, unless it is infinite. 435: * If it reaches zero, free the storage occupied by the object. 436: */ 437: 438: release(v) 439: register value v; 440: { 441: register int i; 442: register value w; 443: 444: if (!v) 445: return; 446: Assert(v->refcnt > 0); 447: if (v->refcnt == Maxintlet) 448: return; 449: 450: Decrefs; 451: --v->refcnt; 452: if (v->refcnt == 0) { 453: switch (v->type) { 454: #ifdef SLOW_INTS 455: case Num: 456: #endif SLOW_INTS 457: case Tex: 458: break; 459: #ifdef COMPOUNDS 460: case Com: 461: for (i = v->len - 1; i >= 0; --i) { 462: w = Field(v, i); 463: Release(w); 464: } 465: break; 466: #endif COMPOUNDS 467: case Nod: 468: for (i = v->len - 1; i >= 0; --i) { 469: w = (value)(((node)v)->n_child[i]); 470: Release(w); 471: } 472: break; 473: case Pat: 474: w = (value)(((path)v)->p_parent); 475: Release(w); 476: w = (value)(((path)v)->p_tree); 477: Release(w); 478: break; 479: default: 480: Abort(); 481: } 482: #ifndef NDEBUG 483: if (dflag) 484: delval(v); 485: --nobjs; 486: #endif NDEBUG 487: free((string)v); 488: } 489: } 490: 491: objstats() 492: { 493: #ifndef NDEBUG 494: fprintf(stderr, "*** Object statistics: %d objects, %d references\n", 495: nobjs, nrefs); 496: #ifdef MSTATS 497: mstats("(at end)"); /* A routine which some malloc versions have to print 498: memory statistics. Remove if your malloc hasn't. */ 499: #endif MSTATS 500: #endif NDEBUG 501: } 502: 503: #ifndef NDEBUG 504: valdump(v) 505: value v; 506: { 507: if (!v) 508: fputs("(nil)", stderr); 509: else { 510: fprintf(stderr, "v=0x%x, type='%c', len=%d, refcnt=", 511: v, v->type, v->len); 512: if (v->refcnt == Maxintlet) 513: putc('*', stderr); 514: else 515: fprintf(stderr, "%d", v->refcnt); 516: fputs(": ", stderr); 517: wrval(v); 518: 519: } 520: putc('\n', stderr); 521: } 522: 523: #define QUOTE '\'' 524: 525: wrval(v) 526: value v; 527: { 528: register string cp; 529: register int c; 530: 531: if (!v) { 532: fputs("nil", stderr); 533: return; 534: } 535: 536: switch (v->type) { 537: 538: #ifdef SLOW_INTS 539: case Num: 540: fprintf(stderr, "%d", intval(v)); 541: break; 542: #endif SLOW_INTS 543: 544: case Tex: 545: putc(QUOTE, stderr); 546: for (cp = Str(v); c = *cp; ++cp) { 547: if (' ' <= c && c < 0177) { 548: putc(c, stderr); 549: if (c == QUOTE) 550: putc(c, stderr); 551: } 552: else if (0 <= c && c < ' ') 553: putc('^', stderr), putc(c + '@', stderr); 554: else 555: fprintf(stderr, "\\%03o", c); 556: } 557: putc(QUOTE, stderr); 558: break; 559: 560: #ifdef COMPOUNDS 561: case Com: 562: { 563: int i; 564: value f; 565: putc('(', stderr); 566: for (i = 0; i < v->len; ++i) { 567: if (i) 568: putc(',', stderr), putc(' ', stderr); 569: f = Field(v, i); 570: if (!f || f->refcnt == 1 || f->type != Com) { 571: if (f && f->type == Com) 572: fprintf(stderr, "0x%x=", f); 573: wrval(f); 574: } 575: else 576: fprintf(stderr, "0x%x", f); 577: } 578: putc(')', stderr); 579: break; 580: } 581: #endif COMPOUNDS 582: 583: default: 584: fprintf(stderr, "0x%x", v); 585: 586: } 587: } 588: 589: static struct list { 590: struct list *link; 591: value val; 592: } head; 593: #endif NDEBUG 594: 595: objdump() 596: { 597: #ifndef NDEBUG 598: struct list *l; 599: 600: for (l = head.link; l; l = l->link) 601: valdump(l->val); 602: #endif NDEBUG 603: } 604: 605: objcheck() 606: { 607: #ifndef NDEBUG 608: struct list *l; 609: 610: for (l = head.link; l; l = l->link) 611: if (l->val->refcnt != Maxintlet) 612: valdump(l->val); 613: #endif NDEBUG 614: } 615: 616: #ifndef NDEBUG 617: newval(v) 618: register value v; 619: { 620: register struct list *l = 621: (struct list *) malloc((unsigned) sizeof(struct list)); 622: 623: if (!l) 624: syserr("newval: malloc"); 625: l->link = head.link; 626: l->val = v; 627: head.link = l; 628: } 629: 630: delval(v) 631: register value v; 632: { 633: register struct list *l; 634: register struct list *p; 635: 636: for (p = &head, l = head.link; l; p = l, l = l->link) { 637: if (l->val == v) { 638: p->link = l->link; 639: free((string)l); 640: return; 641: } 642: } 643: Abort(); 644: } 645: #endif NDEBUG