|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1989 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * Ozan Yigit. ! 7: * ! 8: * Redistribution and use in source and binary forms are permitted ! 9: * provided that: (1) source distributions retain this entire copyright ! 10: * notice and comment, and (2) distributions including binaries display ! 11: * the following acknowledgement: ``This product includes software ! 12: * developed by the University of California, Berkeley and its contributors'' ! 13: * in the documentation or other materials provided with the distribution ! 14: * and in all advertising materials mentioning features or use of this ! 15: * software. Neither the name of the University nor the names of its ! 16: * contributors may be used to endorse or promote products derived ! 17: * from this software without specific prior written permission. ! 18: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 19: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 20: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 21: */ ! 22: ! 23: #ifndef lint ! 24: static char sccsid[] = "@(#)main.c 5.4 (Berkeley) 6/1/90"; ! 25: #endif /* not lint */ ! 26: ! 27: /* ! 28: * main.c ! 29: * Facility: m4 macro processor ! 30: * by: oz ! 31: */ ! 32: ! 33: #include "mdef.h" ! 34: ! 35: /* ! 36: * m4 - macro processor ! 37: * ! 38: * PD m4 is based on the macro tool distributed with the software ! 39: * tools (VOS) package, and described in the "SOFTWARE TOOLS" and ! 40: * "SOFTWARE TOOLS IN PASCAL" books. It has been expanded to include ! 41: * most of the command set of SysV m4, the standard UN*X macro processor. ! 42: * ! 43: * Since both PD m4 and UN*X m4 are based on SOFTWARE TOOLS macro, ! 44: * there may be certain implementation similarities between ! 45: * the two. The PD m4 was produced without ANY references to m4 ! 46: * sources. ! 47: * ! 48: * References: ! 49: * ! 50: * Software Tools distribution: macro ! 51: * ! 52: * Kernighan, Brian W. and P. J. Plauger, SOFTWARE ! 53: * TOOLS IN PASCAL, Addison-Wesley, Mass. 1981 ! 54: * ! 55: * Kernighan, Brian W. and P. J. Plauger, SOFTWARE ! 56: * TOOLS, Addison-Wesley, Mass. 1976 ! 57: * ! 58: * Kernighan, Brian W. and Dennis M. Ritchie, ! 59: * THE M4 MACRO PROCESSOR, Unix Programmer's Manual, ! 60: * Seventh Edition, Vol. 2, Bell Telephone Labs, 1979 ! 61: * ! 62: * System V man page for M4 ! 63: * ! 64: * Modification History: ! 65: * ! 66: * Jan 28 1986 Oz Break the whole thing into little ! 67: * pieces, for easier (?) maintenance. ! 68: * ! 69: * Dec 12 1985 Oz Optimize the code, try to squeeze ! 70: * few microseconds out.. ! 71: * ! 72: * Dec 05 1985 Oz Add getopt interface, define (-D), ! 73: * undefine (-U) options. ! 74: * ! 75: * Oct 21 1985 Oz Clean up various bugs, add comment handling. ! 76: * ! 77: * June 7 1985 Oz Add some of SysV m4 stuff (m4wrap, pushdef, ! 78: * popdef, decr, shift etc.). ! 79: * ! 80: * June 5 1985 Oz Initial cut. ! 81: * ! 82: * Implementation Notes: ! 83: * ! 84: * [1] PD m4 uses a different (and simpler) stack mechanism than the one ! 85: * described in Software Tools and Software Tools in Pascal books. ! 86: * The triple stack nonsense is replaced with a single stack containing ! 87: * the call frames and the arguments. Each frame is back-linked to a ! 88: * previous stack frame, which enables us to rewind the stack after ! 89: * each nested call is completed. Each argument is a character pointer ! 90: * to the beginning of the argument string within the string space. ! 91: * The only exceptions to this are (*) arg 0 and arg 1, which are ! 92: * the macro definition and macro name strings, stored dynamically ! 93: * for the hash table. ! 94: * ! 95: * . . ! 96: * | . | <-- sp | . | ! 97: * +-------+ +-----+ ! 98: * | arg 3 ------------------------------->| str | ! 99: * +-------+ | . | ! 100: * | arg 2 --------------+ . ! 101: * +-------+ | ! 102: * * | | | ! 103: * +-------+ | +-----+ ! 104: * | plev | <-- fp +---------------->| str | ! 105: * +-------+ | . | ! 106: * | type | . ! 107: * +-------+ ! 108: * | prcf -----------+ plev: paren level ! 109: * +-------+ | type: call type ! 110: * | . | | prcf: prev. call frame ! 111: * . | ! 112: * +-------+ | ! 113: * | <----------+ ! 114: * +-------+ ! 115: * ! 116: * [2] We have three types of null values: ! 117: * ! 118: * nil - nodeblock pointer type 0 ! 119: * null - null string ("") ! 120: * NULL - Stdio-defined NULL ! 121: * ! 122: */ ! 123: ! 124: ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ ! 125: char buf[BUFSIZE]; /* push-back buffer */ ! 126: char *bp = buf; /* first available character */ ! 127: char *endpbb = buf+BUFSIZE; /* end of push-back buffer */ ! 128: stae mstack[STACKMAX+1]; /* stack of m4 machine */ ! 129: char strspace[STRSPMAX+1]; /* string space for evaluation */ ! 130: char *ep = strspace; /* first free char in strspace */ ! 131: char *endest= strspace+STRSPMAX;/* end of string space */ ! 132: int sp; /* current m4 stack pointer */ ! 133: int fp; /* m4 call frame pointer */ ! 134: FILE *infile[MAXINP]; /* input file stack (0=stdin) */ ! 135: FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ ! 136: FILE *active; /* active output file pointer */ ! 137: char *m4temp; /* filename for diversions */ ! 138: int ilevel = 0; /* input file stack pointer */ ! 139: int oindex = 0; /* diversion index.. */ ! 140: char *null = ""; /* as it says.. just a null.. */ ! 141: char *m4wraps = ""; /* m4wrap string default.. */ ! 142: char lquote = LQUOTE; /* left quote character (`) */ ! 143: char rquote = RQUOTE; /* right quote character (') */ ! 144: char scommt = SCOMMT; /* start character for comment */ ! 145: char ecommt = ECOMMT; /* end character for comment */ ! 146: struct keyblk keywrds[] = { /* m4 keywords to be installed */ ! 147: "include", INCLTYPE, ! 148: "sinclude", SINCTYPE, ! 149: "define", DEFITYPE, ! 150: "defn", DEFNTYPE, ! 151: "divert", DIVRTYPE, ! 152: "expr", EXPRTYPE, ! 153: "eval", EXPRTYPE, ! 154: "substr", SUBSTYPE, ! 155: "ifelse", IFELTYPE, ! 156: "ifdef", IFDFTYPE, ! 157: "len", LENGTYPE, ! 158: "incr", INCRTYPE, ! 159: "decr", DECRTYPE, ! 160: "dnl", DNLNTYPE, ! 161: "changequote", CHNQTYPE, ! 162: "changecom", CHNCTYPE, ! 163: "index", INDXTYPE, ! 164: #ifdef EXTENDED ! 165: "paste", PASTTYPE, ! 166: "spaste", SPASTYPE, ! 167: #endif ! 168: "popdef", POPDTYPE, ! 169: "pushdef", PUSDTYPE, ! 170: "dumpdef", DUMPTYPE, ! 171: "shift", SHIFTYPE, ! 172: "translit", TRNLTYPE, ! 173: "undefine", UNDFTYPE, ! 174: "undivert", UNDVTYPE, ! 175: "divnum", DIVNTYPE, ! 176: "maketemp", MKTMTYPE, ! 177: "errprint", ERRPTYPE, ! 178: "m4wrap", M4WRTYPE, ! 179: "m4exit", EXITTYPE, ! 180: "syscmd", SYSCTYPE, ! 181: "sysval", SYSVTYPE, ! 182: "unix", MACRTYPE, ! 183: }; ! 184: ! 185: #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) ! 186: ! 187: extern ndptr lookup(); ! 188: extern ndptr addent(); ! 189: extern int onintr(); ! 190: ! 191: extern char *malloc(); ! 192: extern char *mktemp(); ! 193: ! 194: extern int optind; ! 195: extern char *optarg; ! 196: ! 197: main(argc,argv) ! 198: char *argv[]; ! 199: { ! 200: register int c; ! 201: register int n; ! 202: char *p; ! 203: ! 204: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 205: signal(SIGINT, onintr); ! 206: #ifdef NONZEROPAGES ! 207: initm4(); ! 208: #endif ! 209: initkwds(); ! 210: ! 211: while ((c = getopt(argc, argv, "tD:U:o:")) != EOF) ! 212: switch(c) { ! 213: ! 214: case 'D': /* define something..*/ ! 215: for (p = optarg; *p; p++) ! 216: if (*p == '=') ! 217: break; ! 218: if (*p) ! 219: *p++ = EOS; ! 220: dodefine(optarg, p); ! 221: break; ! 222: case 'U': /* undefine... */ ! 223: remhash(optarg, TOP); ! 224: break; ! 225: case 'o': /* specific output */ ! 226: case '?': ! 227: default: ! 228: usage(); ! 229: } ! 230: ! 231: infile[0] = stdin; /* default input (naturally) */ ! 232: active = stdout; /* default active output */ ! 233: m4temp = mktemp(DIVNAM); /* filename for diversions */ ! 234: ! 235: sp = -1; /* stack pointer initialized */ ! 236: fp = 0; /* frame pointer initialized */ ! 237: ! 238: macro(); /* get some work done here */ ! 239: ! 240: if (*m4wraps) { /* anything for rundown ?? */ ! 241: ilevel = 0; /* in case m4wrap includes.. */ ! 242: putback(EOF); /* eof is a must !! */ ! 243: pbstr(m4wraps); /* user-defined wrapup act */ ! 244: macro(); /* last will and testament */ ! 245: } ! 246: ! 247: if (active != stdout) ! 248: active = stdout; /* reset output just in case */ ! 249: for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */ ! 250: if (outfile[n] != NULL) ! 251: getdiv(n); ! 252: /* remove bitbucket if used */ ! 253: if (outfile[0] != NULL) { ! 254: (void) fclose(outfile[0]); ! 255: m4temp[UNIQUE] = '0'; ! 256: (void) unlink(m4temp); ! 257: } ! 258: ! 259: exit(0); ! 260: } ! 261: ! 262: ndptr inspect(); /* forward ... */ ! 263: ! 264: /* ! 265: * macro - the work horse.. ! 266: * ! 267: */ ! 268: macro() { ! 269: char token[MAXTOK]; ! 270: register char *s; ! 271: register int t, l; ! 272: register ndptr p; ! 273: register int nlpar; ! 274: ! 275: cycle { ! 276: if ((t = gpbc()) == '_' || isalpha(t)) { ! 277: putback(t); ! 278: if ((p = inspect(s = token)) == nil) { ! 279: if (sp < 0) ! 280: while (*s) ! 281: putc(*s++, active); ! 282: else ! 283: while (*s) ! 284: chrsave(*s++); ! 285: } ! 286: else { ! 287: /* ! 288: * real thing.. First build a call frame: ! 289: * ! 290: */ ! 291: pushf(fp); /* previous call frm */ ! 292: pushf(p->type); /* type of the call */ ! 293: pushf(0); /* parenthesis level */ ! 294: fp = sp; /* new frame pointer */ ! 295: /* ! 296: * now push the string arguments: ! 297: * ! 298: */ ! 299: pushs(p->defn); /* defn string */ ! 300: pushs(p->name); /* macro name */ ! 301: pushs(ep); /* start next..*/ ! 302: ! 303: putback(l = gpbc()); ! 304: if (l != LPAREN) { /* add bracks */ ! 305: putback(RPAREN); ! 306: putback(LPAREN); ! 307: } ! 308: } ! 309: } ! 310: else if (t == EOF) { ! 311: if (sp > -1) ! 312: error("m4: unexpected end of input"); ! 313: if (--ilevel < 0) ! 314: break; /* all done thanks.. */ ! 315: (void) fclose(infile[ilevel+1]); ! 316: continue; ! 317: } ! 318: /* ! 319: * non-alpha single-char token seen.. ! 320: * [the order of else if .. stmts is ! 321: * important.] ! 322: * ! 323: */ ! 324: else if (t == lquote) { /* strip quotes */ ! 325: nlpar = 1; ! 326: do { ! 327: if ((l = gpbc()) == rquote) ! 328: nlpar--; ! 329: else if (l == lquote) ! 330: nlpar++; ! 331: else if (l == EOF) ! 332: error("m4: missing right quote"); ! 333: if (nlpar > 0) { ! 334: if (sp < 0) ! 335: putc(l, active); ! 336: else ! 337: chrsave(l); ! 338: } ! 339: } ! 340: while (nlpar != 0); ! 341: } ! 342: ! 343: else if (sp < 0) { /* not in a macro at all */ ! 344: if (t == scommt) { /* comment handling here */ ! 345: putc(t, active); ! 346: while ((t = gpbc()) != ecommt) ! 347: putc(t, active); ! 348: } ! 349: putc(t, active); /* output directly.. */ ! 350: } ! 351: ! 352: else switch(t) { ! 353: ! 354: case LPAREN: ! 355: if (PARLEV > 0) ! 356: chrsave(t); ! 357: while (isspace(l = gpbc())) ! 358: ; /* skip blank, tab, nl.. */ ! 359: putback(l); ! 360: PARLEV++; ! 361: break; ! 362: ! 363: case RPAREN: ! 364: if (--PARLEV > 0) ! 365: chrsave(t); ! 366: else { /* end of argument list */ ! 367: chrsave(EOS); ! 368: ! 369: if (sp == STACKMAX) ! 370: error("m4: internal stack overflow"); ! 371: ! 372: if (CALTYP == MACRTYPE) ! 373: expand(mstack+fp+1, sp-fp); ! 374: else ! 375: eval(mstack+fp+1, sp-fp, CALTYP); ! 376: ! 377: ep = PREVEP; /* flush strspace */ ! 378: sp = PREVSP; /* previous sp.. */ ! 379: fp = PREVFP; /* rewind stack...*/ ! 380: } ! 381: break; ! 382: ! 383: case COMMA: ! 384: if (PARLEV == 1) { ! 385: chrsave(EOS); /* new argument */ ! 386: while (isspace(l = gpbc())) ! 387: ; ! 388: putback(l); ! 389: pushs(ep); ! 390: } ! 391: break; ! 392: default: ! 393: chrsave(t); /* stack the char */ ! 394: break; ! 395: } ! 396: } ! 397: } ! 398: ! 399: ! 400: /* ! 401: * build an input token.. ! 402: * consider only those starting with _ or A-Za-z. This is a ! 403: * combo with lookup to speed things up. ! 404: */ ! 405: ndptr ! 406: inspect(tp) ! 407: register char *tp; ! 408: { ! 409: register int h = 0; ! 410: register char c; ! 411: register char *name = tp; ! 412: register char *etp = tp+MAXTOK; ! 413: register ndptr p; ! 414: ! 415: while (tp < etp && (isalnum(c = gpbc()) || c == '_')) ! 416: h += (*tp++ = c); ! 417: putback(c); ! 418: if (tp == etp) ! 419: error("m4: token too long"); ! 420: *tp = EOS; ! 421: for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr) ! 422: if (strcmp(name, p->name) == 0) ! 423: break; ! 424: return(p); ! 425: } ! 426: ! 427: #ifdef NONZEROPAGES ! 428: /* ! 429: * initm4 - initialize various tables. Useful only if your system ! 430: * does not know anything about demand-zero pages. ! 431: * ! 432: */ ! 433: initm4() ! 434: { ! 435: register int i; ! 436: ! 437: for (i = 0; i < HASHSIZE; i++) ! 438: hashtab[i] = nil; ! 439: for (i = 0; i < MAXOUT; i++) ! 440: outfile[i] = NULL; ! 441: } ! 442: #endif ! 443: ! 444: /* ! 445: * initkwds - initialise m4 keywords as fast as possible. ! 446: * This very similar to install, but without certain overheads, ! 447: * such as calling lookup. Malloc is not used for storing the ! 448: * keyword strings, since we simply use the static pointers ! 449: * within keywrds block. We also assume that there is enough memory ! 450: * to at least install the keywords (i.e. malloc won't fail). ! 451: * ! 452: */ ! 453: initkwds() { ! 454: register int i; ! 455: register int h; ! 456: register ndptr p; ! 457: ! 458: for (i = 0; i < MAXKEYS; i++) { ! 459: h = hash(keywrds[i].knam); ! 460: p = (ndptr) malloc(sizeof(struct ndblock)); ! 461: p->nxtptr = hashtab[h]; ! 462: hashtab[h] = p; ! 463: p->name = keywrds[i].knam; ! 464: p->defn = null; ! 465: p->type = keywrds[i].ktyp | STATIC; ! 466: } ! 467: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.