[BACK]Return to expr.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / m4

Annotation of src/usr.bin/m4/expr.c, Revision 1.10

1.10    ! espie       1: /*     $OpenBSD: expr.c,v 1.9 1999/11/15 22:12:00 espie Exp $  */
1.1       deraadt     2: /*     $NetBSD: expr.c,v 1.7 1995/09/28 05:37:31 tls Exp $     */
                      3:
                      4: /*
                      5:  * Copyright (c) 1989, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to Berkeley by
                      9:  * Ozan Yigit at York University.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *     This product includes software developed by the University of
                     22:  *     California, Berkeley and its contributors.
                     23:  * 4. Neither the name of the University nor the names of its contributors
                     24:  *    may be used to endorse or promote products derived from this software
                     25:  *    without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     28:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     29:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     30:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     31:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     32:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     33:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     34:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     35:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     36:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     37:  * SUCH DAMAGE.
                     38:  */
                     39:
                     40: #ifndef lint
                     41: #if 0
                     42: static char sccsid[] = "@(#)expr.c     8.2 (Berkeley) 4/29/95";
                     43: #else
1.10    ! espie      44: static char rcsid[] = "$OpenBSD: expr.c,v 1.9 1999/11/15 22:12:00 espie Exp $";
1.1       deraadt    45: #endif
                     46: #endif /* not lint */
                     47:
                     48: #include <sys/cdefs.h>
1.10    ! espie      49: #include <ctype.h>
        !            50: #include <err.h>
        !            51: #include <stddef.h>
1.1       deraadt    52: #include <stdio.h>
1.5       espie      53: #include "mdef.h"
1.10    ! espie      54: #include "extern.h"
1.1       deraadt    55:
                     56: /*
                     57:  *      expression evaluator: performs a standard recursive
                     58:  *      descent parse to evaluate any expression permissible
                     59:  *      within the following grammar:
                     60:  *
                     61:  *      expr    :       query EOS
                     62:  *      query   :       lor
                     63:  *              |       lor "?" query ":" query
                     64:  *      lor     :       land { "||" land }
                     65:  *      land    :       not { "&&" not }
                     66:  *     not     :       eqrel
                     67:  *             |       '!' not
                     68:  *      eqrel   :       shift { eqrelop shift }
                     69:  *      shift   :       primary { shop primary }
                     70:  *      primary :       term { addop term }
                     71:  *      term    :       exp { mulop exp }
                     72:  *     exp     :       unary { expop unary }
                     73:  *      unary   :       factor
                     74:  *              |       unop unary
                     75:  *      factor  :       constant
                     76:  *              |       "(" query ")"
                     77:  *      constant:       num
                     78:  *              |       "'" CHAR "'"
                     79:  *      num     :       DIGIT
                     80:  *              |       DIGIT num
                     81:  *      shop    :       "<<"
                     82:  *              |       ">>"
                     83:  *      eqrel   :       "="
                     84:  *              |       "=="
                     85:  *              |       "!="
                     86:  *             |       "<"
                     87:  *              |       ">"
                     88:  *              |       "<="
                     89:  *              |       ">="
                     90:  *
                     91:  *
                     92:  *      This expression evaluator is lifted from a public-domain
                     93:  *      C Pre-Processor included with the DECUS C Compiler distribution.
                     94:  *      It is hacked somewhat to be suitable for m4.
                     95:  *
                     96:  *      Originally by:  Mike Lutz
                     97:  *                      Bob Harper
                     98:  */
                     99:
                    100: #define EQL     0
                    101: #define NEQ     1
                    102: #define LSS     2
                    103: #define LEQ     3
                    104: #define GTR     4
                    105: #define GEQ     5
                    106: #define OCTAL   8
                    107: #define DECIMAL 10
1.5       espie     108: #define HEX    16
1.1       deraadt   109:
1.10    ! espie     110: static const char *nxtch;                     /* Parser scan pointer */
1.1       deraadt   111:
                    112: static int query __P((void));
                    113: static int lor __P((void));
                    114: static int land __P((void));
                    115: static int not __P((void));
                    116: static int eqrel __P((void));
                    117: static int shift __P((void));
                    118: static int primary __P((void));
                    119: static int term __P((void));
                    120: static int exp __P((void));
                    121: static int unary __P((void));
                    122: static int factor __P((void));
                    123: static int constant __P((void));
                    124: static int num __P((void));
                    125: static int geteqrel __P((void));
                    126: static int skipws __P((void));
