Annotation of coherent/d/bin/expr/expr.y, revision 1.1.1.1

1.1       root        1: /*
                      2:  * cmd/expr.y
                      3:  * yacc grammar for expr.
                      4:  * Designed so no stdio is called,
                      5:  * which makes the final object code about 1/3 smaller.
                      6:  * To make, say
                      7:  *     yacc expr.y; cc -O -o expr y.tab.c;
                      8:  */
                      9: 
                     10: %{
                     11: 
                     12: #include <ctype.h>
                     13: #include <stddef.h>
                     14: #include <stdlib.h>
                     15: #include <limits.h>
                     16: 
                     17: #define        LONGLEN 12              /* max length of NUL-terminated ASCII long */
                     18: #define        CODELEN 512             /* initial length of code buffer */
                     19: #define        CODEINC 128             /* code buffer length increment */
                     20: 
                     21: #define        EOF     (-1)
                     22: #define TRUE   (0 == 0)
                     23: #define FALSE  (0 != 0)
                     24: #define true(e)        (*(e) == '\0' || (isnum(e) && atol(e) == 0) ? FALSE : TRUE)
                     25: 
                     26: int    exstat;         /* exit status returned by main() */
                     27: char   *result;        /* final expr printed by main */
                     28: char   s0[] = "0";     /* `0' integer - `false' expr */
                     29: char   s1[] = "1";     /* `1' integer - `true' expr */
                     30: 
                     31: char   *regexp(),
                     32:        *arithop(),
                     33:        *relop(),
                     34:        *ltoa();
                     35: 
                     36: 
                     37: /*
                     38:  * The following names are used by the regular expression operator.
                     39:  */
                     40: #define BRSIZE 10                      /* Length of brace list */
                     41: typedef        struct {
                     42:        char    *b_bp;                  /* Ptr to start of string matched */
                     43:        char    *b_ep;                  /* Ptr to end of string matched */
                     44: } BRACE;
                     45: 
                     46: #define CSNUL  000                     /* End of expression */
                     47: #define CSSOL  001                     /* Match start of line */
                     48: #define CSEOL  002                     /* End of line */
                     49: #define CSOPR  003                     /* \( */
                     50: #define CSCPR  004                     /* \) */
                     51: #define CSBRN  005                     /* Match nth brace */
                     52: #define CSDOT  006                     /* Any character */
                     53: #define CMDOT  007                     /* Stream of any characters */
                     54: #define CSCHR  010                     /* Match given character */
                     55: #define CMCHR  011                     /* Match stream of given characters */
                     56: #define CSCCL  014                     /* Character class */
                     57: #define CMCCL  015                     /* Stream of character class */
                     58: #define CSNCL  016                     /* Not character class */
                     59: #define CMNCL  017                     /* Stream of not char class */
                     60: 
                     61: #define        getx(c)         *e++
                     62: #define ungetx(c)      --e
                     63: 
                     64: BRACE  brlist[BRSIZE];                 /* brace list */
                     65: int    brcount;                        /* # of braces in reg_expr */
                     66: char   *codebuf;                       /* Ptr to a compiled regular expr */
                     67: int    cbsiz = CODELEN;                        /* Initial size of codebuf */
                     68: 
                     69: char   *match();
                     70: char   *overflow();
                     71: 
                     72: %}
                     73: 
                     74: 
                     75: 
                     76: 
                     77: %union {
                     78:        char *str;
                     79: }
                     80: 
                     81: %token <str>   STR
                     82: 
                     83: %type  <str>   expr
                     84: 
                     85: %left  '|'
                     86: %left  '&'
                     87: %left  '<' '>' LE GE EQ NEQ    /* relop tokens */
                     88: %left  '+' '-'                 /* arithop tokens */
                     89: %left  '*' '/' '%'             /* arithop tokens */
                     90: %left  ':'                     /* regexp token */
                     91: %right UMINUS '!' LEN          /* uop tokens */
                     92: 
                     93: 
                     94: 
                     95: 
                     96: %%
                     97: 
                     98: 
                     99: 
                    100: 
                    101: start:
                    102:        expr            { result = $1; exstat = true(result) ? 0 : 1; }
                    103: ;
                    104: 
                    105: expr:
                    106:        '(' expr ')'    { $$ = $2; }
                    107: 
                    108: |      LEN expr        { $$ = ltoa((long)strlen($2)); }
                    109: |      '!' expr        { $$ = true($2) ? s0 : s1; }
                    110: |      '-' expr %prec UMINUS
                    111:                        { if (isnum($2))
                    112:                                $$ = ltoa(-atol($2));
                    113:                        else {
                    114:                                --avx;
                    115:                                yyerror();
                    116:                        }
                    117:                        }
                    118: 
                    119: |      expr ':' expr   { $$ = regexp($1, $3); }
                    120: 
                    121: |      expr '*' expr   { $$ = arithop('*', $1, $3); }
                    122: |      expr '/' expr   { $$ = arithop('/', $1, $3); }
                    123: |      expr '%' expr   { $$ = arithop('%', $1, $3); }
                    124: |      expr '+' expr   { $$ = arithop('+', $1, $3); }
                    125: |      expr '-' expr   { $$ = arithop('-', $1, $3); }
                    126: 
                    127: |      expr '<' expr   { $$ = relop('<', $1, $3); }
                    128: |      expr '>' expr   { $$ = relop('>', $1, $3); }
                    129: |      expr LE expr    { $$ = relop(LE, $1, $3); }
                    130: |      expr GE expr    { $$ = relop(GE, $1, $3); }
                    131: |      expr EQ expr    { $$ = relop(EQ, $1, $3); }
                    132: |      expr NEQ expr   { $$ = relop(NEQ, $1, $3); }
                    133: 
                    134: |      expr '&' expr   { $$ = true($3) ? $1 : s0; }
                    135: |      expr '|' expr   { $$ = true($1) ? $1 : $3; }
                    136: 
                    137: |      '{' expr ',' expr '}'           { $$ = true($2) ? $4 : s0; }
                    138: |      '{' expr ',' expr ',' expr '}'  { $$ = true($2) ? $4 : $6; }
                    139: 
                    140: |      STR             { $$ = $1; }
                    141: |      error           { yyerror(); }
                    142: ;
                    143: 
                    144: 
                    145: 
                    146: 
                    147: %%
                    148: 
                    149: 
                    150: 
                    151: 
                    152: char   **av;           /* Global version of argv[] in main() */
                    153: int    avx;            /* Index into av[] */
                    154: 
                    155: main(argc, argv)
                    156: int argc;
                    157: char **argv;
                    158: {
                    159:        if (argc == 1)
                    160:                return 2;
                    161:        av = argv;
                    162:        yyparse();
                    163:        output(result, 1);
                    164:        output("\n", 1);
                    165:        return exstat;
                    166: }
                    167: 
                    168: 
                    169: char *
                    170: arithop(op, e1, e2)
                    171: register int op;
                    172: register char *e1, *e2;
                    173: {
                    174:        register long v1, v2;
                    175: 
                    176:        if (!isnum(e1)) {
                    177:                avx -= 3;
                    178:                yyerror();
                    179:        }
                    180:        if (!isnum(e2)) {
                    181:                --avx;
                    182:                yyerror();
                    183:        }
                    184: 
                    185:        v1 = atol(e1);
                    186:        v2 = atol(e2);
                    187:        switch (op) {
                    188:        case '+':
                    189:                v1 += v2;
                    190:                break;
                    191:        case '-':
                    192:                v1 -= v2;
                    193:                break;
                    194:        case '*':
                    195:                v1 *= v2;
                    196:                break;
                    197:        case '/':
                    198:                if (v2 == 0) {
                    199:                        divzero ();
                    200:                        v1 = LONG_MAX;
                    201:                } else
                    202:                        v1 /= v2;
                    203:                break;
                    204:        case '%':
                    205:                if (v2 == 0) {
                    206:                        divzero ();
                    207:                        v1 = 0;
                    208:                } else
                    209:                        v1 %= v2;
                    210:                break;
                    211:        }
                    212:        return ltoa(v1);
                    213: }
                    214: 
                    215: char *
                    216: relop(op, e1, e2)
                    217: register int op;
                    218: register char *e1, *e2;
                    219: {
                    220:        register int cmp;
                    221:        register long v1, v2;
                    222: 
                    223:        if (!isnum(e1) || !isnum(e2))
                    224:                cmp = strcmp(e1, e2);
                    225:        else {
                    226:                v1 = atol(e1);
                    227:                v2 = atol(e2);
                    228:                cmp = (v1 > v2) ? 1 : (v1 == v2) ? 0 : -1;
                    229:        }
                    230:        switch (op) {
                    231:        case '<':
                    232:                return (cmp < 0) ? s1 : s0;
                    233:        case '>':
                    234:                return (cmp > 0) ? s1 : s0;
                    235:        case LE:
                    236:                return (cmp <= 0) ? s1 : s0;
                    237:        case GE:
                    238:                return (cmp >= 0) ? s1 : s0;
                    239:        case EQ:
                    240:                return (cmp == 0) ? s1 : s0;
                    241:        case NEQ:
                    242:                return (cmp != 0) ? s1 : s0;
                    243:        }
                    244: }
                    245: 
                    246: 
                    247: char *
                    248: regexp(e1, e2)
                    249: char *e1, *e2;
                    250: {
                    251:        register char *a = e1;
                    252:        register char *b;
                    253:        register BRACE *brp;
                    254: 
                    255:        codebuf = malloc(CODELEN);
                    256:        compile(e2);
                    257:        if (brcount > 0)        /* brcount is now the number of braces in e2 */
                    258:                brlist[brcount].b_bp = brlist[brcount].b_ep = NULL;
                    259: #if    1
                    260:        /* Posix P1003.2 4.22.7.1: pattern search is anchored to beginning. */
                    261:        b = match(a, codebuf);
                    262: #else
                    263:        /* This code searches for unanchored match. */
                    264:        if (codebuf[0] == CSSOL)
                    265:                b = match(a, codebuf + 1);
                    266:        else
                    267:                for ( ; *a != '\0'; ++a)
                    268:                        if ((b = match(a, codebuf)) != NULL)
                    269:                                break;
                    270: #endif
                    271:        if (b == NULL)
                    272: #if    1
                    273:                /* If \(\) used, string-valued return */
                    274:                return brcount == 0 ? "0" : "";
                    275: #else
                    276:                return "0";
                    277: #endif
                    278:        if (brcount == 0)
                    279:                return ltoa((long)(b - a));
                    280: 
                    281:        /* Remaining case is extraction of fields */
                    282:        for (a = e1, brp = brlist; (b = brp->b_bp) != NULL; ++brp)
                    283:                while (b < brp->b_ep)
                    284:                        *a++ = *b++;
                    285:        *a = '\0';
                    286:        free (codebuf);
                    287:        return e1;
                    288: }
                    289: 
                    290: 
                    291: isnum(e)
                    292: register char *e;
                    293: {
                    294:        register int c;
                    295: 
                    296:        if ((c = * e ++) == '-')        /* || c == '+' Removed for POSIX */
                    297:                c = * e ++;
                    298:        do
                    299:                if (! isdigit (c))
                    300:                        return FALSE;
                    301:        while ((c = * e ++) != 0);
                    302:        return TRUE;
                    303: }
                    304: 
                    305: /*
                    306:  * Convert long to ascii. Return pointer to the necessary malloced storage.
                    307:  */
                    308: char *
                    309: ltoa(n)
                    310: register long n;
                    311: {
                    312:        char buf[LONGLEN];
                    313:        register char *bp = buf;
                    314:        register char *ep;
                    315:        register char *e;
                    316: 
                    317:        e = ep = malloc(LONGLEN);
                    318:        if (n < 0) {
                    319:                *ep++ = '-';
                    320:                n = -n;
                    321:        }
                    322:        do {
                    323:                *bp++ = (n % 10) + '0';
                    324:                n /= 10;
                    325:        } while (n > 0);
                    326:        while (bp > buf)
                    327:                *ep++ = *--bp;
                    328:        *ep = '\0';
                    329:        return e;
                    330: }
                    331: 
                    332: 
                    333: /*
                    334:  * Compile the regular expression e into codebuf.
                    335:  * Invoke regerror() on a regular expression syntax error.
                    336:  */
                    337: compile(e)
                    338: register char *e;
                    339: {
                    340:        register int c;
                    341:        register char *cp, *lcp;
                    342:        int blevel, n, notflag, bstack[BRSIZE + 1];
                    343: 
                    344:        brcount = 0;
                    345:        blevel = 0;
                    346:        cp = &codebuf[0];
                    347:        if ((c = getx(c)) == '^') {
                    348:                *cp++ = CSSOL;
                    349:                c = getx(c);
                    350:        }
                    351:        while (c != '\0') {
                    352:                if (cp > &codebuf[cbsiz-4])
                    353:                        cp = overflow(cp);
                    354:                switch (c) {
                    355:                case '*':
                    356:                        regerror();
                    357:                case '.':
                    358:                        if ((c = getx(c)) != '*') {
                    359:                                *cp++ = CSDOT;
                    360:                                continue;
                    361:                        }
                    362:                        *cp++ = CMDOT;
                    363:                        c = getx(c);
                    364:                        continue;
                    365:                case '$':
                    366:                        if ((c = getx(c)) != '\0') {
                    367:                                ungetx(c);
                    368:                                c = '$';
                    369:                                goto character;
                    370:                        }
                    371:                        *cp++ = CSEOL;
                    372:                        continue;
                    373:                case '[':
                    374:                        /*
                    375:                         * lcp[0] will contain C<S|M><C|N>CL. lcp[1] will be
                    376:                         * the number of chars in the class. These are followed
                    377:                         * by the members of the class singly enumerated.
                    378:                         * ']' is valid only at the start of the member list.
                    379:                         * '-' is valid only at the end of the member list.
                    380:                         */
                    381:                        lcp = cp;
                    382:                        if ((c = getx(c)) == '^')
                    383:                                notflag = TRUE;
                    384:                        else {
                    385:                                notflag = FALSE;
                    386:                                ungetx(c);
                    387:                        }
                    388:                        cp += 2;
                    389:                        if ((c = getx(c)) == ']')
                    390:                                *cp++ = c;
                    391:                        else
                    392:                                ungetx(c);
                    393:                        while ((c = getx(c)) != ']') {
                    394:                                if (c == '\0')
                    395:                                        regerror();
                    396:                                if (c!='-' || cp==lcp+2) {
                    397:                                        if (cp >= &codebuf[cbsiz-4])
                    398:                                                cp = overflow(cp);
                    399:                                        *cp++ = c;
                    400:                                        continue;
                    401:                                }
                    402: 
                    403:                                /* c = '-' now. Lookahead at the next char */
                    404:                                if ((c = getx(c)) == '\0')
                    405:                                        regerror();
                    406:                                if (c == ']') {
                    407:                                        *cp++ = '-';
                    408:                                        ungetx(c);
                    409:                                        continue;
                    410:                                }
                    411:                                if ((n=cp[-1]) > c)
                    412:                                        regerror();
                    413:                                while (++n <= c) {
                    414:                                        if (cp >= &codebuf[cbsiz-4])
                    415:                                                cp = overflow(cp);
                    416:                                        *cp++ = n;
                    417:                                }
                    418:                        }
                    419:                        if ((c = getx(c)) == '*') {
                    420:                                lcp[0] = (notflag) ? CMNCL : CMCCL;
                    421:                                c = getx(c);
                    422:                        }
                    423:                        else
                    424:                                lcp[0] = (notflag) ? CSNCL : CSCCL;
                    425:                        if ((n=cp-(lcp+2)) > 255)
                    426:                                regerror();
                    427:                        *++lcp = n;
                    428:                        continue;
                    429:                case '\\':
                    430:                        switch (c = getx(c)) {
                    431:                        case '\0':
                    432:                                regerror();
                    433:                        case '(':
                    434:                                *cp++ = CSOPR;
                    435:                                *cp++ = bstack[blevel++] = brcount++;
                    436:                                c = getx(c);
                    437:                                continue;
                    438:                        case ')':
                    439:                                if (blevel == 0)
                    440:                                        regerror();
                    441:                                *cp++ = CSCPR;
                    442:                                *cp++ = bstack[--blevel];
                    443:                                c = getx(c);
                    444:                                continue;
                    445:                        default:
                    446:                                if (isascii(c) && isdigit(c)) {
                    447:                                        *cp++ = CSBRN;
                    448:                                        *cp++ = c-'0' - 1;
                    449:                                        c = getx(c);
                    450:                                        continue;
                    451:                                }
                    452:                        }
                    453:                default:
                    454:                character:
                    455:                        *cp++ = CSCHR;
                    456:                        *cp++ = c;
                    457:                        if ((c = getx(c)) == '*') {
                    458:                                cp[-2] = CMCHR;
                    459:                                c = getx(c);
                    460:                        }
                    461:                }
                    462:        }
                    463:        *cp++ = CSNUL;
                    464:        return;
                    465: }
                    466: 
                    467: /*
                    468:  * Given a pointer to a compiled expression `cp' and a pointer to a line `lp',
                    469:  * return a ptr to the char following the last char of the match
                    470:  * if successful, NULL otherwise.
                    471:  */
                    472: char *
                    473: match(lp, cp)
                    474: register char *lp, *cp;
                    475: {
                    476:        register int n;
                    477:        char *llp, *lcp;
                    478: 
                    479:        for (;;) {
                    480:                switch (*cp++) {
                    481:                case CSNUL:
                    482:                        return lp;
                    483:                case CSEOL:
                    484:                        if (*lp)
                    485:                                return NULL;
                    486:                        return lp;
                    487:                case CSOPR:
                    488:                        brlist[*cp++].b_bp = lp;
                    489:                        continue;
                    490:                case CSCPR:
                    491:                        brlist[*cp++].b_ep = lp;
                    492:                        continue;
                    493:                case CSBRN:
                    494:                        n = *cp++;
                    495:                        lcp = cp;
                    496:                        cp = brlist[n].b_bp;
                    497:                        n = brlist[n].b_ep - cp;
                    498:                        if (n > strlen(lp))
                    499:                                return NULL;
                    500:                        while (n-- > 0)
                    501:                                if (*lp++ != *cp++)
                    502:                                        return NULL;
                    503:                        cp = lcp;
                    504:                        continue;
                    505:                case CSDOT:
                    506:                        if (*lp++ == '\0')
                    507:                                return NULL;
                    508:                        continue;
                    509:                case CMDOT:
                    510:                        llp = lp;
                    511:                        while (*lp)
                    512:                                lp++;
                    513:                        goto star;
                    514:                case CSCHR:
                    515:                        if (*cp++ != *lp++)
                    516:                                return NULL;
                    517:                        continue;
                    518:                case CMCHR:
                    519:                        llp = lp;
                    520:                        while (*cp == *lp)
                    521:                                lp++;
                    522:                        cp++;
                    523:                        goto star;
                    524:                case CSCCL:
                    525:                        n = *cp++;
                    526:                        while (*cp++ != *lp)
                    527:                                if (--n == 0)
                    528:                                        return NULL;
                    529:                        lp++;
                    530:                        cp += n-1;
                    531:                        continue;
                    532:                case CMCCL:
                    533:                        llp = lp;
                    534:                        lcp = cp;
                    535:                        while (*lp) {
                    536:                                cp = lcp;
                    537:                                n = *cp++;
                    538:                                while (*cp++ != *lp)
                    539:                                        if (--n == 0)
                    540:                                                goto star;
                    541:                                lp++;
                    542:                        }
                    543:                        cp = lcp + *lcp + 1;
                    544:                        goto star;
                    545:                case CSNCL:
                    546:                        if (*lp == '\0')
                    547:                                return NULL;
                    548:                        n = *cp++;
                    549:                        while (n--)
                    550:                                if (*cp++ == *lp)
                    551:                                        return NULL;
                    552:                        lp++;
                    553:                        continue;
                    554:                case CMNCL:
                    555:                        llp = lp;
                    556:                        lcp = cp;
                    557:                        while (*lp) {
                    558:                                cp = lcp;
                    559:                                n = *cp++;
                    560:                                while (n--) {
                    561:                                        if (*cp++ == *lp) {
                    562:                                                cp = lcp + *lcp + 1;
                    563:                                                goto star;
                    564:                                        }
                    565:                                }
                    566:                                lp++;
                    567:                        }
                    568:                        cp = lcp + *lcp + 1;
                    569:                star:
                    570:                        do {
                    571:                                if (lcp=match(lp, cp))
                    572:                                        return lcp;
                    573:                        } while (--lp >= llp);
                    574:                        return NULL;
                    575:                }
                    576:        }
                    577: }
                    578: 
                    579: /*
                    580:  * overflow enlarges codebuf by CODEINC bytes. The argument is a pointer
                    581:  * to a position in codebuf - the function returns a pointer with the same
                    582:  * relative position in the new buffer.
                    583:  */
                    584: char *
                    585: overflow(pc)
                    586: register char *pc;
                    587: {
                    588:        register int posn = pc - codebuf;
                    589: 
                    590:        if ((codebuf = realloc(codebuf, cbsiz += CODEINC)) == NULL)
                    591:                regerror();
                    592:        return codebuf + posn;
                    593: }
                    594: 
                    595: /*
                    596:  * An output function to avoid having to include stdio.
                    597:  */
                    598: output(s, fildes)
                    599: register char *s;
                    600: int fildes;
                    601: {
                    602:        register int len;
                    603: 
                    604:        len = strlen(s);
                    605:        if ((write(fildes, s, len)) != len)
                    606:                exit(3);
                    607: }
                    608: 
                    609: 
                    610: yylex()
                    611: {
                    612:        register int c;
                    613: 
                    614:        if ((yylval.str = av[++avx]) == NULL)
                    615:                return EOF;
                    616:        if (av[avx][1] == '\0')
                    617:                switch (c = av[avx][0]) {
                    618:                case '{':
                    619:                case '}':
                    620:                case ',':
                    621:                case '|':
                    622:                case '&':
                    623:                case '<':
                    624:                case '>':
                    625:                case '+':
                    626:                case '-':
                    627:                case '*':
                    628:                case '/':
                    629:                case '%':
                    630:                case ':':
                    631:                case '!':
                    632:                case '(':
                    633:                case ')':
                    634:                        return c;
                    635:                default:
                    636:                        return STR;
                    637:                }
                    638:        if (av[avx][1] == '='  &&  av[avx][2] == '\0')
                    639:                switch (c = av[avx][0]) {
                    640:                case '<':
                    641:                        return LE;
                    642:                case '>':
                    643:                        return GE;
                    644:                case '=':
                    645:                        return EQ;
                    646:                case '!':
                    647:                        return NEQ;
                    648:                default:
                    649:                        return STR;
                    650:                }
                    651:        return (strcmp(yylval.str, "len") == 0) ? LEN : STR;
                    652: }
                    653: 
                    654: /*
                    655:  * The common code between yyerror() and regerror() (in regexp.c) is split
                    656:  * off into errexit().
                    657:  */
                    658: yyerror()
                    659: {
                    660:        output("expr: ", 2);
                    661:        errexit();
                    662: }
                    663: regerror()
                    664: {
                    665:        output("expr: regular expression ", 2);
                    666:        --avx;
                    667:        errexit();
                    668: }
                    669: void dieat () {
                    670:        output(ltoa((long) avx), 2);
                    671:        output("\n", 2);
                    672:        exit(2);
                    673: }
                    674: divzero() {
                    675:        output ("Attempt to divide by zero at argument # ", 2);
                    676:        -- avx;
                    677:        dieat ();
                    678: }
                    679: errexit()
                    680: {
                    681:        output("syntax error at argument # ", 2);
                    682:        dieat ();
                    683: }
                    684: 
                    685: /* end of cmd/expr.y */

unix.superglobalmegacorp.com

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