Annotation of 43BSDReno/pgrm/m4/main.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.