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: }