Annotation of coherent/b/bin/sh.420/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,      _RET,   "return",
                     48:        0,      _THEN,  "then",
                     49:        0,      _UNTIL, "until",
                     50:        0,      _WHILE, "while",
                     51:        0,      _OBRAC, "{",
                     52:        0,      _CBRAC, "}"
                     53: };
                     54: #define        NKEYS   (sizeof(keytab) / sizeof(keytab[0]))
                     55:        
                     56: /*
                     57:  * Get the next lexical token.
                     58:  */
                     59: yylex()
                     60: {
                     61:        register int c;
                     62:        register KEY *kp;
                     63:        int hash;
                     64: 
                     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:                /* DO NOTHING */ ;
                     71:        strp = strt;
                     72:        if (c == '#' && readflag == 0) {
                     73:                /*
                     74:                 * Ignore a '#'-delimited comment line.
                     75:                 * Lines which begin with a ':' token are lexed as usual;
                     76:                 * the built-in function s_colon() executes (i.e. ignores)
                     77:                 * lines starting with ':', while other ':' tokens get passed.
                     78:                 * The built-in "read" does not ignore comment lines.
                     79:                 */
                     80:                do
                     81:                        c = getn ();
                     82:                while (c > 0 && c != '\n');
                     83:                return c;
                     84:        } else if (class (c, MDIGI)) {
                     85:                * strp ++ = c;
                     86:                c = getn ();
                     87:                if (c == '>' || c == '<') {
                     88:                        * strp ++ = c;
                     89:                        return lexiors (c);
                     90:                }
                     91:                ungetn (c);
                     92:                return lexname ();
                     93:        }
                     94:        if (! class (c, MNAME)) {
                     95:                if (c >= 0)
                     96:                        ungetn (c);
                     97:                if ((c = lexname ()) == 0)
                     98:                        goto again;
                     99:                else if (c < 0)
                    100:                        return c;
                    101: 
                    102:                hash = ihash (strt);
                    103: 
                    104:                if (keyflag) {
                    105:                        for (kp = keytab; kp < & keytab [NKEYS] ; kp ++)
                    106:                                if (hash == kp->k_hash &&
                    107:                                    strcmp (strt, kp->k_name) == 0) {
                    108:                                        return kp->k_lexv;
                    109:                                }
                    110:                }
                    111: 
                    112:                return c;
                    113:        }
                    114:        * strp ++ = c;
                    115:        * strp = '\0';
                    116: 
                    117:        switch (c) {
                    118:        case ';':
                    119:                return isnext (c, _DSEMI);
                    120: 
                    121:        case '>':
                    122:                return lexiors (c);
                    123: 
                    124:        case '<':
                    125:                return lexiors (c);
                    126: 
                    127:        case '&':
                    128:                return isnext (c, _ANDF);
                    129: 
                    130:        case '|':
                    131: #ifdef NAMEPIPE
                    132:                if ( ! isnext (')', 0))
                    133:                        return _NCLOSE;
                    134: #endif
                    135:                return isnext (c, _ORF);
                    136: 
                    137: #ifdef NAMEPIPE
                    138:        case '(':
                    139:                return isnext ('|', _NOPEN);
                    140: #else
                    141:        case '(':
                    142:                return isnext (')', _PARENS);
                    143: #endif
                    144: 
                    145:        default:
                    146:                if (hereeof != NULL) {
                    147:                        /* Read here document. */
                    148:                        for (;;) {
                    149:                                strp = strt;
                    150:                                if ((c = collect ('\n', NO_ERRORS)) < 0)
                    151:                                        break;
                    152:                                * strp = '\0';
                    153:                                if (strcmp (strt, hereeof) == 0)
                    154:                                        break;
                    155:                                if (herefd < 0)
                    156:                                        continue;
                    157:                                if (! hereqflag && strp > strt + 1 &&
                    158:                                    strp [-2] == '\\')
                    159:                                        * (strp -= 2) = '\0';
                    160:                                if (! hereqflag && * strt == '\\' &&
                    161:                                    strcmp (hereeof, strt + 1) == 0) {
                    162:                                        write (herefd, strt + 1,
                    163:                                               strp - strt - 1);
                    164:                                } else
                    165:                                        write (herefd, strt, strp - strt);
                    166:                        }
                    167:                        close (herefd);
                    168:                        remember_temp (heretmp);
                    169:                        hereeof = NULL;
                    170:                        return '\n';
                    171:                }
                    172: 
                    173:                return c;
                    174:        }
                    175: }
                    176: 
                    177: isnext(c, t1)
                    178: register int c;
                    179: {
                    180:        register int c2;
                    181: 
                    182:        if ((c2 = getn ()) == c) {
                    183:                * strp ++ = c2;
                    184:                * strp = '\0';
                    185:                return t1;
                    186:        }
                    187:        ungetn (c2);
                    188:        return strp [-1];
                    189: }
                    190: 
                    191: /*
                    192:  * Read stuff delimited by (possibly nested) '{' '}' pairs.
                    193:  */
                    194: 
                    195: void getcurlies () {
                    196:        int             c;
                    197:        int             quote = 0;
                    198: 
                    199:        for (;;) {
                    200:                if ((c = getn ()) < 0 || c == '\n')
                    201:                        emisschar ();
                    202: 
                    203:                if (strp >= strt + STRSIZE)
                    204:                        etoolong ("in getcurlies ()");
                    205: 
                    206:                switch (* strp ++ = c) {
                    207:                case '}':
                    208:                        if (! quote)
                    209:                                return;
                    210:                        continue;
                    211: 
                    212:                case '"':
                    213:                        quote ^= 1;
                    214:                        continue;
                    215: 
                    216:                case '\'':
                    217:                        if ((c = collect ('\'', NO_BACKSLASH)) != '\'')
                    218:                                break;
                    219:                        continue;
                    220: 
                    221:                case '\\':
                    222:                        if ((c = getn ()) < 0) {
                    223:                                syntax ();
                    224:                                break;
                    225:                        }
                    226:                        if (c == '\n') {
                    227:                                strp --;
                    228:                                continue;
                    229:                        }
                    230:                        * strp ++ = c;
                    231:                        continue;
                    232: 
                    233:                case '$':
                    234:                        c = getn ();
                    235:                        if (c == '{') {
                    236:                                * strp ++ = c;
                    237:                                getcurlies ();
                    238:                        } else
                    239:                                ungetn(c);
                    240:                        continue;
                    241: 
                    242:                case '`':
                    243:                        if ((c = collect ('`', BACKSLASH_END)) != '`')
                    244:                                break;
                    245:                        continue;
                    246:                }
                    247:        }
                    248: }
                    249: 
                    250: 
                    251: /*
                    252:  * Scan a single argument.
                    253:  *     Return 0 if it's an escaped newline, EOF if EOF is found,
                    254:  *     or _NAME or _ASGN if any part of an argument is found.
                    255:  */
                    256: lexname()
                    257: {
                    258:        int q, asgn;
                    259:        register int c, m;
                    260:        register char *cp;
                    261: 
                    262:        q = 0;
                    263:        asgn = 0;
                    264:        m = MNQUO;
                    265:        cp = strp;
                    266:        for (;;) {
                    267:                c = getn ();
                    268:                if (asgn == 0)
                    269:                        asgn = class (c, MBVAR) ? 1 : -1;
                    270:                else if (asgn == 1)
                    271:                        asgn = class (c, MRVAR) ? 1 : (c == '=' ? 2 : -1);
                    272:                if (cp >= strt + STRSIZE)
                    273:                        etoolong ("in lexname ()");
                    274:                else
                    275:                        * cp++ = c;
                    276:                if (! class (c, m))
                    277:                        continue;
                    278:                switch (c) {
                    279:                case '"':
                    280:                        m = (q ^= 1) ? MDQUO : MNQUO;
                    281:                        continue;
                    282: 
                    283:                case '\'':
                    284:                        strp = cp;
                    285:                        c = collect ('\'', NO_BACKSLASH);
                    286:                        cp = strp;
                    287:                        if (c != '\'')
                    288:                                break;
                    289:                        continue;
                    290: 
                    291:                case '\\':
                    292:                        if ((c = getn ()) < 0) {
                    293:                                syntax ();
                    294:                                break;
                    295:                        }
                    296:                        if (c == '\n') {
                    297:                                ungetn ((c = getn ()) < 0 ? '\n' : c);
                    298:                                if (-- cp == strp)
                    299:                                        return 0;
                    300:                                continue;
                    301:                        }
                    302:                        * cp ++ = c;
                    303:                        continue;
                    304: 
                    305:                case '$':
                    306:                        c = getn ();
                    307:                        if (c == '{') {
                    308:                                * cp ++ = c;
                    309:                                strp = cp;
                    310:                                getcurlies ();
                    311:                                cp = strp;
                    312:                        } else
                    313:                                ungetn (c);
                    314:                        continue;
                    315: 
                    316:                case '`':
                    317:                        strp = cp;
                    318:                        c = collect ('`', BACKSLASH_END);
                    319:                        cp = strp;
                    320:                        if (c != '`')
                    321:                                break;
                    322:                        continue;
                    323: 
                    324:                case '\n':
                    325:                        if (q)
                    326:                                continue;
                    327:                        break;
                    328:                }
                    329:                break;
                    330:        }
                    331: 
                    332: #if 0
                    333:        if (c < 0)
                    334:                return c;
                    335: #endif
                    336: 
                    337:        if (q) {
                    338:                emisschar ('"');
                    339:                * cp = '\0';
                    340:        } else
                    341:                * -- cp = '\0';
                    342: 
                    343:        if (c >= 0)
                    344:                ungetn (c);
                    345:        strp = cp;
                    346: 
                    347: #ifdef VERBOSE
                    348:        if (vflag)
                    349:        prints("\t<%d> <%s> %s\n", getpid(), (asgn==2 ? "ASGN" : "NAME"), strt);
                    350: #endif
                    351:        if (errflag)
                    352:                return _NULL;
                    353:        else if (asgn == 2)
                    354:                return _ASGN;
                    355:        else
                    356:                return _NAME;
                    357: }
                    358: 
                    359: /*
                    360:  * Lex an io redirection string, including the file name if any.
                    361:  *     Called with one '>' or '<' in buffer, optionally preceded by
                    362:  *     a digit.
                    363:  */
                    364: lexiors(c1)
                    365: {
                    366:        register int c;
                    367:        register char *name;
                    368:        char *iors;
                    369: 
                    370:        * strp ++ = c = getn ();
                    371:        if (c == '&') {
                    372:                * strp ++ = c = getn ();
                    373:                * strp = '\0';
                    374:                if (c < 0)
                    375:                        return c;
                    376:                if (c != '-' && ! class (c, MDIGI))
                    377:                        eredir ();
                    378:                return _IORS;
                    379:        }
                    380:        if (c == c1)
                    381:                c1 += 0200;
                    382:        else {
                    383:                * -- strp = '\0';
                    384:                ungetn (c);
                    385:        }
                    386: 
                    387:        /* Collect file name */
                    388:        while ((c = getn ()) == ' ' || c == '\t')
                    389:                * strp ++ = c;
                    390:        ungetn (c);
                    391:        name = strp;
                    392:        if (c == '\n') {
                    393:                eredir ();
                    394:                return _IORS;
                    395:        }
                    396: 
                    397:        while ((c = lexname ()) == 0)
                    398:                /* DO NOTHING */ ;
                    399: 
                    400:        if (c < 0)
                    401:                return c;
                    402: 
                    403:        if (c1 != '<' + 0200)
                    404:                return _IORS;
                    405: 
                    406:        /*
                    407:         * Set up here document processing.
                    408:         * Modified by steve 1/25/91 so that
                    409:         * the actual processing happens at the '\n' ending the line,
                    410:         * otherwise the common "foo <<SHAR_EOF >baz\n" does not work.
                    411:         * This code is anything but obvious, it could doubtless be simpler.
                    412:         */
                    413:        strp = strt;
                    414:        /* Simplify quoted here document iors from ?<<file to ?<file. */
                    415:        if ((hereqflag = strpbrk (name, "\"\\'") != NULL) != 0)
                    416:                * ++ strp = * strt;
                    417:        heretmp = name;
                    418:        name = duplstr (name, 0);
                    419:        strcpy (heretmp, shtmp ());
                    420:        iors = duplstr (strp, 0);
                    421:        heretmp += iors - strp;
                    422:        eval (name, EWORD);
                    423:        hereeof = duplstr (strcat (strt, "\n"), 0);
                    424:        if ((herefd = creat (heretmp, 0666)) < 0)
                    425:                ecantmake (heretmp);
                    426:        strcpy (strt, iors);
                    427:        return _IORS;
                    428: }
                    429: 
                    430: /*
                    431:  * Collect characters until the end character is found.  If 'f' is
                    432:  * CONSUME_BACKSLASH, '\' escapes the next character and newline is
                    433:  * not allowed. If 'f' is BACKSLASH_END, backslashes are retained but
                    434:  * suppress recognition of the end-character. If 'f' is NO_BACKSLASH,
                    435:  * all characters are passed through. If 'f' is NO_ERRORS, behave as
                    436:  * NO_BACKSLASH but be quiet about errors.
                    437:  */
                    438: collect(ec, f)
                    439: register int ec;
                    440: {
                    441:        register int c;
                    442:        register char *cp;
                    443: 
                    444:        cp = strp;
                    445:        while ((c = getn ()) != ec) {
                    446: backslashed:
                    447:                /*
                    448:                 * NIGEL: Originally, this routine complained about missing
                    449:                 * characters at EOF, but System V just implicitly closes off
                    450:                 * any strings in this situation. In order to stroke the
                    451:                 * lexer, we mutate EOF's into EOL's.
                    452:                 */
                    453:                if (c < 0) {
                    454:                        if (f != NO_ERRORS) {
                    455:                                c = ec;
                    456:                                break;
                    457:                        }
                    458:                        return c;
                    459:                }
                    460:                if (c == '\n' && f == CONSUME_BACKSLASH) {
                    461:                        if (f != NO_ERRORS)
                    462:                                emisschar (ec);
                    463:                        return c;
                    464:                }
                    465:                if (c == '\\' && f == CONSUME_BACKSLASH) {
                    466:                        if ((c = getn ()) < 0) {
                    467:                                syntax ();
                    468:                                return c;
                    469:                        }
                    470:                        if (c == '\n')
                    471:                                continue;
                    472:                }
                    473:                if (cp >= strt + STRSIZE)
                    474:                        etoolong ("in collect ()");
                    475:                else
                    476:                        * cp ++ = c;
                    477:                if (c == '\\' && f == BACKSLASH_END) {
                    478:                        if ((c = getn ()) != '\n')
                    479:                                goto backslashed;
                    480:                        cp --;
                    481:                }
                    482:        }
                    483:        * cp ++ = ec;
                    484:        strp = cp;
                    485:        return ec;
                    486: }
                    487: 
                    488: 
                    489: /*
                    490:  * Get a character.
                    491:  */
                    492: 
                    493: getn()
                    494: {
                    495:        register int c;
                    496:        register int t;
                    497: 
                    498:        if (lastget != '\0') {
                    499:                c = lastget;
                    500:                lastget = '\0';
                    501:                return c;
                    502:        }
                    503:        switch (t = sesp->s_type) {
                    504:        case SSTR:
                    505:        case SFILE:
                    506:                yyline += eolflag;
                    507:                eolflag = 0;
                    508:                if (prpflag && sesp->s_flag) {
                    509:                        if (prpflag -= 1) {
                    510:                                prompt("\n");
                    511:                                prpflag -= 1;
                    512:                        }
                    513:                        prompt (comflag ? vps1 : vps2);
                    514:                        comflag = 0;
                    515:                }
                    516:                if ((c = getc (sesp->s_ifp)) == '\n') {
                    517:                        if (sesp->s_flag) {
                    518:                                prpflag = 1;
                    519:                                yyline = 1;
                    520:                        } else
                    521:                                eolflag = 1;
                    522:                }
                    523:                if (vflag)
                    524:                        putc(c, stderr);
                    525:                return c;
                    526:        case SARGS:
                    527:        case SARGV:
                    528:                if (sesp->s_flag)
                    529:                        return EOF;
                    530:                if ((c = * sesp->s_strp ++) == '\0') {
                    531:                        if (t == SARGV &&
                    532:                            (sesp->s_strp = * ++ sesp->s_argv) != NULL)
                    533:                                c = ' ';
                    534:                        else {
                    535:                                sesp->s_flag = 1;
                    536:                                c = EOF;
                    537:                        }
                    538:                }
                    539:                if (vflag)
                    540:                        putc (c, stderr);
                    541:                return c;
                    542:        }
                    543: }
                    544: 
                    545: 
                    546: /*
                    547:  * Unget a character.
                    548:  */
                    549: 
                    550: ungetn(c)
                    551: {
                    552:        lastget = c;
                    553: }

unix.superglobalmegacorp.com

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