|
|
1.1 ! root 1: # include <useful.h> ! 2: # include <sccs.h> ! 3: ! 4: SCCSID(@(#)mac.c 7.1 2/5/81) ! 5: ! 6: ! 7: # define TRACE if (FALSE) printf ! 8: ! 9: /* ! 10: ** MACRO PROCESSOR ! 11: */ ! 12: ! 13: ! 14: # define ANYDELIM '\020' /* \| -- zero or more delims */ ! 15: # define ONEDELIM '\021' /* \^ -- exactly one delim */ ! 16: # define CHANGE '\022' /* \& -- token change */ ! 17: ! 18: # define PARAMN '\023' /* $ -- non-preprocessed param */ ! 19: # define PARAMP '\024' /* $$ -- preprocessed param */ ! 20: ! 21: # define PRESCANENABLE '@' /* character to enable prescan */ ! 22: # define LBRACE '{' /* left brace */ ! 23: # define RBRACE '}' /* right brace */ ! 24: # define BACKSLASH '\\' /* backslash */ ! 25: # define LQUOTE '`' /* left quote */ ! 26: # define RQUOTE '\'' /* right quote */ ! 27: # define SPACE ' ' ! 28: # define TAB '\t' ! 29: # define NEWLINE '\n' ! 30: ! 31: # define QUOTED 0200 /* pass right through bit */ ! 32: # define CHARMASK 0177 /* character part */ ! 33: # define BYTEMASK 0377 /* one byte */ ! 34: ! 35: # define ITERTHRESH 100 /* iteration limit */ ! 36: # define NPRIMS (sizeof Macprims / sizeof Macprims[0]) ! 37: ! 38: /* token modes, used to compute token changes */ ! 39: # define NONE 0 /* guarantees a token change */ ! 40: # define ID 1 /* identifier */ ! 41: # define NUMBER 2 /* number (int or float) */ ! 42: # define DELIM 3 /* delimiter, guarantees a token change */ ! 43: # define QUOTEMODE 4 /* quoted construct */ ! 44: # define OP 5 /* operator */ ! 45: # define NOCHANGE 6 /* guarantees no token change */ ! 46: ! 47: ! 48: ! 49: # include "buf.h" /* headers for buffer manip */ ! 50: ! 51: ! 52: /* macro definitions */ ! 53: struct macro ! 54: { ! 55: struct macro *nextm; /* pointer to next macro header */ ! 56: char *template; /* pointer to macro template */ ! 57: char *substitute; /* pointer to substitution text */ ! 58: }; ! 59: ! 60: /* primitive declarations */ ! 61: struct macro Macprims[] = ! 62: { ! 63: &Macprims[1], "{define;\020\024t;\020\024s}", (char *) 1, ! 64: &Macprims[2], "{rawdefine;\020\024t;\020\024s}", (char *) 2, ! 65: &Macprims[3], "{remove;\020\024t}", (char *) 3, ! 66: &Macprims[4], "{dump}", (char *) 4, ! 67: &Macprims[5], "{type\020\024m}", (char *) 5, ! 68: &Macprims[6], "{read\020\024m}", (char *) 6, ! 69: &Macprims[7], "{readdefine;\020\024n;\020\024m}", (char *) 7, ! 70: &Macprims[8], "{ifsame;\020\024a;\020\024b;\020\023t;\020\023f}", (char *) 8, ! 71: &Macprims[9], "{ifeq;\020\024a;\020\024b;\020\023t;\020\023f}", (char *) 9, ! 72: &Macprims[10], "{ifgt;\020\024a;\020\024b;\020\023t;\020\023f}", (char *) 10, ! 73: &Macprims[11], "{eval\020\024e}", (char *) 11, ! 74: &Macprims[12], "{substr;\020\024f;\020\024t;\024s}", (char *) 12, ! 75: &Macprims[13], "{dnl}", (char *) 13, ! 76: &Macprims[14], "{remove}", (char *) 3, ! 77: 0, "{dump;\020\024n}", (char *) 4, ! 78: }; ! 79: ! 80: struct macro *Machead = &Macprims[0]; /* head of macro list */ ! 81: ! 82: ! 83: /* parameters */ ! 84: struct param ! 85: { ! 86: struct param *nextp; ! 87: char mode; ! 88: char name; ! 89: char *paramt; ! 90: }; ! 91: ! 92: ! 93: ! 94: /* the environment */ ! 95: struct env ! 96: { ! 97: struct env *nexte; /* next environment */ ! 98: int (*rawget)(); /* raw character get routine */ ! 99: char **rawpar; /* a parameter to that routine */ ! 100: char prevchar; /* previous character read */ ! 101: char tokenmode; /* current token mode */ ! 102: char change; /* token change flag */ ! 103: char eof; /* eof flag */ ! 104: char newline; /* set if bol */ ! 105: char rawnewline; /* same for raw input */ ! 106: struct buf *pbuf; /* peek buffer */ ! 107: struct buf *mbuf; /* macro buffer */ ! 108: char endtrap; /* endtrap flag */ ! 109: char pass; /* pass flag */ ! 110: char pdelim; /* current parameter delimiter */ ! 111: struct param *params; /* parameter list */ ! 112: int itercount; /* iteration count */ ! 113: int quotelevel; /* quote nesting level */ ! 114: }; ! 115: ! 116: /* current environment pointer */ ! 117: struct env *Macenv; ! 118: /* ! 119: ** MACINIT -- initialize for macro processing ! 120: ** ! 121: ** *** EXTERNAL INTERFACE *** ! 122: ** ! 123: ** The macro processor is initialized. Any crap left over from ! 124: ** previous processing (which will never occur normally, but may ! 125: ** happen on an interrupt, for instance) will be cleaned up. The ! 126: ** raw input is defined, and the 'endtrap' parameter tells whether ! 127: ** this is "primary" processing or not; in other words, it tells ! 128: ** whether to spring {begintrap} and {endtrap}. ! 129: ** ! 130: ** This routine must always be called prior to any processing. ! 131: */ ! 132: ! 133: macinit(rawget, rawpar, endtrap) ! 134: int (*rawget)(); ! 135: char **rawpar; ! 136: int endtrap; ! 137: { ! 138: static struct env env; ! 139: register struct env *e; ! 140: register struct env *f; ! 141: ! 142: /* clear out old crap */ ! 143: for (e = Macenv; e != 0; e = f) ! 144: { ! 145: bufpurge(&e->mbuf); ! 146: bufpurge(&e->pbuf); ! 147: macpflush(e); ! 148: f = e->nexte; ! 149: if (f != 0) ! 150: buffree(e); ! 151: } ! 152: ! 153: /* set up the primary environment */ ! 154: Macenv = e = &env; ! 155: clrmem(e, sizeof *e); ! 156: ! 157: e->rawget = rawget; ! 158: e->rawpar = rawpar; ! 159: e->endtrap = endtrap; ! 160: e->newline = 1; ! 161: ! 162: if (endtrap) ! 163: macspring("{begintrap}"); ! 164: } ! 165: /* ! 166: ** MACGETCH -- get character after macro processing ! 167: ** ! 168: ** *** EXTERNAL INTERFACE ROUTINE *** ! 169: ** ! 170: ** The macro processor must have been previously initialized by a ! 171: ** call to macinit(). ! 172: */ ! 173: ! 174: macgetch() ! 175: { ! 176: register struct env *e; ! 177: register int c; ! 178: ! 179: e = Macenv; ! 180: for (;;) ! 181: { ! 182: /* get an input character */ ! 183: c = macgch(); ! 184: ! 185: /* check for end-of-file processing */ ! 186: if (c == 0) ! 187: { ! 188: /* check to see if we should spring {endtrap} */ ! 189: if (e->endtrap) ! 190: { ! 191: e->endtrap = 0; ! 192: macspring("{endtrap}"); ! 193: continue; ! 194: } ! 195: ! 196: /* don't spring endtrap -- real end of file */ ! 197: return (0); ! 198: } ! 199: ! 200: /* not an end of file -- check for pass character through */ ! 201: if (e->pass) ! 202: { ! 203: e->pass = 0; ! 204: e->change = 0; ! 205: } ! 206: if ((c & QUOTED) != 0 || !e->change || e->tokenmode == DELIM) ! 207: { ! 208: /* the character is to be passed through */ ! 209: /* reset iteration count and purge macro buffer */ ! 210: e->itercount = 0; ! 211: bufflush(&e->mbuf); ! 212: e->newline = (c == NEWLINE); ! 213: return (c & CHARMASK); ! 214: } ! 215: ! 216: /* this character is a candidate for macro processing */ ! 217: macunget(0); ! 218: bufflush(&e->mbuf); ! 219: ! 220: /* check for infinite loop */ ! 221: if (e->itercount > ITERTHRESH) ! 222: { ! 223: printf("Infinite loop in macro\n"); ! 224: e->pass++; ! 225: continue; ! 226: } ! 227: ! 228: /* see if we have a macro match */ ! 229: if (macallscan()) ! 230: { ! 231: /* yep -- count iterations and rescan it */ ! 232: e->itercount++; ! 233: } ! 234: else ! 235: { ! 236: /* nope -- pass the next token through raw */ ! 237: e->pass++; ! 238: } ! 239: } ! 240: } ! 241: /* ! 242: ** MACGCH -- get input character, knowing about tokens ! 243: ** ! 244: ** The next input character is returned. In addition, the quote ! 245: ** level info is maintained and the QUOTED bit is set if the ! 246: ** returned character is (a) quoted or (b) backslash escaped. ! 247: ** As a side effect the change flag is maintained. Also, the ! 248: ** character is saved in mbuf. ! 249: */ ! 250: ! 251: macgch() ! 252: { ! 253: register int c; ! 254: register struct env *e; ! 255: register int i; ! 256: ! 257: e = Macenv; ! 258: ! 259: for (;;) ! 260: { ! 261: /* get virtual raw character, save in mbuf, and set change */ ! 262: c = macfetch(e->quotelevel > 0); ! 263: ! 264: /* test for magic frotz */ ! 265: switch (c) ! 266: { ! 267: case 0: /* end of file */ ! 268: return (0); ! 269: ! 270: case LQUOTE: ! 271: if (e->quotelevel++ == 0) ! 272: continue; ! 273: break; ! 274: ! 275: case RQUOTE: ! 276: if (e->quotelevel == 0) ! 277: return (c); ! 278: if (--e->quotelevel == 0) ! 279: { ! 280: continue; ! 281: } ! 282: break; ! 283: ! 284: case BACKSLASH: ! 285: if (e->quotelevel > 0) ! 286: break; ! 287: c = macfetch(1); ! 288: ! 289: /* handle special cases */ ! 290: if (c == e->pdelim) ! 291: break; ! 292: ! 293: /* do translations */ ! 294: switch (c) ! 295: { ! 296: case SPACE: /* space */ ! 297: case TAB: /* tab */ ! 298: case NEWLINE: /* newline */ ! 299: case RQUOTE: ! 300: case LQUOTE: ! 301: case '$': ! 302: case LBRACE: ! 303: case RBRACE: ! 304: case BACKSLASH: ! 305: break; ! 306: ! 307: default: ! 308: /* take character as is (unquoted) */ ! 309: c = 0; ! 310: break; ! 311: } ! 312: ! 313: if (c != 0) ! 314: break; ! 315: ! 316: /* not an escapable character -- treat it normally */ ! 317: macunget(1); ! 318: c = BACKSLASH; ! 319: /* do default character processing on backslash */ ! 320: ! 321: default: ! 322: if (e->quotelevel > 0) ! 323: break; ! 324: return (c); ! 325: } ! 326: ! 327: /* the character is quoted */ ! 328: return (c | QUOTED); ! 329: } ! 330: } ! 331: /* ! 332: ** MACFETCH -- fetch virtual raw character ! 333: ** ! 334: ** A character is fetched from the peek buffer. If that buffer is ! 335: ** empty, it is fetched from the raw input. The character is then ! 336: ** saved away, and the change flag is set accordingly. ! 337: ** The QUOTED bit on the character is set if the 'quote' flag ! 338: ** parameter is set; used for backslash escapes. ! 339: ** Note that the QUOTED bit appears only on the character which ! 340: ** goes into the macro buffer; the character returned is normal. ! 341: */ ! 342: ! 343: macfetch(quote) ! 344: int quote; ! 345: { ! 346: register struct env *e; ! 347: register int c; ! 348: register int escapech; ! 349: ! 350: e = Macenv; ! 351: escapech = 0; ! 352: ! 353: for (;;) ! 354: { ! 355: /* get character from peek buffer */ ! 356: c = bufget(&e->pbuf); ! 357: ! 358: if (c == 0) ! 359: { ! 360: /* peek buffer is empty */ ! 361: /* check for already raw eof */ ! 362: if (!e->eof) ! 363: { ! 364: /* note that c must be int so that the QUOTED bit is not negative */ ! 365: c = (*e->rawget)(e->rawpar); ! 366: if (c <= 0) ! 367: { ! 368: c = 0; ! 369: e->eof++; ! 370: } ! 371: else ! 372: { ! 373: if (e->rawnewline) ! 374: e->prevchar = NEWLINE; ! 375: e->rawnewline = (c == NEWLINE); ! 376: } ! 377: } ! 378: } ! 379: ! 380: /* test for escapable character */ ! 381: if (escapech) ! 382: { ! 383: switch (c) ! 384: { ! 385: case 't': /* become quoted tab */ ! 386: c = TAB | QUOTED; ! 387: break; ! 388: ! 389: case 'n': /* become quoted newline */ ! 390: c = NEWLINE | QUOTED; ! 391: break; ! 392: ! 393: default: ! 394: bufput(c, &e->pbuf); ! 395: c = BACKSLASH; ! 396: } ! 397: escapech = 0; ! 398: } ! 399: else ! 400: { ! 401: if (c == BACKSLASH) ! 402: { ! 403: escapech++; ! 404: continue; ! 405: } ! 406: } ! 407: break; ! 408: } ! 409: ! 410: /* quote the character if appropriate to mask change flag */ ! 411: /* ('escapech' now becomes the maybe quoted character) */ ! 412: escapech = c; ! 413: if (quote && c != 0) ! 414: escapech |= QUOTED; ! 415: ! 416: /* set change flag */ ! 417: macschng(escapech); ! 418: ! 419: if (c != 0) ! 420: { ! 421: /* save the character in the macro buffer */ ! 422: bufput(escapech, &e->mbuf); ! 423: } ! 424: ! 425: return (c); ! 426: } ! 427: /* ! 428: ** MACSCHNG -- set change flag and compute token type ! 429: ** ! 430: ** The change flag and token type is set. This does some tricky ! 431: ** stuff to determine just when a new token begins. Most notably, ! 432: ** notice that quoted stuff IS scanned, but the change flag is ! 433: ** reset in a higher level routine so that quoted stuff looks ! 434: ** like a single token, but any begin/end quote causes a token ! 435: ** change. ! 436: */ ! 437: ! 438: macschng(ch) ! 439: char ch; ! 440: { ! 441: register struct env *e; ! 442: register char c; ! 443: register int thismode; ! 444: int changeflag; ! 445: ! 446: e = Macenv; ! 447: c = ch; ! 448: changeflag = 0; ! 449: thismode = macmode(c); ! 450: ! 451: switch (e->tokenmode) ! 452: { ! 453: case NONE: ! 454: /* always cause token change */ ! 455: break; ! 456: ! 457: case QUOTEMODE: ! 458: /* change only on initial entry to quotes */ ! 459: break; ! 460: ! 461: case DELIM: ! 462: changeflag++; ! 463: break; ! 464: ! 465: case ID: ! 466: /* take any sequence of letters and numerals */ ! 467: if (thismode == NUMBER) ! 468: thismode = ID; ! 469: break; ! 470: ! 471: case NUMBER: ! 472: /* take string of digits and decimal points */ ! 473: if (c == '.') ! 474: thismode = NUMBER; ! 475: break; ! 476: ! 477: case OP: ! 478: switch (e->prevchar) ! 479: { ! 480: case '<': ! 481: case '>': ! 482: case '!': ! 483: if (c != '=') ! 484: changeflag++; ! 485: break; ! 486: ! 487: case '*': ! 488: if (c != '*' && c != '/') ! 489: changeflag++; ! 490: break; ! 491: ! 492: case '/': ! 493: if (c != '*') ! 494: changeflag++; ! 495: break; ! 496: ! 497: case '.': ! 498: if (thismode == NUMBER) ! 499: e->tokenmode = thismode; ! 500: break; ! 501: ! 502: default: ! 503: changeflag++; ! 504: break; ! 505: } ! 506: break; ! 507: ! 508: case NOCHANGE: /* never cause token change */ ! 509: e->tokenmode = thismode; ! 510: break; ! 511: } ! 512: ! 513: e->prevchar = c; ! 514: if (thismode != e->tokenmode) ! 515: changeflag++; ! 516: e->tokenmode = thismode; ! 517: e->change = changeflag; ! 518: } ! 519: /* ! 520: ** MACMODE -- return mode of a character ! 521: */ ! 522: ! 523: macmode(ch) ! 524: char ch; ! 525: { ! 526: register char c; ! 527: ! 528: c = ch; ! 529: ! 530: if ((c & QUOTED) != 0) ! 531: return (QUOTEMODE); ! 532: if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_')) ! 533: return (ID); ! 534: if (c >= '0' && c <= '9') ! 535: return (NUMBER); ! 536: if (c == SPACE || c == TAB || c == NEWLINE) ! 537: return (DELIM); ! 538: return (OP); ! 539: } ! 540: /* ! 541: ** MACALLSCAN -- scan to see if input matches a macro ! 542: ** ! 543: ** Returns true if there was a match, false if not. In any case, ! 544: ** the virtual raw input (i.e., the peek buffer) will contain ! 545: ** either the old raw input, or the substituted macro. ! 546: */ ! 547: ! 548: macallscan() ! 549: { ! 550: register struct macro *m; ! 551: ! 552: for (m = Machead; m != 0; m = m->nextm) ! 553: { ! 554: /* check to see if it matches this macro */ ! 555: if (macscan(m)) ! 556: { ! 557: /* it does -- substituted value is in mbuf */ ! 558: macrescan(); ! 559: return (1); ! 560: } ! 561: ! 562: /* it doesn't match this macro -- try the next one */ ! 563: macrescan(); ! 564: } ! 565: ! 566: /* it doesn't match any of them -- tough luck */ ! 567: return (0); ! 568: } ! 569: /* ! 570: ** MACSCAN -- scan a single macro for a match ! 571: ** ! 572: ** As is scans it also collects parameters for possible future ! 573: ** substitution. If it finds a match, it takes responsibility ! 574: ** for doing the substitution. ! 575: */ ! 576: ! 577: macscan(mac) ! 578: struct macro *mac; ! 579: { ! 580: register struct macro *m; ! 581: register char c; ! 582: register char *temp; ! 583: char pname, pdelim; ! 584: ! 585: m = mac; ! 586: ! 587: /* check for anchored mode */ ! 588: temp = m->template; ! 589: if (*temp == ONEDELIM) ! 590: { ! 591: if (!Macenv->newline) ! 592: return (0); ! 593: temp++; ! 594: } ! 595: ! 596: /* scan the template */ ! 597: for ( ; c = *temp; temp++) ! 598: { ! 599: if (c == PARAMN || c == PARAMP) ! 600: { ! 601: /* we have a parameter */ ! 602: pname = *++temp; ! 603: pdelim = *++temp; ! 604: if (macparam(c, pname, pdelim)) ! 605: { ! 606: /* parameter ok */ ! 607: continue; ! 608: } ! 609: ! 610: /* failure on parameter scan */ ! 611: return (0); ! 612: } ! 613: ! 614: if (!macmatch(c)) ! 615: { ! 616: /* failure on literal match */ ! 617: return (0); ! 618: } ! 619: } ! 620: ! 621: /* it matches!! substitute the macro */ ! 622: macsubs(m); ! 623: return (1); ! 624: } ! 625: /* ! 626: ** MACPARAM -- collect a parameter ! 627: ** ! 628: ** The parameter is collected and stored away "somewhere" with ! 629: ** name 'name'. The delimiter is taken to be 'delim'. 'Mode' ! 630: ** tells whether to prescan the parameter (done immediately before ! 631: ** substitute time to avoid side effects if the macro actually ! 632: ** turns out to not match). ! 633: */ ! 634: ! 635: macparam(mode, name, delim) ! 636: char mode; ! 637: char name; ! 638: char delim; ! 639: { ! 640: register char c; ! 641: register struct env *e; ! 642: struct buf *b; ! 643: register struct param *p; ! 644: int bracecount; ! 645: extern char *bufalloc(),*bufcrunch(); ! 646: e = Macenv; ! 647: b = 0; ! 648: ! 649: e->pdelim = delim; ! 650: TRACE("\nmacparam(%d, %c, %c):\n", mode, name, delim); ! 651: if (mode == PARAMP) ! 652: { ! 653: /* check for REALLY prescan */ ! 654: c = macgch(); ! 655: if (c != PRESCANENABLE) ! 656: { ! 657: mode = PARAMN; ! 658: macunget(0); ! 659: } ! 660: } ! 661: ! 662: bracecount = 0; ! 663: e->tokenmode = NOCHANGE; ! 664: while (!macmatch(delim)) ! 665: { ! 666: do ! 667: { ! 668: c = macgch(); ! 669: if (c == 0 || c == NEWLINE) ! 670: { ! 671: e->pdelim = 0; ! 672: bufpurge(&b); ! 673: TRACE("macparam fails\n"); ! 674: return (0); ! 675: } ! 676: bufput(c, &b); ! 677: if (c == LBRACE) ! 678: bracecount++; ! 679: else if (c == RBRACE && bracecount > 0) ! 680: bracecount--; ! 681: } while (bracecount > 0); ! 682: } ! 683: ! 684: e->pdelim = 0; ! 685: ! 686: /* allocate and store the parameter */ ! 687: p = (struct param *) bufalloc(sizeof *p); ! 688: p->mode = mode; ! 689: p->name = name; ! 690: p->nextp = e->params; ! 691: e->params = p; ! 692: p->paramt = bufcrunch(&b); ! 693: bufpurge(&b); ! 694: TRACE("macparam: |%s|\n", p->paramt); ! 695: ! 696: return (1); ! 697: } ! 698: /* ! 699: ** MACMATCH -- test for a match between template character and input. ! 700: ** ! 701: ** The parameter is the character from the template to match on. ! 702: ** The input is read. The template character may be a meta- ! 703: ** character. In all cases if the match occurs the input is ! 704: ** thrown away; if no match occurs the input is left unchanged. ! 705: ** ! 706: ** Return value is true for a match, false for no match. ! 707: */ ! 708: ! 709: macmatch(template) ! 710: char template; ! 711: { ! 712: register char t; ! 713: register char c; ! 714: register int res; ! 715: ! 716: t = template; ! 717: TRACE("\tmacmatch(%c)", t); ! 718: ! 719: switch (t) ! 720: { ! 721: case ANYDELIM: /* match zero or more delimiters */ ! 722: /* chew and chuck delimiters */ ! 723: while (macdelim()) ! 724: ; ! 725: ! 726: /* as a side effect, must match a token change */ ! 727: if (!macckch()) ! 728: { ! 729: TRACE(" fail\n"); ! 730: return (0); ! 731: } ! 732: TRACE(" succeed\n"); ! 733: return (1); ! 734: ! 735: case ONEDELIM: /* match exactly one delimiter */ ! 736: TRACE(":\n"); ! 737: res = macdelim(); ! 738: return (res); ! 739: ! 740: case CHANGE: /* match a token change */ ! 741: case 0: /* end of template */ ! 742: TRACE(":\n"); ! 743: res = macckch(); ! 744: return (res); ! 745: ! 746: default: /* must have exact character match */ ! 747: c = macgch(); ! 748: TRACE(" against %c ", c); ! 749: if (c == t) ! 750: { ! 751: TRACE("succeed\n"); ! 752: return (1); ! 753: } ! 754: ! 755: /* failure */ ! 756: macunget(0); ! 757: TRACE("fail\n"); ! 758: return (0); ! 759: } ! 760: } ! 761: /* ! 762: ** MACDELIM -- test for next input character a delimiter ! 763: ** ! 764: ** Returns true if the next input character is a delimiter, false ! 765: ** otherwise. Delimiters are chewed. ! 766: */ ! 767: ! 768: macdelim() ! 769: { ! 770: register char c; ! 771: ! 772: c = macgch(); ! 773: TRACE("\t\tmacdelim against %c: ", c); ! 774: if (macmode(c) == DELIM) ! 775: { ! 776: TRACE("succeed\n"); ! 777: return (1); ! 778: } ! 779: macunget(0); ! 780: TRACE("fail\n"); ! 781: return (0); ! 782: } ! 783: /* ! 784: ** MACCKCH -- check for token change ! 785: ** ! 786: ** Returns true if a token change occurs between this and the next ! 787: ** character. No characters are ever chewed, however, the token ! 788: ** change (if it exists) is always chewed. ! 789: */ ! 790: ! 791: macckch() ! 792: { ! 793: register int change; ! 794: register char c; ! 795: register struct env *e; ! 796: ! 797: e = Macenv; ! 798: ! 799: if (e->tokenmode == NONE) ! 800: { ! 801: /* then last character has been ungotten: take old change */ ! 802: change = e->change; ! 803: } ! 804: else ! 805: { ! 806: c = macgch(); ! 807: change = Macenv->change; ! 808: macunget(0); ! 809: } ! 810: TRACE("macckch got %c ret %d\n", c, change); ! 811: ! 812: /* chew the change and return */ ! 813: e->tokenmode = NOCHANGE; ! 814: return (change); ! 815: } ! 816: /* ! 817: ** MACSUBS -- substitute in macro substitution ! 818: ** ! 819: ** This routine prescans appropriate parameters and then either ! 820: ** loads the substitution into the macro buffer or calls the ! 821: ** correct primitive routine. ! 822: */ ! 823: ! 824: macsubs(mac) ! 825: struct macro *mac; ! 826: { ! 827: register struct param *p; ! 828: register struct env *e; ! 829: register char *s; ! 830: char *macprim(); ! 831: ! 832: e = Macenv; ! 833: ! 834: for (p = e->params; p != 0; p = p->nextp) ! 835: { ! 836: /* check to see if we should prescan */ ! 837: if (p->mode != PARAMP) ! 838: { ! 839: continue; ! 840: } ! 841: ! 842: /* prescan parameter */ ! 843: macprescan(&p->paramt); ! 844: p->mode = PARAMN; ! 845: } ! 846: ! 847: s = mac->substitute; ! 848: ! 849: /* clear out the macro call */ ! 850: bufflush(&e->mbuf); ! 851: ! 852: if (s <= (char *) NPRIMS) ! 853: { ! 854: /* it is a primitive */ ! 855: macload(macprim(s), 0); ! 856: } ! 857: else ! 858: { ! 859: /* it is a user-defined macro */ ! 860: macload(s, 1); ! 861: } ! 862: } ! 863: /* ! 864: ** MACPRESCAN -- prescan a parameter ! 865: ** ! 866: ** The parameter pointed to by 'pp' is fed once through the macro ! 867: ** processor and replaced with the new version. ! 868: */ ! 869: ! 870: macprescan(pp) ! 871: char **pp; ! 872: { ! 873: struct buf *b; ! 874: char *p; ! 875: register struct env *e; ! 876: register char c; ! 877: extern int macsget(); ! 878: ! 879: b = 0; ! 880: p = *pp; ! 881: ! 882: /* set up a new environment */ ! 883: macnewev(macsget, &p); ! 884: e = Macenv; ! 885: ! 886: /* scan the parameter */ ! 887: while ((c = macgetch()) != 0) ! 888: bufput(c, &b); ! 889: ! 890: /* free the old parameter */ ! 891: buffree(*pp); ! 892: ! 893: /* move in the new one */ ! 894: *pp = bufcrunch(&b); ! 895: bufpurge(&b); ! 896: ! 897: /* restore the old environment */ ! 898: macpopev(); ! 899: } ! 900: /* ! 901: ** MACNEWEV -- set up new environment ! 902: ** ! 903: ** Parameters are raw get routine and parameter ! 904: */ ! 905: ! 906: macnewev(rawget, rawpar) ! 907: int (*rawget)(); ! 908: char **rawpar; ! 909: { ! 910: register struct env *e; ! 911: extern char *bufalloc(); ! 912: ! 913: e = (struct env *) bufalloc(sizeof *e); ! 914: e->rawget = rawget; ! 915: e->rawpar = rawpar; ! 916: e->nexte = Macenv; ! 917: e->newline = 1; ! 918: Macenv = e; ! 919: } ! 920: /* ! 921: ** MACPOPEV -- pop an environment ! 922: ** ! 923: ** Makes sure all buffers and stuff are purged ! 924: */ ! 925: ! 926: macpopev() ! 927: { ! 928: register struct env *e; ! 929: ! 930: e = Macenv; ! 931: bufpurge(&e->mbuf); ! 932: bufpurge(&e->pbuf); ! 933: macpflush(e); ! 934: Macenv = e->nexte; ! 935: buffree(e); ! 936: } ! 937: /* ! 938: ** MACPFLUSH -- flush all parameters ! 939: ** ! 940: ** Used to deallocate all parameters in a given environment. ! 941: */ ! 942: ! 943: macpflush(env) ! 944: struct env *env; ! 945: { ! 946: register struct env *e; ! 947: register struct param *p; ! 948: register struct param *q; ! 949: ! 950: e = env; ! 951: ! 952: for (p = e->params; p != 0; p = q) ! 953: { ! 954: buffree(p->paramt); ! 955: q = p->nextp; ! 956: buffree(p); ! 957: } ! 958: ! 959: e->params = 0; ! 960: } ! 961: /* ! 962: ** MACSGET -- get from string ! 963: ** ! 964: ** Works like a getchar from a string. Used by macprescan(). ! 965: ** The parameter is a pointer to the string. ! 966: */ ! 967: ! 968: macsget(pp) ! 969: char **pp; ! 970: { ! 971: register char **p; ! 972: register int c; ! 973: ! 974: p = pp; ! 975: ! 976: c = **p & BYTEMASK; ! 977: if (c != 0) ! 978: (*p)++; ! 979: return (c); ! 980: } ! 981: /* ! 982: ** MACLOAD -- load a string into the macro buffer ! 983: ** ! 984: ** The parameters are a pointer to a string to be appended to ! 985: ** the macro buffer and a flag telling whether parameter substi- ! 986: ** tution can occur. ! 987: */ ! 988: ! 989: macload(str, flag) ! 990: char *str; ! 991: int flag; ! 992: { ! 993: register struct env *e; ! 994: register char *s; ! 995: register char c; ! 996: extern char *macplkup(); ! 997: ! 998: e = Macenv; ! 999: s = str; ! 1000: ! 1001: if (s == 0) ! 1002: return; ! 1003: ! 1004: while ((c = *s++) != 0) ! 1005: { ! 1006: if (c == PARAMN) ! 1007: macload(macplkup(*s++), 0); ! 1008: else ! 1009: bufput(c & CHARMASK, &e->mbuf); ! 1010: } ! 1011: } ! 1012: /* ! 1013: ** MACRESCAN -- rescan the macro buffer ! 1014: ** ! 1015: ** Copies the macro buffer into the peek buffer so that it will be ! 1016: ** reread. Also deallocates any parameters which may happen to be ! 1017: ** stored away. ! 1018: */ ! 1019: ! 1020: macrescan() ! 1021: { ! 1022: register struct env *e; ! 1023: register char c; ! 1024: ! 1025: e = Macenv; ! 1026: ! 1027: while ((c = bufget(&e->mbuf) & CHARMASK) != 0) ! 1028: bufput(c, &e->pbuf); ! 1029: ! 1030: e->quotelevel = 0; ! 1031: e->tokenmode = NONE; ! 1032: macpflush(e); ! 1033: } ! 1034: /* ! 1035: ** MACUNGET -- unget a character ! 1036: ** ! 1037: ** Moves one character from the macro buffer to the peek buffer. ! 1038: ** If 'mask' is set, the character has the quote bit stripped off. ! 1039: */ ! 1040: ! 1041: macunget(mask) ! 1042: int mask; ! 1043: { ! 1044: register struct env *e; ! 1045: register char c; ! 1046: ! 1047: e = Macenv; ! 1048: ! 1049: if (e->prevchar != 0) ! 1050: { ! 1051: c = bufget(&e->mbuf); ! 1052: if (mask) ! 1053: c &= CHARMASK; ! 1054: bufput(c, &e->pbuf); ! 1055: e->tokenmode = NONE; ! 1056: } ! 1057: } ! 1058: /* ! 1059: ** MACPLKUP -- look up parameter ! 1060: ** ! 1061: ** Returns a pointer to the named parameter. Returns null ! 1062: ** if the parameter is not found ("cannot happen"). ! 1063: */ ! 1064: ! 1065: char * ! 1066: macplkup(name) ! 1067: char name; ! 1068: { ! 1069: register struct param *p; ! 1070: ! 1071: for (p = Macenv->params; p != 0; p = p->nextp) ! 1072: { ! 1073: if (p->name == name) ! 1074: return (p->paramt); ! 1075: } ! 1076: ! 1077: return (0); ! 1078: } ! 1079: /* ! 1080: ** MACSPRING -- spring a trap ! 1081: ** ! 1082: ** The named trap is sprung, in other words, if the named macro is ! 1083: ** defined it is called, otherwise there is no replacement text. ! 1084: */ ! 1085: ! 1086: macspring(trap) ! 1087: char *trap; ! 1088: { ! 1089: register struct env *e; ! 1090: register char *p; ! 1091: char *macro(); ! 1092: ! 1093: e = Macenv; ! 1094: ! 1095: bufflush(&e->mbuf); ! 1096: ! 1097: /* fetch the macro */ ! 1098: p = macro(trap); ! 1099: ! 1100: /* if not defined, don't bother */ ! 1101: if (p == 0) ! 1102: return; ! 1103: ! 1104: /* load the trap */ ! 1105: macload(p); ! 1106: ! 1107: /* insert a newline after the trap */ ! 1108: bufput('\n', &e->mbuf); ! 1109: ! 1110: macrescan(); ! 1111: } ! 1112: /* ! 1113: ** MACPRIM -- do primitives ! 1114: ** ! 1115: ** The parameter is the primitive to execute. ! 1116: */ ! 1117: ! 1118: char * ! 1119: macprim(n) ! 1120: int n; ! 1121: { ! 1122: register struct env *e; ! 1123: extern char *macplkup(); ! 1124: extern char *macsstr(); ! 1125: ! 1126: e = Macenv; ! 1127: ! 1128: switch (n) ! 1129: { ! 1130: case 1: /* {define; $t; $s} */ ! 1131: macdnl(); ! 1132: macdefine(macplkup('t'), macplkup('s'), 0); ! 1133: break; ! 1134: ! 1135: case 2: /* {rawdefine; $t; $s} */ ! 1136: macdnl(); ! 1137: macdefine(macplkup('t'), macplkup('s'), 1); ! 1138: break; ! 1139: ! 1140: case 3: /* {remove $t} */ ! 1141: macdnl(); ! 1142: macremove(macplkup('t')); ! 1143: break; ! 1144: ! 1145: case 4: /* {dump} */ ! 1146: /* {dump; $n} */ ! 1147: macdnl(); ! 1148: macdump(macplkup('n')); ! 1149: break; ! 1150: ! 1151: case 5: /* {type $m} */ ! 1152: macdnl(); ! 1153: printf("%s\n", macplkup('m')); ! 1154: break; ! 1155: ! 1156: case 6: /* {read $m} */ ! 1157: printf("%s ", macplkup('m')); ! 1158: macread(); ! 1159: break; ! 1160: ! 1161: case 7: /* {read; $n; $m} */ ! 1162: printf("%s ", macplkup('m')); ! 1163: macread(); ! 1164: macdefine(macplkup('n'), bufcrunch(&e->mbuf), 1); ! 1165: return("{readcount}"); ! 1166: ! 1167: case 8: /* {ifsame; $a; $b; $t; $f} */ ! 1168: if (sequal(macplkup('a'), macplkup('b'))) ! 1169: return (macplkup('t')); ! 1170: else ! 1171: return (macplkup('f')); ! 1172: ! 1173: case 9: /* {ifeq; $a; $b; $t; $f} */ ! 1174: if (macnumber(macplkup('a')) == macnumber(macplkup('b'))) ! 1175: return (macplkup('t')); ! 1176: else ! 1177: return (macplkup('f')); ! 1178: ! 1179: case 10: /* {ifgt; $a; $b; $t; $f} */ ! 1180: if (macnumber(macplkup('a')) > macnumber(macplkup('b'))) ! 1181: return (macplkup('t')); ! 1182: else ! 1183: return (macplkup('f')); ! 1184: ! 1185: case 12: /* {substr; $f; $t; $s} */ ! 1186: return (macsstr(macnumber(macplkup('f')), macnumber(macplkup('t')), macplkup('s'))); ! 1187: ! 1188: case 13: /* {dnl} */ ! 1189: macdnl(); ! 1190: break; ! 1191: ! 1192: default: ! 1193: syserr("macro: bad primitive %d", n); ! 1194: } ! 1195: ! 1196: return (""); ! 1197: } ! 1198: /* ! 1199: ** MACDNL -- delete to newline ! 1200: ** ! 1201: ** Used in general after macro definitions to avoid embarrassing ! 1202: ** newlines. Just reads input until a newline character, and ! 1203: ** then throws it away. ! 1204: */ ! 1205: ! 1206: macdnl() ! 1207: { ! 1208: register char c; ! 1209: register struct env *e; ! 1210: ! 1211: e = Macenv; ! 1212: ! 1213: while ((c = macgch()) != 0 && c != NEWLINE) ! 1214: ; ! 1215: ! 1216: bufflush(&e->mbuf); ! 1217: } ! 1218: /* ! 1219: ** MACDEFINE -- define primitive ! 1220: ** ! 1221: ** This function defines a macro. The parameters are the ! 1222: ** template, the substitution string, and a flag telling whether ! 1223: ** this is a raw define or not. Syntax checking is done. ! 1224: */ ! 1225: ! 1226: macdefine(template, subs, raw) ! 1227: char *template; ! 1228: char *subs; ! 1229: int raw; ! 1230: { ! 1231: register struct env *e; ! 1232: char paramdefined[128]; ! 1233: char *p; ! 1234: register char c; ! 1235: char d; ! 1236: struct buf *b; ! 1237: register struct macro *m; ! 1238: extern int macsget(); ! 1239: extern char *bufalloc(),*bufcrunch(); ! 1240: char *mactcvt(); ! 1241: int escapech; ! 1242: ! 1243: /* remove any old macro definition */ ! 1244: macremove(template); ! 1245: ! 1246: /* get a new environment */ ! 1247: macnewev(macsget, &p); ! 1248: b = 0; ! 1249: e = Macenv; ! 1250: ! 1251: /* undefine all parameters */ ! 1252: clrmem(paramdefined, 128); ! 1253: ! 1254: /* avoid an initial token change */ ! 1255: e->tokenmode = NOCHANGE; ! 1256: escapech = 1; ! 1257: ! 1258: /* allocate macro header and template */ ! 1259: m = (struct macro *) bufalloc(sizeof *m); ! 1260: ! 1261: /* scan and convert template, collect available parameters */ ! 1262: p = template; ! 1263: m->template = mactcvt(raw, paramdefined); ! 1264: if (m->template == 0) ! 1265: { ! 1266: /* some sort of syntax error */ ! 1267: buffree(m); ! 1268: macpopev(); ! 1269: return; ! 1270: } ! 1271: ! 1272: bufflush(&e->mbuf); ! 1273: bufflush(&e->pbuf); ! 1274: e->eof = 0; ! 1275: ! 1276: /* scan substitute string */ ! 1277: for (p = subs; c = macfetch(0); ) ! 1278: { ! 1279: if (c != '$') ! 1280: { ! 1281: /* substitute non-parameters literally */ ! 1282: bufput(c & CHARMASK, &b); ! 1283: continue; ! 1284: } ! 1285: ! 1286: /* it's a parameter */ ! 1287: bufput(PARAMN, &b); ! 1288: c = macfetch(0); ! 1289: ! 1290: /* check to see if name is supplied */ ! 1291: if (paramdefined[c] == 0) ! 1292: { ! 1293: /* nope, it's not */ ! 1294: printf("define: parameter %c referenced but not defined\n", c); ! 1295: buffree(m->template); ! 1296: buffree(m); ! 1297: macpopev(); ! 1298: bufpurge(&b); ! 1299: return; ! 1300: } ! 1301: bufput(c & CHARMASK, &b); ! 1302: } ! 1303: ! 1304: /* allocate substitution string */ ! 1305: m->substitute = bufcrunch(&b); ! 1306: ! 1307: /* allocate it as a macro */ ! 1308: m->nextm = Machead; ! 1309: Machead = m; ! 1310: ! 1311: /* finished... */ ! 1312: macpopev(); ! 1313: bufpurge(&b); ! 1314: } ! 1315: /* ! 1316: ** MACTCVT -- convert template to internal form ! 1317: ** ! 1318: ** Converts the template from external form to internal form. ! 1319: ** ! 1320: ** Parameters: ! 1321: ** raw -- set if only raw type conversion should take place. ! 1322: ** paramdefined -- a map of flags to determine declaration of ! 1323: ** parameters, etc. If zero, no parameters are allowed. ! 1324: ** ! 1325: ** Return value: ! 1326: ** A character pointer off into mystic space. ! 1327: ** ! 1328: ** The characters of the template are read using macfetch, so ! 1329: ** a new environment should be created which will arrange to ! 1330: ** get this. ! 1331: */ ! 1332: ! 1333: char * ! 1334: mactcvt(raw, paramdefined) ! 1335: int raw; ! 1336: char paramdefined[128]; ! 1337: { ! 1338: register int c; ! 1339: struct buf *b; ! 1340: register char d; ! 1341: register int escapech; ! 1342: char *p; ! 1343: ! 1344: b = 0; ! 1345: escapech = 1; ! 1346: ! 1347: while (c = macfetch(0)) ! 1348: { ! 1349: switch (c) ! 1350: { ! 1351: case '$': /* parameter */ ! 1352: if (escapech < 0) ! 1353: { ! 1354: printf("define: every parameter needs a delimiter\n"); ! 1355: bufpurge(&b); ! 1356: return (0); ! 1357: } ! 1358: ! 1359: /* skip delimiters before parameter in non-raw */ ! 1360: if (Macenv->change && !escapech && !raw) ! 1361: bufput(ANYDELIM, &b); ! 1362: ! 1363: escapech = 0; ! 1364: c = macfetch(0); ! 1365: d = PARAMN; ! 1366: if (c == '$') ! 1367: { ! 1368: /* prescanned parameter */ ! 1369: d = PARAMP; ! 1370: c = macfetch(0); ! 1371: } ! 1372: ! 1373: /* process parameter name */ ! 1374: if (c == 0) ! 1375: { ! 1376: /* no parameter name */ ! 1377: printf("define: null parameter name\n"); ! 1378: bufpurge(&b); ! 1379: return (0); ! 1380: } ! 1381: ! 1382: bufput(d, &b); ! 1383: escapech = -1; ! 1384: ! 1385: /* check for legal parameter */ ! 1386: if (paramdefined == 0) ! 1387: break; ! 1388: ! 1389: if (paramdefined[c]) ! 1390: { ! 1391: printf("define: parameter %c redeclared\n", c); ! 1392: bufpurge(&b); ! 1393: return (0); ! 1394: } ! 1395: paramdefined[c]++; ! 1396: ! 1397: /* get parameter delimiter */ ! 1398: break; ! 1399: ! 1400: case BACKSLASH: /* a backslash escape */ ! 1401: escapech = 1; ! 1402: c = macfetch(0); ! 1403: switch (c) ! 1404: { ! 1405: case '|': ! 1406: c = ANYDELIM; ! 1407: break; ! 1408: ! 1409: case '^': ! 1410: c = ONEDELIM; ! 1411: break; ! 1412: ! 1413: case '&': ! 1414: c = CHANGE; ! 1415: break; ! 1416: ! 1417: default: ! 1418: escapech = 0; ! 1419: c = BACKSLASH; ! 1420: macunget(0); ! 1421: break; ! 1422: } ! 1423: break; ! 1424: ! 1425: case NEWLINE | QUOTED: ! 1426: case TAB | QUOTED: ! 1427: case SPACE | QUOTED: ! 1428: if (escapech < 0) ! 1429: c &= CHARMASK; ! 1430: escapech = 1; ! 1431: break; ! 1432: ! 1433: default: ! 1434: /* change delimiters to ANYDELIM */ ! 1435: if (macmode(c) == DELIM && !raw) ! 1436: { ! 1437: while (macmode(c = macfetch(0)) == DELIM) ! 1438: ; ! 1439: macunget(0); ! 1440: if (c == 0) ! 1441: c = ONEDELIM; ! 1442: else ! 1443: c = ANYDELIM; ! 1444: escapech = 1; ! 1445: } ! 1446: else ! 1447: { ! 1448: if (Macenv->change && !escapech) ! 1449: { ! 1450: bufput(ANYDELIM, &b); ! 1451: } ! 1452: ! 1453: if (escapech < 0) ! 1454: { ! 1455: /* parameter: don't allow quoted delimiters */ ! 1456: c &= CHARMASK; ! 1457: } ! 1458: escapech = 0; ! 1459: } ! 1460: break; ! 1461: } ! 1462: bufput(c, &b); ! 1463: } ! 1464: if (escapech <= 0) ! 1465: bufput(CHANGE, &b); ! 1466: ! 1467: p = bufcrunch(&b); ! 1468: bufpurge(&b); ! 1469: TRACE("mactcvt: '%s'\n", p); ! 1470: return (p); ! 1471: } ! 1472: /* ! 1473: ** MACREMOVE -- remove macro ! 1474: ** ! 1475: ** The named macro is looked up. If it is found it is removed ! 1476: ** from the macro list. ! 1477: */ ! 1478: ! 1479: macremove(name) ! 1480: char *name; ! 1481: { ! 1482: register struct macro *m; ! 1483: register struct macro **mp; ! 1484: extern int macsget(); ! 1485: char *p; ! 1486: register char *cname; ! 1487: struct macro *macmlkup(); ! 1488: ! 1489: if (name != 0) ! 1490: { ! 1491: /* convert name to internal format */ ! 1492: macnewev(macsget, &p); ! 1493: p = name; ! 1494: cname = mactcvt(0, 0); ! 1495: macpopev(); ! 1496: if (cname == 0) ! 1497: { ! 1498: /* some sort of syntax error */ ! 1499: return; ! 1500: } ! 1501: } ! 1502: ! 1503: /* find macro */ ! 1504: while (name == 0 ? ((m = Machead)->substitute > (char *) NPRIMS) : ((m = macmlkup(cname)) != 0)) ! 1505: { ! 1506: /* remove macro from list */ ! 1507: mp = &Machead; ! 1508: ! 1509: /* find it's parent */ ! 1510: while (*mp != m) ! 1511: mp = &(*mp)->nextm; ! 1512: ! 1513: /* remove macro from list */ ! 1514: *mp = m->nextm; ! 1515: buffree(m->template); ! 1516: buffree(m->substitute); ! 1517: buffree(m); ! 1518: } ! 1519: buffree(cname); ! 1520: } ! 1521: /* ! 1522: ** MACMLKUP -- look up macro ! 1523: ** ! 1524: ** The named macro is looked up and a pointer to the macro header ! 1525: ** is returned. Zero is returned if the macro is not found. ! 1526: ** The name must be in internal form. ! 1527: */ ! 1528: ! 1529: struct macro * ! 1530: macmlkup(name) ! 1531: char *name; ! 1532: { ! 1533: register struct macro *m; ! 1534: register char *n; ! 1535: ! 1536: n = name; ! 1537: ! 1538: /* scan the macro list for it */ ! 1539: for (m = Machead; m != 0; m = m->nextm) ! 1540: { ! 1541: if (macmmatch(n, m->template, 0)) ! 1542: return (m); ! 1543: } ! 1544: return (0); ! 1545: } ! 1546: /* ! 1547: ** MACMMATCH -- check for macro name match ! 1548: ** ! 1549: ** The given 'name' and 'temp' are compared for equality. If they ! 1550: ** match true is returned, else false. ! 1551: ** Both must be converted to internal format before the call is ! 1552: ** given. ! 1553: ** ! 1554: ** "Match" is defined as two macros which might scan as equal. ! 1555: ** ! 1556: ** 'Flag' is set to indicate that the macros must match exactly, ! 1557: ** that is, neither may have any parameters and must end with both ! 1558: ** at end-of-template. This mode is used for getting traps and ! 1559: ** such. ! 1560: */ ! 1561: ! 1562: macmmatch(name, temp, flag) ! 1563: char *name; ! 1564: char *temp; ! 1565: int flag; ! 1566: { ! 1567: register char ac; ! 1568: register char bc; ! 1569: char *ap, *bp; ! 1570: ! 1571: ap = name; ! 1572: bp = temp; ! 1573: ! 1574: /* scan character by character */ ! 1575: for (;; ap++, bp++) ! 1576: { ! 1577: ac = *ap; ! 1578: bc = *bp; ! 1579: TRACE("macmmatch: ac=%c/%u, bc=%c/%u\n", ac, ap, bc, bp); ! 1580: ! 1581: if (bc == ANYDELIM) ! 1582: { ! 1583: if (macmmchew(&ap)) ! 1584: continue; ! 1585: } ! 1586: else ! 1587: { ! 1588: switch (ac) ! 1589: { ! 1590: case SPACE: ! 1591: case NEWLINE: ! 1592: case TAB: ! 1593: if (ac == bc || bc == ONEDELIM) ! 1594: continue; ! 1595: break; ! 1596: ! 1597: case ONEDELIM: ! 1598: if (ac == bc || macmode(bc) == DELIM) ! 1599: continue; ! 1600: break; ! 1601: ! 1602: case ANYDELIM: ! 1603: if (macmmchew(&bp)) ! 1604: continue; ! 1605: break; ! 1606: ! 1607: case PARAMP: ! 1608: case PARAMN: ! 1609: case 0: ! 1610: if (bc == PARAMN || bc == PARAMP || bc == 0 || ! 1611: bc == ANYDELIM || bc == ONEDELIM || ! 1612: bc == CHANGE || macmode(bc) == DELIM) ! 1613: { ! 1614: /* success */ ! 1615: if (!flag) ! 1616: return (1); ! 1617: if (ac == 0 && bc == 0) ! 1618: return (1); ! 1619: } ! 1620: break; ! 1621: ! 1622: default: ! 1623: if (ac == bc) ! 1624: continue; ! 1625: break; ! 1626: } ! 1627: } ! 1628: ! 1629: /* failure */ ! 1630: return (0); ! 1631: } ! 1632: } ! 1633: /* ! 1634: ** MACMMCHEW -- chew nonspecific match characters ! 1635: ** ! 1636: ** The pointer passed as parameter is scanned so as to skip over ! 1637: ** delimiters and pseudocharacters. ! 1638: ** At least one character must match. ! 1639: */ ! 1640: ! 1641: macmmchew(pp) ! 1642: char **pp; ! 1643: { ! 1644: register char *p; ! 1645: register char c; ! 1646: register int matchflag; ! 1647: ! 1648: p = *pp; ! 1649: ! 1650: for (matchflag = 0; ; matchflag++) ! 1651: { ! 1652: c = *p; ! 1653: if (c != ANYDELIM && c != ONEDELIM && c != CHANGE && ! 1654: macmode(c) != DELIM) ! 1655: break; ! 1656: p++; ! 1657: } ! 1658: ! 1659: p--; ! 1660: if (matchflag == 0) ! 1661: return (0); ! 1662: *pp = p; ! 1663: return (1); ! 1664: } ! 1665: /* ! 1666: ** MACREAD -- read a terminal input line ! 1667: ** ! 1668: ** Reads one line from the user. Returns the line into mbuf, ! 1669: ** and a count of the number of characters read into the macro ! 1670: ** "{readcount}" (-1 for end of file). ! 1671: */ ! 1672: ! 1673: macread() ! 1674: { ! 1675: register struct env *e; ! 1676: register int count; ! 1677: register char c; ! 1678: ! 1679: e = Macenv; ! 1680: count = -1; ! 1681: ! 1682: while ((c = getchar()) > 0) ! 1683: { ! 1684: count++; ! 1685: if (c == NEWLINE) ! 1686: break; ! 1687: bufput(c, &e->mbuf); ! 1688: } ! 1689: ! 1690: macdefine("{readcount}", iocv(count), 1); ! 1691: } ! 1692: /* ! 1693: ** MACNUMBER -- return converted number ! 1694: ** ! 1695: ** This procedure is essentially identical to the system atoi ! 1696: ** routine, in that it does no syntax checking whatsoever. ! 1697: */ ! 1698: ! 1699: macnumber(s) ! 1700: char *s; ! 1701: { ! 1702: register char *p; ! 1703: register char c; ! 1704: register int result; ! 1705: int minus; ! 1706: ! 1707: result = 0; ! 1708: p = s; ! 1709: minus = 0; ! 1710: ! 1711: while ((c = *p++) == SPACE) ! 1712: ; ! 1713: ! 1714: if (c == '-') ! 1715: { ! 1716: minus++; ! 1717: while ((c = *p++) == SPACE) ! 1718: ; ! 1719: } ! 1720: ! 1721: while (c >= '0' && c <= '9') ! 1722: { ! 1723: result = result * 10 + (c - '0'); ! 1724: c = *p++; ! 1725: } ! 1726: ! 1727: if (minus) ! 1728: result = -result; ! 1729: ! 1730: return (result); ! 1731: } ! 1732: /* ! 1733: ** MACSUBSTR -- substring primitive ! 1734: ** ! 1735: ** The substring of 'string' from 'from' to 'to' is extracted. ! 1736: ** A pointer to the result is returned. Note that macsstr ! 1737: ** in the general case modifies 'string' in place. ! 1738: */ ! 1739: ! 1740: char * ! 1741: macsstr(from, to, string) ! 1742: int from; ! 1743: int to; ! 1744: char *string; ! 1745: { ! 1746: register int f; ! 1747: int l; ! 1748: register char *s; ! 1749: register int t; ! 1750: ! 1751: s = string; ! 1752: t = to; ! 1753: f = from; ! 1754: ! 1755: if (f < 1) ! 1756: f = 1; ! 1757: ! 1758: if (f >= t) ! 1759: return (""); ! 1760: l = length(s); ! 1761: if (t < l) ! 1762: s[t] = 0; ! 1763: return (&s[f - 1]); ! 1764: } ! 1765: /* ! 1766: ** MACDUMP -- dump a macro definition to the terminal ! 1767: ** ! 1768: ** All macros matching 'name' are output to the buffer. If ! 1769: ** 'name' is the null pointer, all macros are printed. ! 1770: */ ! 1771: ! 1772: macdump(name) ! 1773: char *name; ! 1774: { ! 1775: register struct macro *m; ! 1776: register char *p; ! 1777: register char *n; ! 1778: extern int macsget(); ! 1779: extern char *macmocv(); ! 1780: char *ptr; ! 1781: ! 1782: n = name; ! 1783: if (n != 0) ! 1784: { ! 1785: macnewev(macsget, &ptr); ! 1786: ptr = n; ! 1787: n = mactcvt(0, 0); ! 1788: macpopev(); ! 1789: if (n == 0) ! 1790: return; ! 1791: } ! 1792: ! 1793: for (m = Machead; m != 0; m = m->nextm) ! 1794: { ! 1795: if (n == 0 || macmmatch(n, m->template, 0)) ! 1796: { ! 1797: if (m->substitute <= (char *) NPRIMS) ! 1798: continue; ! 1799: p = macmocv(m->template); ! 1800: macload("`{rawdefine; ", 0); ! 1801: macload(p, 0); ! 1802: macload("; ", 0); ! 1803: p = macmocv(m->substitute); ! 1804: macload(p, 0); ! 1805: macload("}'\n", 0); ! 1806: } ! 1807: } ! 1808: if (n != 0) ! 1809: buffree(n); ! 1810: } ! 1811: /* ! 1812: ** MACMOCV -- macro output conversion ! 1813: ** ! 1814: ** This routine converts the internal format of the named macro ! 1815: ** to an unambigous external representation. ! 1816: ** ! 1817: ** Note that much work can be done to this routine to make it ! 1818: ** produce cleaner output, for example, translate "\|" to " " ! 1819: ** in most cases. ! 1820: */ ! 1821: ! 1822: char * ! 1823: macmocv(m) ! 1824: char *m; ! 1825: { ! 1826: register char *p; ! 1827: struct buf *b; ! 1828: register int c; ! 1829: register int pc; ! 1830: static char *lastbuf; ! 1831: extern char *bufcrunch(); ! 1832: ! 1833: p = m; ! 1834: ! 1835: /* release last used buffer (as appropriate) */ ! 1836: if (lastbuf != 0) ! 1837: { ! 1838: buffree(lastbuf); ! 1839: lastbuf = 0; ! 1840: } ! 1841: ! 1842: if (p <= (char *) NPRIMS) ! 1843: { ! 1844: /* we have a primitive */ ! 1845: p = "Primitive xxx"; ! 1846: itoa(m, &p[10]); ! 1847: return (p); ! 1848: } ! 1849: ! 1850: b = 0; ! 1851: ! 1852: for (; (c = *p++) != 0; pc = c) ! 1853: { ! 1854: switch (c) ! 1855: { ! 1856: case BACKSLASH: ! 1857: case '|': ! 1858: case '&': ! 1859: case '^': ! 1860: break; ! 1861: ! 1862: case ANYDELIM: ! 1863: c = '\\|'; ! 1864: break; ! 1865: ! 1866: case ONEDELIM: ! 1867: c = '\\^'; ! 1868: break; ! 1869: ! 1870: case CHANGE: ! 1871: c = '\\&'; ! 1872: break; ! 1873: ! 1874: case PARAMN: ! 1875: c = '$'; ! 1876: break; ! 1877: ! 1878: case PARAMP: ! 1879: c = '$$'; ! 1880: break; ! 1881: ! 1882: case '$': ! 1883: c = '\\$'; ! 1884: break; ! 1885: ! 1886: case NEWLINE: ! 1887: c = ('\\' | QUOTED) | ('\n' << 8); ! 1888: break; ! 1889: ! 1890: default: ! 1891: bufput(c, &b); ! 1892: continue; ! 1893: } ! 1894: ! 1895: if (pc == BACKSLASH) ! 1896: bufput(pc, &b); ! 1897: pc = c & CHARMASK; ! 1898: bufput(pc, &b); ! 1899: pc = (c >> 8) & CHARMASK; ! 1900: if (pc != 0) ! 1901: { ! 1902: c = pc; ! 1903: bufput(c, &b); ! 1904: } ! 1905: } ! 1906: ! 1907: p = bufcrunch(&b); ! 1908: bufpurge(&b); ! 1909: lastbuf = p; ! 1910: return (p); ! 1911: } ! 1912: /* ! 1913: ** MACRO -- get macro substitution value ! 1914: ** ! 1915: ** *** EXTERNAL INTERFACE *** ! 1916: ** ! 1917: ** This routine handles the rather specialized case of looking ! 1918: ** up a macro and returning the substitution value. The name ! 1919: ** must match EXACTLY, character for character. ! 1920: ** ! 1921: ** The null pointer is returned if the macro is not defined. ! 1922: */ ! 1923: ! 1924: char * ! 1925: macro(name) ! 1926: char *name; ! 1927: { ! 1928: register struct macro *m; ! 1929: register char *n; ! 1930: extern int macsget(); ! 1931: char *p; ! 1932: ! 1933: /* convert macro name to internal format */ ! 1934: macnewev(macsget, &p); ! 1935: p = name; ! 1936: n = mactcvt(0, 0); ! 1937: macpopev(); ! 1938: if (n == 0) ! 1939: { ! 1940: /* some sort of syntax error */ ! 1941: return (0); ! 1942: } ! 1943: ! 1944: for (m = Machead; m != 0; m = m->nextm) ! 1945: { ! 1946: if (macmmatch(n, m->template, 1)) ! 1947: { ! 1948: buffree(n); ! 1949: return (m->substitute); ! 1950: } ! 1951: } ! 1952: ! 1953: buffree(n); ! 1954: return (0); ! 1955: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.