Annotation of coherent/a/usr/bob/korn/lex.c, revision 1.1.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.