[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.7

1.7     ! espie       1: /*     $OpenBSD: expr.c,v 1.4 1998/04/25 18:47:19 millert 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.7     ! espie      44: static char rcsid[] = "$OpenBSD: expr.c,v 1.4 1998/04/25 18:47:19 millert Exp $";
1.1       deraadt    45: #endif
                     46: #endif /* not lint */
                     47:
                     48: #include <sys/cdefs.h>
                     49: #include <stdio.h>
1.6       espie      50: #include <ctype.h>
1.5       espie      51: #include "mdef.h"
1.1       deraadt    52:
                     53: /*
                     54:  *      expression evaluator: performs a standard recursive
                     55:  *      descent parse to evaluate any expression permissible
                     56:  *      within the following grammar:
                     57:  *
                     58:  *      expr    :       query EOS
                     59:  *      query   :       lor
                     60:  *              |       lor "?" query ":" query
                     61:  *      lor     :       land { "||" land }
                     62:  *      land    :       not { "&&" not }
                     63:  *     not     :       eqrel
                     64:  *             |       '!' not
                     65:  *      eqrel   :       shift { eqrelop shift }
                     66:  *      shift   :       primary { shop primary }
                     67:  *      primary :       term { addop term }
                     68:  *      term    :       exp { mulop exp }
                     69:  *     exp     :       unary { expop unary }
                     70:  *      unary   :       factor
                     71:  *              |       unop unary
                     72:  *      factor  :       constant
                     73:  *              |       "(" query ")"
                     74:  *      constant:       num
                     75:  *              |       "'" CHAR "'"
                     76:  *      num     :       DIGIT
                     77:  *              |       DIGIT num
                     78:  *      shop    :       "<<"
                     79:  *              |       ">>"
                     80:  *      eqrel   :       "="
                     81:  *              |       "=="
                     82:  *              |       "!="
                     83:  *             |       "<"
                     84:  *              |       ">"
                     85:  *              |       "<="
                     86:  *              |       ">="
                     87:  *
                     88:  *
                     89:  *      This expression evaluator is lifted from a public-domain
                     90:  *      C Pre-Processor included with the DECUS C Compiler distribution.
                     91:  *      It is hacked somewhat to be suitable for m4.
                     92:  *
                     93:  *      Originally by:  Mike Lutz
                     94:  *                      Bob Harper
                     95:  */
                     96:
                     97: #define EQL     0
                     98: #define NEQ     1
                     99: #define LSS     2
                    100: #define LEQ     3
                    101: #define GTR     4
                    102: #define GEQ     5
                    103: #define OCTAL   8
                    104: #define DECIMAL 10
1.5       espie     105: #define HEX    16
1.1       deraadt   106:
                    107: static char *nxtch;                   /* Parser scan pointer */
                    108:
                    109: static int query __P((void));
                    110: static int lor __P((void));
                    111: static int land __P((void));
                    112: static int not __P((void));
                    113: static int eqrel __P((void));
                    114: static int shift __P((void));
                    115: static int primary __P((void));
                    116: static int term __P((void));
                    117: static int exp __P((void));
                    118: static int unary __P((void));
                    119: static int factor __P((void));
                    120: static int constant __P((void));
                    121: static int num __P((void));
                    122: static int geteqrel __P((void));
                    123: static int skipws __P((void));
                    124: static void experr __P((char *));
                    125:
                    126: /*
                    127:  * For longjmp
                    128:  */
                    129: #include <setjmp.h>
                    130: static jmp_buf expjump;
                    131:
                    132: /*
                    133:  * macros:
                    134:  *      ungetch - Put back the last character examined.
                    135:  *      getch   - return the next character from expr string.
                    136:  */
                    137: #define ungetch()       nxtch--
                    138: #define getch()         *nxtch++
                    139:
                    140: int
                    141: expr(expbuf)
1.7     ! espie     142:        char *expbuf;
1.1       deraadt   143: {
1.7     ! espie     144:        int rval;
1.1       deraadt   145:
                    146:        nxtch = expbuf;
                    147:        if (setjmp(expjump) != 0)
                    148:                return FALSE;
                    149:
                    150:        rval = query();
                    151:        if (skipws() == EOS)
                    152:                return rval;
                    153:
                    154:        printf("m4: ill-formed expression.\n");
                    155:        return FALSE;
                    156: }
                    157:
                    158: /*
                    159:  * query : lor | lor '?' query ':' query
                    160:  */
                    161: static int
                    162: query()
                    163: {
1.7     ! espie     164:        int bool, true_val, false_val;
1.1       deraadt   165:
                    166:        bool = lor();
                    167:        if (skipws() != '?') {
                    168:                ungetch();
                    169:                return bool;
                    170:        }
                    171:
                    172:        true_val = query();
                    173:        if (skipws() != ':')
                    174:                experr("bad query");
                    175:
                    176:        false_val = query();
                    177:        return bool ? true_val : false_val;
                    178: }
                    179:
                    180: /*
                    181:  * lor : land { '||' land }
                    182:  */
                    183: static int
                    184: lor()
                    185: {
1.7     ! espie     186:        int c, vl, vr;
1.1       deraadt   187:
                    188:        vl = land();
                    189:        while ((c = skipws()) == '|') {
                    190:                if (getch() != '|')
                    191:                        ungetch();
                    192:                vr = land();
                    193:                vl = vl || vr;
                    194:        }
                    195:
                    196:        ungetch();
                    197:        return vl;
                    198: }
                    199:
                    200: /*
                    201:  * land : not { '&&' not }
                    202:  */
                    203: static int
                    204: land()
                    205: {
1.7     ! espie     206:        int c, vl, vr;
1.1       deraadt   207:
                    208:        vl = not();
                    209:        while ((c = skipws()) == '&') {
                    210:                if (getch() != '&')
                    211:                        ungetch();
                    212:                vr = not();
                    213:                vl = vl && vr;
                    214:        }
                    215:
                    216:        ungetch();
                    217:        return vl;
                    218: }
                    219:
                    220: /*
                    221:  * not : eqrel | '!' not
                    222:  */
                    223: static int
                    224: not()
                    225: {
1.7     ! espie     226:        int val, c;
1.1       deraadt   227:
                    228:        if ((c = skipws()) == '!' && getch() != '=') {
                    229:                ungetch();
                    230:                val = not();
                    231:                return !val;
                    232:        }
                    233:
                    234:        if (c == '!')
                    235:                ungetch();
                    236:        ungetch();
                    237:        return eqrel();
                    238: }
                    239:
                    240: /*
                    241:  * eqrel : shift { eqrelop shift }
                    242:  */
                    243: static int
                    244: eqrel()
                    245: {
1.7     ! espie     246:        int vl, vr, eqrel;
1.1       deraadt   247:
                    248:        vl = shift();
                    249:        while ((eqrel = geteqrel()) != -1) {
                    250:                vr = shift();
                    251:
                    252:                switch (eqrel) {
                    253:
                    254:                case EQL:
                    255:                        vl = (vl == vr);
                    256:                        break;
                    257:                case NEQ:
                    258:                        vl = (vl != vr);
                    259:                        break;
                    260:
                    261:                case LEQ:
                    262:                        vl = (vl <= vr);
                    263:                        break;
                    264:                case LSS:
                    265:                        vl = (vl < vr);
                    266:                        break;
                    267:                case GTR:
                    268:                        vl = (vl > vr);
                    269:                        break;
                    270:                case GEQ:
                    271:                        vl = (vl >= vr);
                    272:                        break;
                    273:                }
                    274:        }
                    275:        return vl;
                    276: }
                    277:
                    278: /*
                    279:  * shift : primary { shop primary }
                    280:  */
                    281: static int
                    282: shift()
                    283: {
1.7     ! espie     284:        int vl, vr, c;
1.1       deraadt   285:
                    286:        vl = primary();
                    287:        while (((c = skipws()) == '<' || c == '>') && getch() == c) {
                    288:                vr = primary();
                    289:
                    290:                if (c == '<')
                    291:                        vl <<= vr;
                    292:                else
                    293:                        vl >>= vr;
                    294:        }
                    295:
                    296:        if (c == '<' || c == '>')
                    297:                ungetch();
                    298:        ungetch();
                    299:        return vl;
                    300: }
                    301:
                    302: /*
                    303:  * primary : term { addop term }
                    304:  */
                    305: static int
                    306: primary()
                    307: {
1.7     ! espie     308:        int c, vl, vr;
1.1       deraadt   309:
                    310:        vl = term();
                    311:        while ((c = skipws()) == '+' || c == '-') {
                    312:                vr = term();
                    313:
                    314:                if (c == '+')
                    315:                        vl += vr;
                    316:                else
                    317:                        vl -= vr;
                    318:        }
                    319:
                    320:        ungetch();
                    321:        return vl;
                    322: }
                    323:
                    324: /*
                    325:  * <term> := <exp> { <mulop> <exp> }
                    326:  */
                    327: static int
                    328: term()
                    329: {
1.7     ! espie     330:        int c, vl, vr;
1.1       deraadt   331:
                    332:        vl = exp();
                    333:        while ((c = skipws()) == '*' || c == '/' || c == '%') {
                    334:                vr = exp();
                    335:
                    336:                switch (c) {
                    337:                case '*':
                    338:                        vl *= vr;
                    339:                        break;
                    340:                case '/':
                    341:                        vl /= vr;
                    342:                        break;
                    343:                case '%':
                    344:                        vl %= vr;
                    345:                        break;
                    346:                }
                    347:        }
                    348:        ungetch();
                    349:        return vl;
                    350: }
                    351:
                    352: /*
                    353:  * <term> := <unary> { <expop> <unary> }
                    354:  */
                    355: static int
                    356: exp()
                    357: {
1.7     ! espie     358:        int c, vl, vr, n;
1.1       deraadt   359:
                    360:        vl = unary();
                    361:        switch (c = skipws()) {
                    362:
                    363:        case '*':
                    364:                if (getch() != '*') {
                    365:                        ungetch();
                    366:                        break;
                    367:                }
                    368:
                    369:        case '^':
                    370:                vr = exp();
                    371:                n = 1;
                    372:                while (vr-- > 0)
                    373:                        n *= vl;
                    374:                return n;
                    375:        }
                    376:
                    377:        ungetch();
                    378:        return vl;
                    379: }
                    380:
                    381: /*
                    382:  * unary : factor | unop unary
                    383:  */
                    384: static int
                    385: unary()
                    386: {
1.7     ! espie     387:        int val, c;
1.1       deraadt   388:
                    389:        if ((c = skipws()) == '+' || c == '-' || c == '~') {
                    390:                val = unary();
                    391:
                    392:                switch (c) {
                    393:                case '+':
                    394:                        return val;
                    395:                case '-':
                    396:                        return -val;
                    397:                case '~':
                    398:                        return ~val;
                    399:                }
                    400:        }
                    401:
                    402:        ungetch();
                    403:        return factor();
                    404: }
                    405:
                    406: /*
                    407:  * factor : constant | '(' query ')'
                    408:  */
                    409: static int
                    410: factor()
                    411: {
1.7     ! espie     412:        int val;
1.1       deraadt   413:
                    414:        if (skipws() == '(') {
                    415:                val = query();
                    416:                if (skipws() != ')')
                    417:                        experr("bad factor");
                    418:                return val;
                    419:        }
                    420:
                    421:        ungetch();
                    422:        return constant();
                    423: }
                    424:
                    425: /*
                    426:  * constant: num | 'char'
                    427:  * Note: constant() handles multi-byte constants
                    428:  */
                    429: static int
                    430: constant()
                    431: {
1.7     ! espie     432:        int i;
        !           433:        int value;
        !           434:        int c;
1.1       deraadt   435:        int v[sizeof(int)];
                    436:
                    437:        if (skipws() != '\'') {
                    438:                ungetch();
                    439:                return num();
                    440:        }
                    441:        for (i = 0; i < sizeof(int); i++) {
                    442:                if ((c = getch()) == '\'') {
                    443:                        ungetch();
                    444:                        break;
                    445:                }
                    446:                if (c == '\\') {
                    447:                        switch (c = getch()) {
                    448:                        case '0':
                    449:                        case '1':
                    450:                        case '2':
                    451:                        case '3':
                    452:                        case '4':
                    453:                        case '5':
                    454:                        case '6':
                    455:                        case '7':
                    456:                                ungetch();
                    457:                                c = num();
                    458:                                break;
                    459:                        case 'n':
                    460:                                c = 012;
                    461:                                break;
                    462:                        case 'r':
                    463:                                c = 015;
                    464:                                break;
                    465:                        case 't':
                    466:                                c = 011;
                    467:                                break;
                    468:                        case 'b':
                    469:                                c = 010;
                    470:                                break;
                    471:                        case 'f':
                    472:                                c = 014;
                    473:                                break;
                    474:                        }
                    475:                }
                    476:                v[i] = c;
                    477:        }
                    478:        if (i == 0 || getch() != '\'')
                    479:                experr("illegal character constant");
                    480:        for (value = 0; --i >= 0;) {
                    481:                value <<= 8;
                    482:                value += v[i];
                    483:        }
                    484:        return value;
                    485: }
                    486:
                    487: /*
                    488:  * num : digit | num digit
                    489:  */
                    490: static int
                    491: num()
                    492: {
1.7     ! espie     493:        int rval, c, base;
1.1       deraadt   494:        int ndig;
                    495:
                    496:        rval = 0;
                    497:        ndig = 0;
1.5       espie     498:        c = skipws();
                    499:        if (c == '0') {
                    500:                c = skipws();
                    501:                if (c == 'x' || c == 'X') {
                    502:                        base = HEX;
                    503:                        c = skipws();
                    504:                } else {
                    505:                        base = OCTAL;
                    506:                        ndig++;
                    507:                }
                    508:        } else
                    509:                base = DECIMAL;
                    510:        for(;;) {
                    511:                switch(c) {
                    512:                        case '8': case '9':
                    513:                                if (base != OCTAL)
                    514:                                        goto bad_digit;
                    515:                                /*FALLTHRU*/
                    516:                        case '0': case '1': case '2': case '3':
                    517:                        case '4': case '5': case '6': case '7':
                    518:                                rval *= base;
                    519:                                rval += c - '0';
                    520:                                break;
                    521:                        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
                    522:                                c = tolower(c);
                    523:                        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
                    524:                                if (base == HEX) {
                    525:                                        rval *= base;
                    526:                                        rval += c - 'a' + 10;
                    527:                                        break;
                    528:                                }
                    529:                                /*FALLTHRU*/
                    530:                        default:
                    531:                                goto bad_digit;
                    532:                }
1.1       deraadt   533:                c = getch();
                    534:                ndig++;
                    535:        }
1.5       espie     536: bad_digit:
1.1       deraadt   537:        ungetch();
                    538:
                    539:        if (ndig == 0)
                    540:                experr("bad constant");
                    541:
                    542:        return rval;
                    543: }
                    544:
                    545: /*
                    546:  * eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>='
                    547:  */
                    548: static int
                    549: geteqrel()
                    550: {
1.7     ! espie     551:        int c1, c2;
1.1       deraadt   552:
                    553:        c1 = skipws();
                    554:        c2 = getch();
                    555:
                    556:        switch (c1) {
                    557:
                    558:        case '=':
                    559:                if (c2 != '=')
                    560:                        ungetch();
                    561:                return EQL;
                    562:
                    563:        case '!':
                    564:                if (c2 == '=')
                    565:                        return NEQ;
                    566:                ungetch();
                    567:                ungetch();
                    568:                return -1;
                    569:
                    570:        case '<':
                    571:                if (c2 == '=')
                    572:                        return LEQ;
                    573:                ungetch();
                    574:                return LSS;
                    575:
                    576:        case '>':
                    577:                if (c2 == '=')
                    578:                        return GEQ;
                    579:                ungetch();
                    580:                return GTR;
                    581:
                    582:        default:
                    583:                ungetch();
                    584:                ungetch();
                    585:                return -1;
                    586:        }
                    587: }
                    588:
                    589: /*
                    590:  * Skip over any white space and return terminating char.
                    591:  */
                    592: static int
                    593: skipws()
                    594: {
1.7     ! espie     595:        int c;
1.1       deraadt   596:
                    597:        while ((c = getch()) <= ' ' && c > EOS)
                    598:                ;
                    599:        return c;
                    600: }
                    601:
                    602: /*
                    603:  * resets environment to eval(), prints an error
                    604:  * and forces eval to return FALSE.
                    605:  */
                    606: static void
                    607: experr(msg)
1.7     ! espie     608:        char *msg;
1.1       deraadt   609: {
                    610:        printf("m4: %s in expr.\n", msg);
                    611:        longjmp(expjump, -1);
                    612: }