1.10    ! espie     127: static void experr __P((const char *));
1.1       deraadt   128:
                    129: /*
                    130:  * For longjmp
                    131:  */
                    132: #include <setjmp.h>
                    133: static jmp_buf expjump;
                    134:
                    135: /*
                    136:  * macros:
                    137:  *      ungetch - Put back the last character examined.
                    138:  *      getch   - return the next character from expr string.
                    139:  */
                    140: #define ungetch()       nxtch--
                    141: #define getch()         *nxtch++
                    142:
                    143: int
                    144: expr(expbuf)
1.10    ! espie     145:        const char *expbuf;
1.1       deraadt   146: {
1.7       espie     147:        int rval;
1.1       deraadt   148:
                    149:        nxtch = expbuf;
                    150:        if (setjmp(expjump) != 0)
                    151:                return FALSE;
                    152:
                    153:        rval = query();
                    154:        if (skipws() == EOS)
                    155:                return rval;
                    156:
                    157:        printf("m4: ill-formed expression.\n");
                    158:        return FALSE;
                    159: }
                    160:
                    161: /*
                    162:  * query : lor | lor '?' query ':' query
                    163:  */
                    164: static int
                    165: query()
                    166: {
1.7       espie     167:        int bool, true_val, false_val;
1.1       deraadt   168:
                    169:        bool = lor();
                    170:        if (skipws() != '?') {
                    171:                ungetch();
                    172:                return bool;
                    173:        }
                    174:
                    175:        true_val = query();
                    176:        if (skipws() != ':')
                    177:                experr("bad query");
                    178:
                    179:        false_val = query();
                    180:        return bool ? true_val : false_val;
                    181: }
                    182:
                    183: /*
                    184:  * lor : land { '||' land }
                    185:  */
                    186: static int
                    187: lor()
                    188: {
1.7       espie     189:        int c, vl, vr;
1.1       deraadt   190:
                    191:        vl = land();
                    192:        while ((c = skipws()) == '|') {
                    193:                if (getch() != '|')
                    194:                        ungetch();
                    195:                vr = land();
                    196:                vl = vl || vr;
                    197:        }
                    198:
                    199:        ungetch();
                    200:        return vl;
                    201: }
                    202:
                    203: /*
                    204:  * land : not { '&&' not }
                    205:  */
                    206: static int
                    207: land()
                    208: {
1.7       espie     209:        int c, vl, vr;
1.1       deraadt   210:
                    211:        vl = not();
                    212:        while ((c = skipws()) == '&') {
                    213:                if (getch() != '&')
                    214:                        ungetch();
                    215:                vr = not();
                    216:                vl = vl && vr;
                    217:        }
                    218:
                    219:        ungetch();
                    220:        return vl;
                    221: }
                    222:
                    223: /*
                    224:  * not : eqrel | '!' not
                    225:  */
                    226: static int
                    227: not()
                    228: {
1.7       espie     229:        int val, c;
1.1       deraadt   230:
                    231:        if ((c = skipws()) == '!' && getch() != '=') {
                    232:                ungetch();
                    233:                val = not();
                    234:                return !val;
                    235:        }
                    236:
                    237:        if (c == '!')
                    238:                ungetch();
                    239:        ungetch();
                    240:        return eqrel();
                    241: }
                    242:
                    243: /*
                    244:  * eqrel : shift { eqrelop shift }
                    245:  */
                    246: static int
                    247: eqrel()
                    248: {
1.7       espie     249:        int vl, vr, eqrel;
1.1       deraadt   250:
                    251:        vl = shift();
                    252:        while ((eqrel = geteqrel()) != -1) {
                    253:                vr = shift();
                    254:
                    255:                switch (eqrel) {
                    256:
                    257:                case EQL:
                    258:                        vl = (vl == vr);
                    259:                        break;
                    260:                case NEQ:
                    261:                        vl = (vl != vr);
                    262:                        break;
                    263:
                    264:                case LEQ:
                    265:                        vl = (vl <= vr);
                    266:                        break;
                    267:                case LSS:
                    268:                        vl = (vl < vr);
                    269:                        break;
                    270:                case GTR:
                    271:                        vl = (vl > vr);
                    272:                        break;
                    273:                case GEQ:
                    274:                        vl = (vl >= vr);
                    275:                        break;
                    276:                }
                    277:        }
                    278:        return vl;
                    279: }
                    280:
                    281: /*
                    282:  * shift : primary { shop primary }
                    283:  */
                    284: static int
                    285: shift()
                    286: {
1.7       espie     287:        int vl, vr, c;
1.1       deraadt   288:
                    289:        vl = primary();
                    290:        while (((c = skipws()) == '<' || c == '>') && getch() == c) {
                    291:                vr = primary();
                    292:
                    293:                if (c == '<')
                    294:                        vl <<= vr;
                    295:                else
                    296:                        vl >>= vr;
                    297:        }
                    298:
                    299:        if (c == '<' || c == '>')
                    300:                ungetch();
                    301:        ungetch();
                    302:        return vl;
                    303: }
                    304:
                    305: /*
                    306:  * primary : term { addop term }
                    307:  */
                    308: static int
                    309: primary()
                    310: {
1.7       espie     311:        int c, vl, vr;
1.1       deraadt   312:
                    313:        vl = term();
                    314:        while ((c = skipws()) == '+' || c == '-') {
                    315:                vr = term();
                    316:
                    317:                if (c == '+')
                    318:                        vl += vr;
                    319:                else
                    320:                        vl -= vr;
                    321:        }
                    322:
                    323:        ungetch();
                    324:        return vl;
                    325: }
                    326:
                    327: /*
                    328:  * <term> := <exp> { <mulop> <exp> }
                    329:  */
                    330: static int
                    331: term()
                    332: {
1.7       espie     333:        int c, vl, vr;
1.1       deraadt   334:
                    335:        vl = exp();
                    336:        while ((c = skipws()) == '*' || c == '/' || c == '%') {
                    337:                vr = exp();
                    338:
                    339:                switch (c) {
                    340:                case '*':
                    341:                        vl *= vr;
                    342:                        break;
                    343:                case '/':
1.8       espie     344:                        if (vr == 0)
                    345:                                errx(1, "division by zero in eval.");
                    346:                        else
                    347:                                vl /= vr;
1.1       deraadt   348:                        break;
                    349:                case '%':
1.8       espie     350:                        if (vr == 0)
                    351:                                errx(1, "modulo zero in eval.");
                    352:                        else
                    353:                                vl %= vr;
1.1       deraadt   354:                        break;
                    355:                }
                    356:        }
                    357:        ungetch();
                    358:        return vl;
                    359: }
                    360:
                    361: /*
                    362:  * <term> := <unary> { <expop> <unary> }
                    363:  */
                    364: static int
                    365: exp()
                    366: {
1.7       espie     367:        int c, vl, vr, n;
1.1       deraadt   368:
                    369:        vl = unary();
                    370:        switch (c = skipws()) {
                    371:
                    372:        case '*':
                    373:                if (getch() != '*') {
                    374:                        ungetch();
                    375:                        break;
                    376:                }
                    377:
                    378:        case '^':
                    379:                vr = exp();
                    380:                n = 1;
                    381:                while (vr-- > 0)
                    382:                        n *= vl;
                    383:                return n;
                    384:        }
                    385:
                    386:        ungetch();
                    387:        return vl;
                    388: }
                    389:
                    390: /*
                    391:  * unary : factor | unop unary
                    392:  */
                    393: static int
                    394: unary()
                    395: {
1.7       espie     396:        int val, c;
1.1       deraadt   397:
                    398:        if ((c = skipws()) == '+' || c == '-' || c == '~') {
                    399:                val = unary();
                    400:
                    401:                switch (c) {
                    402:                case '+':
                    403:                        return val;
                    404:                case '-':
                    405:                        return -val;
                    406:                case '~':
                    407:                        return ~val;
                    408:                }
                    409:        }
                    410:
                    411:        ungetch();
                    412:        return factor();
                    413: }
                    414:
                    415: /*
                    416:  * factor : constant | '(' query ')'
                    417:  */
                    418: static int
                    419: factor()
                    420: {
1.7       espie     421:        int val;
1.1       deraadt   422:
                    423:        if (skipws() == '(') {
                    424:                val = query();
                    425:                if (skipws() != ')')
                    426:                        experr("bad factor");
                    427:                return val;
                    428:        }
                    429:
                    430:        ungetch();
                    431:        return constant();
                    432: }
                    433:
                    434: /*
                    435:  * constant: num | 'char'
                    436:  * Note: constant() handles multi-byte constants
                    437:  */
                    438: static int
                    439: constant()
                    440: {
1.7       espie     441:        int i;
                    442:        int value;
                    443:        int c;
1.1       deraadt   444:        int v[sizeof(int)];
                    445:
                    446:        if (skipws() != '\'') {
                    447:                ungetch();
                    448:                return num();
                    449:        }
                    450:        for (i = 0; i < sizeof(int); i++) {
                    451:                if ((c = getch()) == '\'') {
                    452:                        ungetch();
                    453:                        break;
                    454:                }
                    455:                if (c == '\\') {
                    456:                        switch (c = getch()) {
                    457:                        case '0':
                    458:                        case '1':
                    459:                        case '2':
                    460:                        case '3':
                    461:                        case '4':
                    462:                        case '5':
                    463:                        case '6':
                    464:                        case '7':
                    465:                                ungetch();
                    466:                                c = num();
                    467:                                break;
                    468:                        case 'n':
                    469:                                c = 012;
                    470:                                break;
                    471:                        case 'r':
                    472:                                c = 015;
                    473:                                break;
                    474:                        case 't':
                    475:                                c = 011;
                    476:                                break;
                    477:                        case 'b':
                    478:                                c = 010;
                    479:                                break;
                    480:                        case 'f':
                    481:                                c = 014;
                    482:                                break;
                    483:                        }
                    484:                }
                    485:                v[i] = c;
                    486:        }
                    487:        if (i == 0 || getch() != '\'')
                    488:                experr("illegal character constant");
                    489:        for (value = 0; --i >= 0;) {
                    490:                value <<= 8;
                    491:                value += v[i];
                    492:        }
                    493:        return value;
                    494: }
                    495:
                    496: /*
                    497:  * num : digit | num digit
                    498:  */
                    499: static int
                    500: num()
                    501: {
1.7       espie     502:        int rval, c, base;
1.1       deraadt   503:        int ndig;
                    504:
                    505:        rval = 0;
                    506:        ndig = 0;
1.5       espie     507:        c = skipws();
                    508:        if (c == '0') {
                    509:                c = skipws();
                    510:                if (c == 'x' || c == 'X') {
                    511:                        base = HEX;
                    512:                        c = skipws();
                    513:                } else {
                    514:                        base = OCTAL;
                    515:                        ndig++;
                    516:                }
                    517:        } else
                    518:                base = DECIMAL;
                    519:        for(;;) {
                    520:                switch(c) {
                    521:                        case '8': case '9':
1.9       espie     522:                                if (base == OCTAL)
1.5       espie     523:                                        goto bad_digit;
                    524:                                /*FALLTHRU*/
                    525:                        case '0': case '1': case '2': case '3':
                    526:                        case '4': case '5': case '6': case '7':
                    527:                                rval *= base;
                    528:                                rval += c - '0';
                    529:                                break;
                    530:                        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
                    531:                                c = tolower(c);
                    532:                        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
                    533:                                if (base == HEX) {
                    534:                                        rval *= base;
                    535:                                        rval += c - 'a' + 10;
                    536:                                        break;
                    537:                                }
                    538:                                /*FALLTHRU*/
                    539:                        default:
                    540:                                goto bad_digit;
                    541:                }
1.1       deraadt   542:                c = getch();
                    543:                ndig++;
                    544:        }
1.5       espie     545: bad_digit:
1.1       deraadt   546:        ungetch();
                    547:
                    548:        if (ndig == 0)
                    549:                experr("bad constant");
                    550:
                    551:        return rval;
                    552: }
                    553:
                    554: /*
                    555:  * eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>='
                    556:  */
                    557: static int
                    558: geteqrel()
                    559: {
1.7       espie     560:        int c1, c2;
1.1       deraadt   561:
                    562:        c1 = skipws();
                    563:        c2 = getch();
                    564:
                    565:        switch (c1) {
                    566:
                    567:        case '=':
                    568:                if (c2 != '=')
                    569:                        ungetch();
                    570:                return EQL;
                    571:
                    572:        case '!':
                    573:                if (c2 == '=')
                    574:                        return NEQ;
                    575:                ungetch();
                    576:                ungetch();
                    577:                return -1;
                    578:
                    579:        case '<':
                    580:                if (c2 == '=')
                    581:                        return LEQ;
                    582:                ungetch();
                    583:                return LSS;
                    584:
                    585:        case '>':
                    586:                if (c2 == '=')
                    587:                        return GEQ;
                    588:                ungetch();
                    589:                return GTR;
                    590:
                    591:        default:
                    592:                ungetch();
                    593:                ungetch();
                    594:                return -1;
                    595:        }
                    596: }
                    597:
                    598: /*
                    599:  * Skip over any white space and return terminating char.
                    600:  */
                    601: static int
                    602: skipws()
                    603: {
1.7       espie     604:        int c;
1.1       deraadt   605:
                    606:        while ((c = getch()) <= ' ' && c > EOS)
                    607:                ;
                    608:        return c;
                    609: }
                    610:
                    611: /*
                    612:  * resets environment to eval(), prints an error
                    613:  * and forces eval to return FALSE.
                    614:  */
                    615: static void
                    616: experr(msg)
1.10    ! espie     617:        const char *msg;
1.1       deraadt   618: {
                    619:        printf("m4: %s in expr.\n", msg);
                    620:        longjmp(expjump, -1);
                    621: }