Annotation of coherent/a/usr/bob/korn/lex.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * lexical analysis and source input
        !             3:  */
        !             4: 
        !             5: static char *RCSid = "$Header: lex.c,v 3.1 88/11/03 09:16:43 egisin Exp $";
        !             6: 
        !             7: #include <stddef.h>
        !             8: #include <stdlib.h>
        !             9: #include <stdio.h>
        !            10: #include <string.h>
        !            11: #include <errno.h>
        !            12: #include <setjmp.h>
        !            13: #include <unistd.h>
        !            14: #include "sh.h"
        !            15: #include "lex.h"
        !            16: #include "tree.h"
        !            17: #include "table.h"
        !            18: #include "expand.h"
        !            19: 
        !            20:        int     ttyfd = -1;             /* tty fd for edit and jobs */
        !            21:        char   *history[HISTORY];       /* saved commands */
        !            22:        char  **histptr = history - 1;  /* last history item */
        !            23:        int     histpush;               /* number of pushed fc commands */
        !            24: 
        !            25: static int     alias;
        !            26: static int     getsc_ ARGS((void));
        !            27: 
        !            28: /* optimized getsc_() */
        !            29: #define        getsc() ((*source->str != 0) ? *source->str++ : getsc_())
        !            30: #define        ungetsc() ((source->str != null) ? (source->str--) : source->str)
        !            31: 
        !            32: /*
        !            33:  * Lexical analyzer
        !            34:  *
        !            35:  * tokens are not regular expressions, they are LL(1).
        !            36:  * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
        !            37:  * hence the state stack.
        !            38:  */
        !            39: 
        !            40: int
        !            41: yylex(cf)
        !            42:        int cf;
        !            43: {
        !            44:        register int c, state;
        !            45:        char states [64], *statep = states;
        !            46:        XString ws;             /* expandable output word */
        !            47:        register char *wp;      /* output word pointer */
        !            48:        register char *sp, *dp;
        !            49:        int istate;
        !            50:        int c2;
        !            51: 
        !            52:   Again:
        !            53:        Xinit(ws, wp, 256);
        !            54:        if (alias) {                    /* trailing ' ' in alias definition */
        !            55:                alias = 0;
        !            56:                cf |= ALIAS;
        !            57:        }
        !            58: 
        !            59:        if (cf&ONEWORD)
        !            60:                istate = SWORD;
        !            61:        else {                  /* normal lexing */
        !            62:                istate = SBASE;
        !            63:                while ((c = getsc()) == ' ' || c == '\t')
        !            64:                        ;
        !            65:                if (c == '#')
        !            66:                        while ((c = getsc()) != 0 && c != '\n')
        !            67:                                ;
        !            68:                ungetsc();
        !            69:        }
        !            70: 
        !            71:        /* collect non-special or quoted characters to form word */
        !            72:        for (*statep = state = istate;
        !            73:             !((c = getsc()) == 0 || state == SBASE && ctype(c, C_LEX1)); ) {
        !            74:                Xcheck(ws, wp);
        !            75:                switch (state) {
        !            76:                  case SBASE:
        !            77:                  Sbase:
        !            78:                        switch (c) {
        !            79:                          case '\\':
        !            80:                                c = getsc();
        !            81:                                if (c != '\n')
        !            82:                                        *wp++ = QCHAR, *wp++ = c;
        !            83:                                else
        !            84:                                        if (wp == Xstring(ws, wp))
        !            85:                                                goto Again;
        !            86:                                break;
        !            87:                          case '\'':
        !            88:                                *++statep = state = SSQUOTE;
        !            89:                                *wp++ = OQUOTE;
        !            90:                                break;
        !            91:                          case '"':
        !            92:                                *++statep = state = SDQUOTE;
        !            93:                                *wp++ = OQUOTE;
        !            94:                                break;
        !            95:                          default:
        !            96:                                goto Subst;
        !            97:                        }
        !            98:                        break;
        !            99: 
        !           100:                  Subst:
        !           101:                        switch (c) {
        !           102:                          case '\\':
        !           103:                                c = getsc();
        !           104:                                switch (c) {
        !           105:                                  case '\n':
        !           106:                                        break;
        !           107:                                  case '"': case '\\':
        !           108:                                  case '$': case '`':
        !           109:                                        *wp++ = QCHAR, *wp++ = c;
        !           110:                                        break;
        !           111:                                  default:
        !           112:                                        *wp++ = CHAR, *wp++ = '\\';
        !           113:                                        *wp++ = CHAR, *wp++ = c;
        !           114:                                        break;
        !           115:                                }
        !           116:                                break;
        !           117:                          case '$':
        !           118:                                c = getsc();
        !           119:                                if (c == '(') {
        !           120:                                        *++statep = state = SPAREN;
        !           121:                                        *wp++ = COMSUB;
        !           122:                                } else
        !           123:                                if (c == '{') {
        !           124:                                        *++statep = state = SBRACE;
        !           125:                                        *wp++ = OSUBST;
        !           126:                                        c = getsc();
        !           127:                                        do {
        !           128:                                                Xcheck(ws, wp);
        !           129:                                                *wp++ = c;
        !           130:                                                c = getsc();
        !           131:                                        } while (ctype(c, C_ALPHA|C_DIGIT));
        !           132:                                        *wp++ = 0;
        !           133:                                        /* todo: more compile-time checking */
        !           134:                                        if (c == '}')
        !           135:                                                ungetsc();
        !           136:                                        else if (c == '#' || c == '%') {
        !           137:                                                /* Korn pattern trimming */
        !           138:                                                if (getsc() == c)
        !           139:                                                        c |= 0x80;
        !           140:                                                else
        !           141:                                                        ungetsc();
        !           142:                                                *wp++ = c;
        !           143:                                        } else if (c == ':')
        !           144:                                                *wp++ = 0x80|getsc();
        !           145:                                        else
        !           146:                                                *wp++ = c;
        !           147:                                } else if (ctype(c, C_ALPHA)) {
        !           148:                                        *wp++ = OSUBST;
        !           149:                                        do {
        !           150:                                                *wp++ = c;
        !           151:                                                c = getsc();
        !           152:                                        } while (ctype(c, C_ALPHA|C_DIGIT));
        !           153:                                        *wp++ = 0;
        !           154:                                        *wp++ = CSUBST;
        !           155:                                        ungetsc();
        !           156:                                } else if (ctype(c, C_DIGIT|C_VAR1)) {
        !           157:                                        *wp++ = OSUBST;
        !           158:                                        *wp++ = c;
        !           159:                                        *wp++ = 0;
        !           160:                                        *wp++ = CSUBST;
        !           161:                                } else {
        !           162:                                        *wp++ = CHAR, *wp++ = '$';
        !           163:                                        *wp++ = CHAR, *wp++ = c;
        !           164:                                }
        !           165:                                break;
        !           166:                          case '`':
        !           167:                                *++statep = state = SBQUOTE;
        !           168:                                *wp++ = COMSUB;
        !           169:                                break;
        !           170:                          default:
        !           171:                                *wp++ = CHAR, *wp++ = c;
        !           172:                        }
        !           173:                        break;
        !           174: 
        !           175:                  case SSQUOTE:
        !           176:                        if (c == '\'') {
        !           177:                                state = *--statep;
        !           178:                                *wp++ = CQUOTE;
        !           179:                        } else
        !           180:                                *wp++ = QCHAR, *wp++ = c;
        !           181:                        break;
        !           182: 
        !           183:                  case SDQUOTE:
        !           184:                        if (c == '"') {
        !           185:                                state = *--statep;
        !           186:                                *wp++ = CQUOTE;
        !           187:                        } else
        !           188:                                goto Subst;
        !           189:                        break;
        !           190: 
        !           191:                  case SPAREN:
        !           192:                        if (c == '(')
        !           193:                                *++statep = state;
        !           194:                        else if (c == ')')
        !           195:                                state = *--statep;
        !           196:                        if (state == SPAREN)
        !           197:                                *wp++ = c;
        !           198:                        else
        !           199:                                *wp++ = 0; /* end of COMSUB */
        !           200:                        break;
        !           201: 
        !           202:                  case SBRACE:
        !           203:                        if (c == '}') {
        !           204:                                state = *--statep;
        !           205:                                *wp++ = CSUBST;
        !           206:                        } else
        !           207:                                goto Sbase;
        !           208:                        break;
        !           209: 
        !           210:                  case SBQUOTE:
        !           211:                        if (c == '`') {
        !           212:                                *wp++ = 0;
        !           213:                                state = *--statep;
        !           214:                        } else  /* todo: handle silly `\`` escapes */
        !           215:                                /* todo: both \" and \` in "`...`" */
        !           216:                                *wp++ = c;
        !           217:                        break;
        !           218: 
        !           219:                  case SWORD:   /* ONEWORD */
        !           220:                        goto Subst;
        !           221:                }
        !           222:        }
        !           223:        if (state != istate)
        !           224:                yyerror("no closing quote");
        !           225: 
        !           226:        if (c == '<' || c == '>') {
        !           227:                char *cp = Xstring(ws, wp);
        !           228:                if (wp > cp && cp[0] == CHAR && digit(cp[1])) {
        !           229:                        wp = cp; /* throw away word */
        !           230:                        iounit = cp[1] - '0';
        !           231:                } else
        !           232:                        iounit = -1; /* default */
        !           233:        }
        !           234: 
        !           235:        if (wp == Xstring(ws, wp) && state == SBASE) {
        !           236:                Xfree(ws, sp);  /* free word */
        !           237:                /* no word, process LEX1 character */
        !           238:                switch (c) {
        !           239:                  default:
        !           240:                        return c;
        !           241: 
        !           242:                  case '|':
        !           243:                  case '&':
        !           244:                  case ';':
        !           245:                        if (getsc() == c)
        !           246:                                c = (c == ';') ? BREAK :
        !           247:                                    (c == '|') ? LOGOR :
        !           248:                                    (c == '&') ? LOGAND :
        !           249:                                    YYERRCODE;
        !           250:                        else
        !           251:                                ungetsc();
        !           252:                        return c;
        !           253: 
        !           254:                  case '>':
        !           255:                  case '<':
        !           256:                        c2 = getsc();
        !           257:                        if (c2 == '>' || c2 == '<') {
        !           258:                                if (c2 != c)
        !           259:                                        yyerror("syntax error");
        !           260:                                yylval.i = c == '>'? IOWRITE|IOCAT: IOHERE;
        !           261:                                c2 = getsc();
        !           262:                        } else
        !           263:                                yylval.i = c == '>'? IOWRITE: IOREAD;
        !           264:                        if (c2 != '&' || yylval.i == IOHERE)
        !           265:                                ungetsc();
        !           266:                        else
        !           267:                                yylval.i |= IODUP;
        !           268:                        return REDIR;
        !           269: 
        !           270:                  case '\n':
        !           271:                        gethere();
        !           272:                        if (cf & CONTIN)
        !           273:                                goto Again;
        !           274:                        return c;
        !           275: 
        !           276:                  case '(':
        !           277:                        c2 = getsc();
        !           278:                        if (c2 == ')')
        !           279:                                c = MPAREN;
        !           280:                        else if (c2 == '(')
        !           281:                                yyerror("(( not supported");
        !           282:                        else
        !           283:                                ungetsc();
        !           284:                  case ')':
        !           285:                        return c;
        !           286:                }
        !           287:        }
        !           288: 
        !           289:        *wp++ = EOS;            /* terminate word */
        !           290:        yylval.cp = Xclose(ws, wp);
        !           291:        if (state == SWORD)     /* ONEWORD? */
        !           292:                return LWORD;
        !           293:        ungetsc();              /* unget terminator */
        !           294: 
        !           295:        /* copy word to unprefixed string ident */
        !           296:        for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; )
        !           297:                *dp++ = *sp++;
        !           298:        *dp = 0;
        !           299: #if 0
        !           300:        if (*ident == '~' || (dp = strchr(ident, '=')) != NULL && dp[1] == '~')
        !           301:                "Tilde expansion";
        !           302: #endif
        !           303:        if (c != EOS)
        !           304:                *ident = 0;     /* word is not unquoted */
        !           305: 
        !           306:        if (*ident != 0 && (cf&(KEYWORD|ALIAS))) {
        !           307:                register struct tbl *p;
        !           308: 
        !           309:                p = tsearch(&lexicals, ident, hash(ident));
        !           310:                if (p != NULL && (p->flag&ISSET))
        !           311:                        if (p->type == CKEYWD && (cf&KEYWORD)) {
        !           312:                                afree(yylval.cp, ATEMP);
        !           313:                                return p->val.i;
        !           314:                        } else
        !           315:                        if (p->type == CALIAS && (cf&ALIAS)) {
        !           316:                                register Source *s;
        !           317: 
        !           318:                                /* check for recursive aliasing */
        !           319:                                for (s = source; s->type == SALIAS; s = s->next)
        !           320:                                        if (s->u.tblp == p)
        !           321:                                                return LWORD;
        !           322:                                afree(yylval.cp, ATEMP);
        !           323: 
        !           324:                                /* push alias expansion */
        !           325:                                s = pushs(SALIAS);
        !           326:                                s->str = p->val.s;
        !           327:                                s->u.tblp = p;
        !           328:                                s->next = source;
        !           329:                                source = s;
        !           330:                                goto Again;
        !           331:                        }
        !           332:        }
        !           333: 
        !           334:        return LWORD;
        !           335: }
        !           336: 
        !           337: static void readhere();
        !           338: 
        !           339: gethere()
        !           340: {
        !           341:        register struct ioword **p;
        !           342: 
        !           343:        for (p = heres; p < herep; p++)
        !           344:                readhere(*p);
        !           345:        herep = heres;
        !           346: }
        !           347: 
        !           348: /*
        !           349:  * read "<<word" text into temp file
        !           350:  * todo: set up E_ERR to fclose(f) on unwind
        !           351:  */
        !           352: 
        !           353: static void
        !           354: readhere(iop)
        !           355:        register struct ioword *iop;
        !           356: {
        !           357:        register FILE *f;
        !           358:        struct temp *h;
        !           359:        register int c;
        !           360:        char *eof;
        !           361:        register char *cp;
        !           362:        int strip;
        !           363:        char line [LINE+1];
        !           364: 
        !           365:        eof = evalstr(iop->name, 0);
        !           366:        strip = *eof == '-';
        !           367:        eof += strip;           /* skip '-' */
        !           368: 
        !           369:        h = maketemp(ATEMP);
        !           370:        h->next = e.temps; e.temps = h;
        !           371:        iop->name = h->name;
        !           372:        f = fopen(h->name, "w");
        !           373:        if (f == NULL)
        !           374:                errorf("Cannot create temporary file\n");
        !           375:        setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
        !           376: 
        !           377:        for (;;) {
        !           378:                cp = line;
        !           379:                while ((c = getsc()) != '\n') {
        !           380:                        if (c == 0)
        !           381:                                errorf("here document `%s' unclosed\n", eof);
        !           382:                        if (cp >= line+LINE)
        !           383:                                break;
        !           384:                        *cp++ = c;
        !           385:                }
        !           386:                ungetsc();
        !           387:                *cp = 0;
        !           388:                for (cp = line; strip && *cp == '\t'; cp++)
        !           389:                        ;
        !           390:                if (strcmp(eof, cp) == 0 || c == 0)
        !           391:                        break;
        !           392:                while ((c = *cp++) != '\0')
        !           393:                        putc(c, f);
        !           394:                while ((c = getsc()) != '\n') {
        !           395:                        if (c == 0)
        !           396:                                errorf("here document `%s' unclosed\n", eof);
        !           397:                        putc(c, f);
        !           398:                }
        !           399:                putc(c, f);
        !           400:        }
        !           401:        fclose(f);
        !           402: }
        !           403: 
        !           404: void
        !           405: yyerror(msg)
        !           406:        Const char *msg;
        !           407: {
        !           408:        yynerrs++;
        !           409:        while (source->type == SALIAS) /* pop aliases */
        !           410:                source = source->next;
        !           411:        if (source->file != NULL)
        !           412:                shellf("%s[%d]: ", source->file, source->line);
        !           413:        source->str = null;     /* zap pending input */
        !           414:        errorf("%s\n", msg);
        !           415: }
        !           416: 
        !           417: /*
        !           418:  * input for yylex with alias expansion
        !           419:  */
        !           420: 
        !           421: Source *
        !           422: pushs(type)
        !           423:        int type;
        !           424: {
        !           425:        register Source *s;
        !           426: 
        !           427:        s = (Source *) alloc(sizeof(Source), ATEMP);
        !           428:        s->type = type;
        !           429:        s->str = null;          /* "" */
        !           430:        s->line = 0;
        !           431:        s->file = NULL;
        !           432:        s->echo = 0;
        !           433:        s->next = NULL;
        !           434:        return s;
        !           435: }
        !           436: 
        !           437: int
        !           438: getsc_()
        !           439: {
        !           440:        register Source *s = source;
        !           441:        register int c;
        !           442: 
        !           443:        while ((c = *s->str++) == 0) {
        !           444:                s->str = NULL;          /* return 0 for EOF by default */
        !           445:                switch (s->type) {
        !           446:                  case SEOF:
        !           447:                        s->str = null;
        !           448:                        return 0;
        !           449: 
        !           450:                  case STTY:
        !           451:                        if (histpush < 0) {     /* commands pushed by dofc */
        !           452:                                s->type = SHIST;
        !           453:                                s->str = null;
        !           454:                                continue;
        !           455:                        }
        !           456: #if COHERENT
        !           457:                        mail();
        !           458: #endif
        !           459:                        s->line++;
        !           460:                        s->str = line;
        !           461:                        line[0] = '\0';
        !           462:                        pprompt(prompt);
        !           463:                        flushshf(1);    flushshf(2);
        !           464: #if EDIT
        !           465:                        if (flag[FEMACS])
        !           466:                                c = x_read(ttyfd, line, LINE);
        !           467:                        else
        !           468: #endif
        !           469:                                c = read(ttyfd, line, LINE);
        !           470:                        if (c < 0)      /* read error */
        !           471:                                c = 0;
        !           472:                        if (c == 0) /* EOF */
        !           473:                                s->str = NULL;  /* was NULL */
        !           474:                        prompt = strval(global("PS2"));
        !           475:                        line[c] = '\0';
        !           476:                        if (line[0] != '\n')
        !           477:                                histsave(line);
        !           478:                        else
        !           479:                                s->line--;
        !           480:                        break;
        !           481: 
        !           482:                  case SHIST:
        !           483:                        if (histpush == 0) {
        !           484:                                s->type = STTY;
        !           485:                                s->str = null;
        !           486:                                continue;
        !           487:                        }
        !           488:                        s->line++;
        !           489:                        s->str = histptr[++histpush];
        !           490:                        pprompt("!< "); /* todo: PS9 */
        !           491:                        shellf("%s\n", s->str);
        !           492:                        strcpy(line, s->str);
        !           493:                        s->str = strchr(line, 0);
        !           494:                        *s->str++ = '\n';
        !           495:                        *s->str = 0;
        !           496:                        s->str = line;
        !           497:                        break;
        !           498: 
        !           499:                  case SFILE:
        !           500:                        s->line++;
        !           501:                        s->str = fgets(line, LINE, s->u.file);
        !           502:                        if (s->str == NULL)
        !           503:                                if (s->u.file != stdin)
        !           504:                                        fclose(s->u.file);
        !           505:                        break;
        !           506: 
        !           507:                  case SWSTR:
        !           508:                        break;
        !           509: 
        !           510:                  case SSTRING:
        !           511:                        s->str = "\n";
        !           512:                        s->type = SEOF;
        !           513:                        break;
        !           514: 
        !           515:                  case SWORDS:
        !           516:                        s->str = *s->u.strv++;
        !           517:                        s->type = SWORDSEP;
        !           518:                        break;
        !           519: 
        !           520:                  case SWORDSEP:
        !           521:                        if (*s->u.strv == NULL) {
        !           522:                                s->str = "\n";
        !           523:                                s->type = SEOF;
        !           524:                        } else {
        !           525:                                s->str = " ";
        !           526:                                s->type = SWORDS;
        !           527:                        }
        !           528:                        break;
        !           529: 
        !           530:                  case SALIAS:
        !           531:                        s->str = s->u.tblp->val.s;
        !           532:                        if (s->str[0] != 0 && strchr(s->str, 0)[-1] == ' ')
        !           533:                                alias = 1;      /* trailing ' ' */
        !           534:                        source = s = s->next;   /* pop source stack */
        !           535:                        continue;
        !           536:                }
        !           537:                if (s->str == NULL) {
        !           538:                        s->type = SEOF;
        !           539:                        s->str = null; /* "" */
        !           540:                        return 0;
        !           541:                }
        !           542:                if (s->echo)
        !           543:                        fputs(s->str, shlout);
        !           544:        }
        !           545:        return c;
        !           546: }
        !           547: 
        !           548: pprompt(cp)
        !           549:        register char *cp;
        !           550: {
        !           551:        while (*cp != 0)
        !           552:                if (*cp != '!')
        !           553:                        putc(*cp++, shlout);
        !           554:                else
        !           555:                        if (*++cp == '!')
        !           556:                                putc(*cp++, shlout);
        !           557:                        else
        !           558:                                shellf("%d", source->line);
        !           559:        fflush(shlout);
        !           560: }
        !           561: 

unix.superglobalmegacorp.com

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