1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ 2: static char rcsid[] = "$Header: node.c,v 2.4 85/08/22 16:05:27 timo Exp $"; 3: 4: /* 5: * B editor -- Parse tree and Focus stack. 6: */ 7: 8: #include "b.h" 9: #include "bobj.h" 10: 11: #include "node.h" 12: 13: #define Register register 14: /* Used for registers 4-6. Define as empty macro on PDP */ 15: 16: 17: /* 18: * Lowest level routines for 'node' data type. 19: */ 20: 21: #define Isnode(n) ((n) && (n)->type == Nod) 22: 23: #define Nchildren(n) ((n)->len) 24: #define Symbol(n) ((n)->n_symbol) 25: #define Child(n, i) ((n)->n_child[(i)-1]) 26: #define Marks(n) ((n)->n_marks) 27: #define Width(n) ((n)->n_width) 28: 29: 30: /* 31: * Routines which are macros for the compiler but real functions for lint, 32: * so it will check the argument types more strictly. 33: */ 34: 35: #ifdef lint 36: node 37: nodecopy(n) 38: node n; 39: { 40: return (node) copy((value) n); 41: } 42: 43: noderelease(n) 44: node n; 45: { 46: release((value)n); 47: } 48: 49: nodeuniql(pn) 50: node *pn; 51: { 52: uniql((value*)pn); 53: } 54: #endif lint 55: 56: 57: /* 58: * Allocate a new node. 59: */ 60: 61: Visible node 62: newnode(nch, sym, children) 63: register int nch; 64: Register int sym; 65: register node children[]; 66: { 67: register node n = (node) grab_node(nch); /* Must preset with zeros! */ 68: 69: Symbol(n) = sym; 70: for (; nch > 0; --nch) 71: Child(n, nch) = children[nch-1]; 72: Width(n) = evalwidth(n); 73: return n; 74: } 75: 76: 77: /* 78: * Macros to change the fields of a node. 79: */ 80: 81: #define Locchild(pn, i) \ 82: (Refcnt(*(pn)) == 1 || nodeuniql(pn), &Child(*(pn), i)) 83: #define Setmarks(pn, x) \ 84: (Refcnt(*(pn)) == 1 || nodeuniql(pn), Marks(*(pn))=(x)) 85: #define Setwidth(pn, w) (Refcnt(*(pn)) == 1 || nodeuniql(pn), Width(*(pn))=w) 86: 87: 88: /* 89: * Change a child of a node. 90: * Like replace(), it does not increase the reference count of n. 91: */ 92: 93: Visible Procedure 94: setchild(pn, i, n) 95: register node *pn; 96: register int i; 97: Register node n; 98: { 99: register node *pch; 100: register node oldchild; 101: 102: Assert(Isnode(*pn)); 103: pch = Locchild(pn, i); 104: oldchild = *pch; 105: *pch = n; 106: repwidth(pn, oldchild, n); 107: noderelease(oldchild); 108: } 109: 110: 111: /* 112: * Lowest level routines for 'path' data type. 113: */ 114: 115: #define NPATHFIELDS 6 116: 117: #define Parent(p) ((p)->p_parent) 118: #define Tree(p) ((p)->p_tree) 119: #define Ichild(p) ((p)->p_ichild) 120: #define Ycoord(p) ((p)->p_ycoord) 121: #define Xcoord(p) ((p)->p_xcoord) 122: #define Level(p) ((p)->p_level) 123: 124: 125: /* 126: * Routines which are macros for the compiler but real functions for lint, 127: * so it will check the argument types more strictly. 128: */ 129: 130: #ifdef lint 131: Visible path 132: pathcopy(p) 133: path p; 134: { 135: return (path) copy((value) p); 136: } 137: 138: Visible Procedure 139: pathrelease(p) 140: path p; 141: { 142: release((value)p); 143: } 144: 145: Visible Procedure 146: pathuniql(pp) 147: path *pp; 148: { 149: uniql((value*)pp); 150: } 151: #endif lint 152: 153: 154: /* 155: * Allocate a new path entry. 156: */ 157: 158: Visible path 159: newpath(pa, n, i) 160: register path pa; 161: register node n; 162: Register int i; 163: { 164: register path p = (path) grab_path(); 165: 166: Parent(p) = pa; 167: Tree(p) = n; 168: Ichild(p) = i; 169: Ycoord(p) = Xcoord(p) = Level(p) = 0; 170: return p; 171: } 172: 173: 174: /* 175: * Macros to change the fields of a path entry. 176: */ 177: 178: #define Uniqp(pp) (Refcnt(*(pp)) == 1 || pathuniql(pp)) 179: 180: #define Setcoord(pp, y, x, level) (Uniqp(pp), \ 181: (*(pp))->p_ycoord = y, (*(pp))->p_xcoord = x, (*(pp))->p_level = level) 182: 183: #define Locparent(pp) (Uniqp(pp), &Parent(*(pp))) 184: 185: #define Loctree(pp) (Uniqp(pp), &Tree(*(pp))) 186: 187: #define Addmarks(pp, x) (Uniqp(pp), \ 188: (*(pp))->p_addmarks |= (x), (*(pp))->p_delmarks &= ~(x)) 189: 190: #define Delmarks(pp, x) (Uniqp(pp), \ 191: (*(pp))->p_delmarks |= (x), (*(pp))->p_addmarks &= ~(x)) 192: 193: 194: Hidden Procedure 195: connect(pp) 196: path *pp; 197: { 198: register path p = *pp; 199: register path pa = Parent(p); 200: register path *ppa; 201: register node n; 202: register node npa; 203: register node *pn; 204: node oldchild; 205: node *pnpa; 206: int i; 207: markbits add; 208: markbits del; 209: 210: if (!pa) 211: return; 212: i = ichild(p); 213: n = Tree(p); 214: if (Child(Tree(pa), i) == n) 215: return; /* Still connected */ 216: 217: n = nodecopy(n); 218: ppa = Locparent(pp); 219: pnpa = Loctree(ppa); 220: pn = Locchild(pnpa, i); 221: oldchild = *pn; 222: *pn = n; 223: repwidth(pnpa, oldchild, n); 224: noderelease(oldchild); 225: 226: add = p->p_addmarks; 227: del = p->p_delmarks; 228: if (add|del) { 229: p = *pp; 230: p->p_addmarks = 0; 231: p->p_delmarks = 0; 232: if (add) 233: Addmarks(ppa, add); 234: npa = *pnpa; 235: if (del) { 236: for (i = Nchildren(npa); i > 0; --i) 237: if (i != ichild(p)) 238: del &= ~marks(Child(npa, i)); 239: Delmarks(ppa, del); 240: } 241: Setmarks(pnpa, Marks(npa)&~del|add); 242: } 243: } 244: 245: 246: /* 247: * The following procedure sets the new width of node *pn when child 248: * oldchild is replaced by child newchild. 249: * This was added because the original call to evalwidth seemed to 250: * be the major caller of noderepr() and fwidth(). 251: */ 252: 253: Hidden Procedure 254: repwidth(pn, old, new) 255: register node *pn; 256: Register node old; 257: Register node new; 258: { 259: register int w = Width(*pn); 260: register int oldwidth = width(old); 261: register int newwidth = width(new); 262: 263: if (w < 0) { 264: if (oldwidth > 0) 265: oldwidth = 0; 266: if (newwidth > 0) 267: newwidth = 0; 268: } 269: else { 270: Assert(oldwidth >= 0); 271: if (newwidth < 0) { 272: Setwidth(pn, newwidth); 273: return; 274: } 275: } 276: newwidth -= oldwidth; 277: if (newwidth) 278: Setwidth(pn, w + newwidth); 279: } 280: 281: 282: Visible Procedure 283: markpath(pp, new) 284: register path *pp; 285: register markbits new; 286: { 287: register node *pn; 288: register markbits old; 289: 290: Assert(Type(Tree(*pp)) == Nod); 291: old = Marks(Tree(*pp)); 292: if ((old|new) == old) 293: return; /* Bits already set */ 294: 295: pn = Loctree(pp); 296: Setmarks(pn, old|new); 297: Addmarks(pp, new&~old); 298: } 299: 300: 301: Visible Procedure 302: unmkpath(pp, del) 303: register path *pp; 304: register int del; 305: { 306: register node *pn; 307: register markbits old; 308: 309: Assert(Type(Tree(*pp)) == Nod); 310: old = Marks(Tree(*pp)); 311: if ((old&~del) == del) 312: return; 313: 314: pn = Loctree(pp); 315: Setmarks(pn, old&~del); 316: Delmarks(pp, del&old); 317: } 318: 319: 320: Hidden Procedure 321: clearmarks(pn) 322: register node *pn; 323: { 324: register int i; 325: 326: if (!Marks(*pn)) 327: return; 328: if (Isnode(*pn)) { 329: Setmarks(pn, 0); 330: for (i = Nchildren(*pn); i > 0; --i) 331: clearmarks(Locchild(pn, i)); 332: } 333: } 334: 335: 336: /* 337: * Replace the focus' tree by a new node. 338: * WARNING: n's reference count is not increased! 339: * You can also think of this as: replace(pp, n) implies noderelease(n). 340: * Mark bits are copied from the node being replaced. 341: */ 342: 343: Visible Procedure 344: replace(pp, n) 345: register path *pp; 346: register node n; 347: { 348: register node *pn; 349: register markbits old; 350: 351: pn = Loctree(pp); 352: if (Type(*pn) == Nod) 353: old = Marks(*pn); 354: else 355: old = 0; 356: noderelease(*pn); 357: *pn = n; 358: if (Type(n) == Nod) { 359: clearmarks(pn); 360: if (old) 361: Setmarks(pn, old); 362: } 363: else if (old) 364: Addmarks(pp, old); 365: } 366: 367: 368: Visible bool 369: up(pp) 370: register path *pp; 371: { 372: register path p = *pp; 373: 374: if (!Parent(p)) 375: return No; 376: 377: connect(pp); 378: p = pathcopy(Parent(*pp)); 379: pathrelease(*pp); 380: *pp = p; 381: return Yes; 382: } 383: 384: 385: Visible bool 386: downi(pp, i) 387: register path *pp; 388: register int i; 389: { 390: register node n; 391: auto int y; 392: auto int x; 393: auto int level; 394: 395: n = Tree(*pp); 396: if (!Isnode(n) || i < 1 || i > Nchildren(n)) 397: return No; 398: 399: y = Ycoord(*pp); 400: x = Xcoord(*pp); 401: level = Level(*pp); 402: *pp = newpath(*pp, nodecopy(Child(n, i)), i); 403: evalcoord(n, i, &y, &x, &level); 404: Setcoord(pp, y, x, level); 405: return Yes; 406: } 407: 408: 409: Visible bool 410: downrite(pp) 411: register path *pp; 412: { 413: if (!Isnode(Tree(*pp))) 414: return No; 415: return downi(pp, Nchildren(Tree(*pp))); 416: } 417: 418: 419: Visible bool 420: left(pp) 421: register path *pp; 422: { 423: register int i; 424: 425: i = ichild(*pp) - 1; 426: if (i <= 0) 427: return No; 428: if (!up(pp)) 429: return No; 430: return downi(pp, i); 431: } 432: 433: 434: Visible bool 435: rite(pp) 436: register path *pp; 437: { 438: register int i; 439: register path pa = Parent(*pp); 440: 441: i = ichild(*pp) + 1; 442: if (!pa || i > Nchildren(Tree(pa))) 443: return No; 444: if (!up(pp)) 445: return No; 446: return downi(pp, i); 447: } 448: 449: 450: /* 451: * Highest level: small utilities. 452: * 453: * WARNING: Several of the following routines may change their argument 454: * even if they return No. 455: * HINT: Some of these routines are not used; they are included for 456: * completeness of the provided set of operators only. If you have 457: * space problems (as, e.g., on a PDP-11), you can delete the superfluous 458: * ones (lint will tell you which they are). 459: */ 460: 461: Visible Procedure 462: top(pp) 463: register path *pp; 464: { 465: while (up(pp)) 466: ; 467: } 468: 469: 470: Visible bool 471: nextnode(pp) 472: register path *pp; 473: { 474: while (!rite(pp)) { 475: if (!up(pp)) 476: return No; 477: } 478: return Yes; 479: } 480: 481: 482: Visible Procedure 483: firstleaf(pp) 484: register path *pp; 485: { 486: while (down(pp)) 487: ; 488: } 489: 490: #if NOT_USED 491: 492: Visible bool 493: nextleaf(pp) 494: register path *pp; 495: { 496: if (!nextnode(pp)) 497: return No; 498: firstleaf(pp); 499: return Yes; 500: } 501: 502: #endif NOT_USED 503: 504: Visible bool 505: prevnode(pp) 506: register path *pp; 507: { 508: while (!left(pp)) { 509: if (!up(pp)) 510: return No; 511: } 512: return Yes; 513: } 514: 515: Visible Procedure 516: lastleaf(pp) 517: register path *pp; 518: { 519: while (downrite(pp)) 520: ; 521: } 522: 523: #ifdef NOT_USED 524: 525: Visible bool 526: prevleaf(pp) 527: register path *pp; 528: { 529: if (!prevnode(pp)) 530: return No; 531: lastleaf(pp); 532: return Yes; 533: } 534: 535: 536: Visible bool 537: nextmarked(pp, x) 538: register path *pp; 539: register markbits x; 540: { 541: do { 542: if (!nextnode(pp)) 543: return No; 544: } while (!marked(*pp, x)); 545: while (down(pp)) { 546: while (!marked(*pp, x)) { 547: if (!rite(pp)) { 548: up(pp) || Abort(); 549: return Yes; 550: } 551: } 552: } 553: return Yes; 554: } 555: 556: #endif NOT_UED 557: 558: Visible bool 559: firstmarked(pp, x) 560: register path *pp; 561: register markbits x; 562: { 563: while (!marked(*pp, x)) { 564: if (!up(pp)) 565: return No; 566: } 567: while (down(pp)) { 568: while (Type(tree(*pp)) == Tex || !marked(*pp, x)) { 569: if (!rite(pp)) { 570: up(pp) || Abort(); 571: return Yes; 572: } 573: } 574: } 575: return Yes; 576: } 577: 578: 579: Visible bool 580: prevmarked(pp, x) 581: register path *pp; 582: register markbits x; 583: { 584: do { 585: if (!prevnode(pp)) 586: return No; 587: } while (!marked(*pp, x)); 588: while (downrite(pp)) { 589: while (!marked(*pp, x)) { 590: if (!left(pp)) { 591: up(pp) || Abort(); 592: return Yes; 593: } 594: } 595: } 596: return Yes; 597: } 598: 599: 600: /* 601: * Deliver the path length to the root. 602: */ 603: 604: 605: Visible Procedure 606: pathlength(p) 607: register path p; 608: { 609: register int n; 610: 611: for (n = 0; p; ++n) 612: p = parent(p); 613: return n; 614: } 615: 616: 617: /* 618: * Put a C string in a trimmed location (this name should change, 619: * the 'official' routine of this name has quite different parameters). 620: */ 621: 622: 623: Visible Procedure 624: putintrim(pn, head, tail, str) 625: register value *pn; 626: register int head; 627: Register int tail; 628: Register string str; 629: { 630: register value v = *pn; 631: value w = head == 0 ? mk_text("") : 632: head == Length(v) ? copy(v) : trim(v, 0, Length(v) - head); 633: 634: Assert(head >= 0 && tail >= 0 && head + tail <= Length(v)); 635: if (*str) 636: concato(&w, str); 637: if (tail > 0) 638: concato(&w, Str(v)+(Length(v) - tail)); 639: release(v); 640: *pn = w; 641: } 642: 643: 644: /* 645: * Touch the node in focus. 646: */ 647: 648: Visible Procedure 649: touchpath(pp) 650: register path *pp; 651: { 652: nodeuniql(Loctree(pp)); 653: }