Annotation of coherent/d/bin/sh/lex.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * sh/lex.c
                      3:  * Bourne shell.
                      4:  * Lexical analysis.
                      5:  */
                      6: 
                      7: #include "sh.h"
                      8: #include <y.tab.h>
                      9: 
                     10: /*
                     11:  * Local externals.
                     12:  */
                     13: int    lastget = '\0';         /* Pushed back character */
                     14: int    eolflag = 0;            /* End of line */
                     15: 
                     16: /*
                     17:  * For processing here documents.
                     18:  */
                     19: char   *hereeof = NULL;        /* Here document EOF mark */
                     20: int    herefd;                 /* Here document fd */
                     21: char   *heretmp;               /* Here document tempfile name */
                     22: int    hereqflag;              /* Here document quoted */
                     23: 
                     24: /*
                     25:  * Keyword table.
                     26:  */
                     27: typedef        struct  key {
                     28:        int     k_hash;                 /* Hash */
                     29:        int     k_lexv;                 /* Lexical value */
                     30:        char    *k_name;                /* Keyword name */
                     31: } KEY;
                     32: 
                     33: /*
                     34:  * Keyword table.
                     35:  */
                     36: KEY keytab[] ={
                     37:        0,      _CASE,  "case",
                     38:        0,      _DO,    "do",
                     39:        0,      _DONE,  "done",
                     40:        0,      _ELIF,  "elif",
                     41:        0,      _ELSE,  "else",
                     42:        0,      _ESAC,  "esac",
                     43:        0,      _FI,    "fi",
                     44:        0,      _FOR,   "for",
                     45:        0,      _IF,    "if",
                     46:        0,      _IN,    "in",
                     47:        0,      _THEN,  "then",
                     48:        0,      _UNTIL, "until",
                     49:        0,      _WHILE, "while",
                     50:        0,      _OBRAC, "{",
                     51:        0,      _CBRAC, "}"
                     52: };
                     53: #define        NKEYS   (sizeof(keytab) / sizeof(keytab[0]))
                     54: 
                     55: /*
                     56:  * Get the next lexical token.
                     57:  */
                     58: yylex()
                     59: {
                     60:        register int c;
                     61:        register KEY *kp;
                     62:        int hash;
                     63: 
                     64:        /* Initialize hash values in key table. */
                     65:        if (keytab[0].k_hash == 0)
                     66:                for (kp = &keytab[0]; kp < &keytab[NKEYS]; kp++)
                     67:                        kp->k_hash = ihash(kp->k_name);
                     68: again:
                     69:        while ((c=getn())==' '  ||  c=='\t') ;
                     70:        strp = strt;
                     71:        if (c == '#' && readflag == 0) {
                     72:                /*
                     73:                 * Ignore a '#'-delimited comment line.
                     74:                 * Lines which begin with a ':' token are lexed as usual;
                     75:                 * the built-in function s_colon() executes (i.e. ignores)
                     76:                 * lines starting with ':', while other ':' tokens get passed.
                     77:                 * The built-in "read" does not ignore comment lines.
                     78:                 */
                     79:                do
                     80:                        c = getn();
                     81:                while (c > 0 && c != '\n');
                     82:                return c;
                     83:        } else if (class(c, MDIGI)) {
                     84:                *strp++ = c;
                     85:                c = getn();
                     86:                if (c=='>' || c=='<') {
                     87:                        *strp++ = c;
                     88:                        return lexiors(c);
                     89:                }
                     90:                ungetn(c);
                     91:                return lexname();
                     92:        }
                     93:        if (!class(c, MNAME)) {
                     94:                ungetn(c);
                     95:                if ((c = lexname()) == 0)
                     96:                        goto again;
                     97:                else if (c < 0)
                     98:                        return c;
                     99:                hash = ihash(strt);
                    100:                if (keyflag) {
                    101:                        for (kp = keytab; kp < &keytab[NKEYS]; kp++)
                    102:                                if (hash == kp->k_hash && strcmp(strt, kp->k_name) == 0)
                    103:                                        return kp->k_lexv;
                    104:                }
                    105:                return c;
                    106:        }
                    107:        *strp++ = c;
                    108:        *strp = '\0';
                    109:        switch (c) {
                    110:        case ';':
                    111:                return isnext(c, _DSEMI);
                    112:        case '>':
                    113:                return lexiors(c);
                    114:        case '<':
                    115:                return lexiors(c);
                    116:        case '&':
                    117:                return isnext(c, _ANDF);
                    118:        case '|':
                    119: #ifdef NAMEPIPE
                    120:                if ( ! isnext(')', 0))
                    121:                        return _NCLOSE;
                    122: #endif
                    123:                return isnext(c, _ORF);
                    124: #ifdef NAMEPIPE
                    125:        case '(':
                    126:                return isnext('|', _NOPEN);
                    127: #endif
                    128:        default:
                    129:                if (hereeof != NULL) {
                    130:                        /* Read here document. */
                    131:                        for (;;) {
                    132:                                strp = strt;
                    133:                                if ((c = collect('\n', 2)) < 0)
                    134:                                        break;
                    135:                                *strp = '\0';
                    136:                                if (strcmp(strt, hereeof)==0)
                    137:                                        break;
                    138:                                if (herefd < 0)
                    139:                                        continue;
                    140:                                if (!hereqflag && strp > strt + 1 && strp[-2]=='\\')
                    141:                                        *(strp-=2) = '\0';
                    142:                                if (!hereqflag && *strt=='\\' && strcmp(hereeof, strt+1)==0)
                    143:                                        write(herefd, strt+1, strp-strt-1);
                    144:                                else
                    145:                                        write(herefd, strt, strp-strt);
                    146:                        }
                    147:                        close(herefd);
                    148:                        cleanup(0, heretmp);
                    149:                        hereeof = NULL;
                    150:                        return '\n';
                    151:                }
                    152:                return c;
                    153:        }
                    154: }
                    155: 
                    156: isnext(c, t1)
                    157: register int c;
                    158: {
                    159:        register int c2;
                    160: 
                    161:        if ((c2=getn()) == c) {
                    162:                *strp++ = c2;
                    163:                *strp = '\0';
                    164:                return t1;
                    165:        }
                    166:        ungetn(c2);
                    167:        return strp[-1];
                    168: }
                    169: 
                    170: /*
                    171:  * Scan a single argument.
                    172:  *     Return 0 if it's an escaped newline, EOF if EOF is found,
                    173:  *     or _NAME or _ASGN if any part of an argument is found.
                    174:  */
                    175: lexname()
                    176: {
                    177:        int q, asgn;
                    178:        register int c, m;
                    179:        register char *cp;
                    180: 
                    181:        q = 0;
                    182:        asgn = 0;
                    183:        m = MNQUO;
                    184:        cp = strp;
                    185:        for (;;) {
                    186:                c = getn();
                    187:                if (asgn==0)
                    188:                        asgn = class(c, MBVAR) ? 1 : -1;
                    189:                else if (asgn==1)
                    190:                        asgn = class(c, MRVAR) ? 1 : (c=='=' ? 2 : -1);
                    191:                if (cp >= strt + STRSIZE)
                    192:                        etoolong();
                    193:                else
                    194:                        *cp++ = c;
                    195:                if (!class(c, m))
                    196:                        continue;
                    197:                switch (c) {
                    198:                case '"':
                    199:                        m = (q^=1) ? MDQUO : MNQUO;
                    200:                        continue;
                    201:                case '\'':
                    202:                        strp = cp;
                    203:                        if ((c = collect('\'', 1)) != '\'')
                    204:                                break;
                    205:                        cp = strp;
                    206:                        continue;
                    207:                case '\\':
                    208:                        if ((c=getn()) < 0) {
                    209:                                syntax();
                    210:                                break;
                    211:                        }
                    212:                        if (c == '\n') {
                    213:                                ungetn((c=getn())<0 ? '\n' : c);
                    214:                                if (--cp == strp)
                    215:                                        return 0;
                    216:                                continue;
                    217:                        }
                    218:                        *cp++ = c;
                    219:                        continue;
                    220:                case '$':
                    221:                        if ((c=getn()) == '{') {
                    222:                                *cp++ = c;
                    223:                                strp = cp;
                    224:                                if ((c = collect('}', 0)) != '}')
                    225:                                        break;
                    226:                                cp = strp;
                    227:                                continue;
                    228:                        }
                    229:                        ungetn(c);
                    230:                        continue;
                    231:                case '`':
                    232:                        strp = cp;
                    233:                        if ((c = collect('`', 1)) != '`')
                    234:                                break;
                    235:                        cp = strp;
                    236:                        continue;
                    237:                case '\n':
                    238:                        if (q)
                    239:                                continue;
                    240:                        break;
                    241:                }
                    242:                break;
                    243:        }
                    244:        if (c < 0)
                    245:                return c;
                    246:        if (q) {
                    247:                emisschar('"');
                    248:                *cp = '\0';
                    249:        } else {
                    250:                *--cp = '\0';
                    251:        }
                    252:        ungetn(c);
                    253:        strp = cp;
                    254: #ifdef VERBOSE
                    255:        if (vflag)
                    256:        prints("\t<%d> <%s> %s\n", getpid(), (asgn==2 ? "ASGN" : "NAME"), strt);
                    257: #endif
                    258:        if (errflag)
                    259:                return _NULL;
                    260:        else if (asgn==2)
                    261:                return _ASGN;
                    262:        else
                    263:                return _NAME;
                    264:        return (asgn==2 ? _ASGN : _NAME);
                    265: }
                    266: 
                    267: /*
                    268:  * Lex an io redirection string, including the file name if any.
                    269:  *     Called with one '>' or '<' in buffer, optionally preceded by
                    270:  *     a digit.
                    271:  */
                    272: lexiors(c1)
                    273: {
                    274:        register int c;
                    275:        register char *name;
                    276:        char *iors;
                    277: 
                    278:        *strp++ = c = getn();
                    279:        if (c=='&') {
                    280:                *strp++ = c = getn();
                    281:                *strp = '\0';
                    282:                if (c < 0) return c;
                    283:                if (c!='-' && !class(c, MDIGI))
                    284:                        eredir();
                    285:                return _IORS;
                    286:        }
                    287:        if (c==c1)
                    288:                c1 += 0200;
                    289:        else {
                    290:                *--strp = '\0';
                    291:                ungetn(c);
                    292:        }
                    293:        /* Collect file name */
                    294:        while ((c=getn())==' '||c=='\t')
                    295:                *strp++ = c;
                    296:        ungetn(c);
                    297:        name = strp;
                    298:        if (c=='\n') {
                    299:                eredir();
                    300:                return _IORS;
                    301:        }
                    302:        while ((c = lexname())==0);
                    303:        if (c < 0) return c;
                    304:        if (c1!='<'+0200)
                    305:                return _IORS;
                    306: #if    1
                    307:        /*
                    308:         * Set up here document processing.
                    309:         * Modified by steve 1/25/91 so that
                    310:         * the actual processing happens at the '\n' ending the line,
                    311:         * otherwise the common "foo <<SHAR_EOF >baz\n" does not work.
                    312:         * This code is anything but obvious, it could doubtless be simpler.
                    313:         */
                    314:        strp = strt;
                    315:        /* Simplify quoted here document iors from ?<<file to ?<file. */
                    316:        if (hereqflag = (strpbrk(name, "\"\\'") != NULL))
                    317:                *++strp = *strt;
                    318:        heretmp = name;
                    319:        name = duplstr(name, 0);
                    320:        strcpy(heretmp, shtmp());
                    321:        iors = duplstr(strp, 0);
                    322:        heretmp += iors - strp;
                    323:        eval(name, EWORD);
                    324:        hereeof = duplstr(strcat(strt, "\n"), 0);
                    325:        if ((herefd = creat(heretmp, 0666)) < 0)
                    326:                ecantmake(heretmp);
                    327:        strcpy(strt, iors);
                    328: #else
                    329:        /* Collect here document */
                    330:        if ((c=getn())!='\n') {
                    331:                eredir();
                    332:                ++strp;
                    333:                c = collect('\n', 1);
                    334:        }
                    335:        if (c < 0) return c;
                    336:        bpp = savebuf();
                    337:        strp = strt;
                    338:        /* Simplify quoted to ?<file from ?<<file */
                    339:        if (quote = (strpbrk(name, "\"\\'") != NULL))
                    340:                *++strp = *strt;
                    341:        tmp = name;
                    342:        name = duplstr(name, 0);
                    343:        strcpy(tmp, shtmp());
                    344:        iors = duplstr(strp, 0);
                    345:        tmp += iors - strp;
                    346:        eval(name, EWORD);
                    347:        name = duplstr(strcat(strt, "\n"), 0);
                    348:        if ((hfd = creat(tmp, 0666)) < 0)
                    349:                ecantmake(tmp);
                    350:        for (;;) {
                    351:                strp = strt;
                    352:                if ((c = collect('\n', 2)) < 0)
                    353:                        break;
                    354:                *strp = '\0';
                    355:                if (strcmp(strt, name)==0)
                    356:                        break;
                    357:                if (hfd < 0)
                    358:                        continue;
                    359:                if (! quote && strp > strt + 1 && strp[-2]=='\\')
                    360:                        *(strp-=2) = '\0';
                    361:                if (! quote && *strt=='\\' && strcmp(name, strt+1)==0)
                    362:                        write(hfd, strt+1, strp-strt-1);
                    363:                else
                    364:                        write(hfd, strt, strp-strt);
                    365:        }
                    366:        close(hfd);
                    367:        cleanup(0, tmp);
                    368:        ungetn('\n');
                    369:        strcpy(strt, iors);
                    370:        freebuf(bpp);
                    371:        /* Check for interrupt, since EOF is legal for once */
                    372:        if (c < 0 && ! recover(ILEX)) return c;
                    373: #endif
                    374:        return _IORS;
                    375: }
                    376: 
                    377: /*
                    378:  * Collect characters until the end character is found.  If `f' is
                    379:  * set, all characters are passed through otherwise '\' escapes the
                    380:  * next character and newline is not allowed.
                    381:  * If `f' is set to 2, then no error is desired.
                    382:  */
                    383: collect(ec, f)
                    384: register int ec;
                    385: {
                    386:        register int c;
                    387:        register char *cp;
                    388: 
                    389:        cp = strp;
                    390:        while ((c=getn()) != ec) {
                    391:                if (c<0 || (c=='\n' && f==0)) {
                    392:                        if (--f <= 0)
                    393:                                emisschar(ec);
                    394:                        return c;
                    395:                }
                    396:                if (c=='\\' && f==0) {
                    397:                        if ((c=getn()) < 0) {
                    398:                                syntax();
                    399:                                return c;
                    400:                        }
                    401:                        if (c == '\n')
                    402:                                continue;
                    403:                }
                    404:                if (cp >= strt + STRSIZE)
                    405:                        etoolong();
                    406:                else
                    407:                        *cp++ = c;
                    408:        }
                    409:        *cp++ = ec;
                    410:        strp = cp;
                    411:        return ec;
                    412: }
                    413: 
                    414: /*
                    415:  * Get a character.
                    416:  */
                    417: getn()
                    418: {
                    419:        register int c;
                    420:        register int t;
                    421: 
                    422:        if (lastget != '\0') {
                    423:                c = lastget;
                    424:                lastget = '\0';
                    425:                return c;
                    426:        }
                    427:        switch (t = sesp->s_type) {
                    428:        case SSTR:
                    429:        case SFILE:
                    430:                yyline += eolflag;
                    431:                eolflag = 0;
                    432:                if (prpflag && sesp->s_flag) {
                    433:                        if (prpflag -= 1) {
                    434:                                prompt("\n");
                    435:                                prpflag -= 1;
                    436:                        }
                    437:                        prompt(comflag ? vps1 : vps2);
                    438:                        comflag = 0;
                    439:                }
                    440:                if ((c=getc(sesp->s_ifp))=='\n') {
                    441:                        if (sesp->s_flag) {
                    442:                                prpflag = 1;
                    443:                                yyline = 1;
                    444:                        } else
                    445:                                eolflag = 1;
                    446:                }
                    447:                if (vflag)
                    448:                        putc(c, stderr);
                    449:                return c;
                    450:        case SARGS:
                    451:        case SARGV:
                    452:                if (sesp->s_flag)
                    453:                        return EOF;
                    454:                if ((c=*sesp->s_strp++) == '\0') {
                    455:                        if (t == SARGV
                    456:                         && (sesp->s_strp=*++sesp->s_argv) != NULL)
                    457:                                c = ' ';
                    458:                        else {
                    459:                                sesp->s_flag = 1;
                    460:                                c = '\n';
                    461:                        }
                    462:                }
                    463:                if (vflag)
                    464:                        putc(c, stderr);
                    465:                return c;
                    466:        }
                    467: }
                    468: 
                    469: /*
                    470:  * Unget a character.
                    471:  */
                    472: ungetn(c)
                    473: {
                    474:        lastget = c;
                    475: }
                    476: 
                    477: /* end of sh/lex.c */

unix.superglobalmegacorp.com

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