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

Defined functions

band defined in line 259; used 2 times
bor defined in line 220; used 2 times
bxor defined in line 241; used 2 times
constant defined in line 454; used 1 times
eql defined in line 280; used 2 times
experr defined in line 620; used 4 times
expr defined in line 137; never used
factor defined in line 434; used 1 times
geteql defined in line 542; used 1 times
getrel defined in line 574; used 1 times
land defined in line 200; used 2 times
lor defined in line 180; used 1 times
num defined in line 515; used 2 times
primary defined in line 360; used 2 times
query defined in line 158; used 4 times
relat defined in line 305; used 2 times
shift defined in line 336; used 2 times
skipws defined in line 606; used 18 times
term defined in line 381; used 2 times
unary defined in line 409; used 3 times

Defined variables

expjump defined in line 127; used 2 times
nxtch defined in line 101; used 3 times
sccsid defined in line 38; never used

Defined macros

DECIMAL defined in line 99; used 1 times
EOS defined in line 91; used 2 times
EQL defined in line 92; used 1 times
FALSE defined in line 90; used 2 times
GEQ defined in line 97; used 1 times
GTR defined in line 96; used 1 times
LEQ defined in line 95; used 1 times
LSS defined in line 94; used 1 times
NEQ defined in line 93; used 1 times
OCTAL defined in line 98; used 2 times
TRUE defined in line 89; never used
getch defined in line 135; used 12 times
ungetch defined in line 134; used 31 times
Last modified: 1994-04-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3019
Valid CSS Valid XHTML 1.0 Strict