1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Ozan Yigit. 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 #ifndef lint 38 static char sccsid[] = "@(#)expr.c 5.3 (Berkeley) 2/26/91"; 39 #endif /* not lint */ 40 41 #include <setjmp.h> 42 #include <stdio.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 /* 104 * For longjmp 105 */ 106 static jmp_buf expjump; 107 108 /* 109 * macros: 110 * 111 * ungetch - Put back the last character examined. 112 * getch - return the next character from expr string. 113 */ 114 #define ungetch() nxtch-- 115 #define getch() *nxtch++ 116 117 expr(expbuf) 118 char *expbuf; 119 { 120 register int rval; 121 122 nxtch = expbuf; 123 if (setjmp(expjump) != 0) 124 return (FALSE); 125 rval = query(); 126 if (skipws() == EOS) 127 return(rval); 128 experr("Ill-formed expression"); 129 } 130 131 /* 132 * query : lor | lor '?' query ':' query 133 * 134 */ 135 query() 136 { 137 register int bool, true_val, false_val; 138 139 bool = lor(); 140 if (skipws() != '?') { 141 ungetch(); 142 return(bool); 143 } 144 145 true_val = query(); 146 if (skipws() != ':') 147 experr("Bad query"); 148 149 false_val = query(); 150 return(bool ? true_val : false_val); 151 } 152 153 /* 154 * lor : land { '||' land } 155 * 156 */ 157 lor() 158 { 159 register int c, vl, vr; 160 161 vl = land(); 162 while ((c = skipws()) == '|' && getch() == '|') { 163 vr = land(); 164 vl = vl || vr; 165 } 166 167 if (c == '|') 168 ungetch(); 169 ungetch(); 170 return(vl); 171 } 172 173 /* 174 * land : bor { '&&' bor } 175 * 176 */ 177 land() 178 { 179 register int c, vl, vr; 180 181 vl = bor(); 182 while ((c = skipws()) == '&' && getch() == '&') { 183 vr = bor(); 184 vl = vl && vr; 185 } 186 187 if (c == '&') 188 ungetch(); 189 ungetch(); 190 return(vl); 191 } 192 193 /* 194 * bor : bxor { '|' bxor } 195 * 196 */ 197 bor() 198 { 199 register int vl, vr, c; 200 201 vl = bxor(); 202 while ((c = skipws()) == '|' && getch() != '|') { 203 ungetch(); 204 vr = bxor(); 205 vl |= vr; 206 } 207 208 if (c == '|') 209 ungetch(); 210 ungetch(); 211 return(vl); 212 } 213 214 /* 215 * bxor : band { '^' band } 216 * 217 */ 218 bxor() 219 { 220 register int vl, vr; 221 222 vl = band(); 223 while (skipws() == '^') { 224 vr = band(); 225 vl ^= vr; 226 } 227 228 ungetch(); 229 return(vl); 230 } 231 232 /* 233 * band : eql { '&' eql } 234 * 235 */ 236 band() 237 { 238 register int vl, vr, c; 239 240 vl = eql(); 241 while ((c = skipws()) == '&' && getch() != '&') { 242 ungetch(); 243 vr = eql(); 244 vl &= vr; 245 } 246 247 if (c == '&') 248 ungetch(); 249 ungetch(); 250 return(vl); 251 } 252 253 /* 254 * eql : relat { eqrel relat } 255 * 256 */ 257 eql() 258 { 259 register int vl, vr, rel; 260 261 vl = relat(); 262 while ((rel = geteql()) != -1) { 263 vr = relat(); 264 265 switch (rel) { 266 267 case EQL: 268 vl = (vl == vr); 269 break; 270 case NEQ: 271 vl = (vl != vr); 272 break; 273 } 274 } 275 return(vl); 276 } 277 278 /* 279 * relat : shift { rel shift } 280 * 281 */ 282 relat() 283 { 284 register int vl, vr, rel; 285 286 vl = shift(); 287 while ((rel = getrel()) != -1) { 288 289 vr = shift(); 290 switch (rel) { 291 292 case LEQ: 293 vl = (vl <= vr); 294 break; 295 case LSS: 296 vl = (vl < vr); 297 break; 298 case GTR: 299 vl = (vl > vr); 300 break; 301 case GEQ: 302 vl = (vl >= vr); 303 break; 304 } 305 } 306 return(vl); 307 } 308 309 /* 310 * shift : primary { shop primary } 311 * 312 */ 313 shift() 314 { 315 register int vl, vr, c; 316 317 vl = primary(); 318 while (((c = skipws()) == '<' || c == '>') && c == getch()) { 319 vr = primary(); 320 321 if (c == '<') 322 vl <<= vr; 323 else 324 vl >>= vr; 325 } 326 327 if (c == '<' || c == '>') 328 ungetch(); 329 ungetch(); 330 return(vl); 331 } 332 333 /* 334 * primary : term { addop term } 335 * 336 */ 337 primary() 338 { 339 register int c, vl, vr; 340 341 vl = term(); 342 while ((c = skipws()) == '+' || c == '-') { 343 vr = term(); 344 if (c == '+') 345 vl += vr; 346 else 347 vl -= vr; 348 } 349 350 ungetch(); 351 return(vl); 352 } 353 354 /* 355 * <term> := <unary> { <mulop> <unary> } 356 * 357 */ 358 term() 359 { 360 register int c, vl, vr; 361 362 vl = unary(); 363 while ((c = skipws()) == '*' || c == '/' || c == '%') { 364 vr = unary(); 365 366 switch (c) { 367 case '*': 368 vl *= vr; 369 break; 370 case '/': 371 vl /= vr; 372 break; 373 case '%': 374 vl %= vr; 375 break; 376 } 377 } 378 ungetch(); 379 return(vl); 380 } 381 382 /* 383 * unary : factor | unop unary 384 * 385 */ 386 unary() 387 { 388 register int val, c; 389 390 if ((c = skipws()) == '!' || c == '~' || c == '-') { 391 val = unary(); 392 393 switch (c) { 394 case '!': 395 return(! val); 396 case '~': 397 return(~ val); 398 case '-': 399 return(- val); 400 } 401 } 402 403 ungetch(); 404 return(factor()); 405 } 406 407 /* 408 * factor : constant | '(' query ')' 409 * 410 */ 411 factor() 412 { 413 register int val; 414 415 if (skipws() == '(') { 416 val = query(); 417 if (skipws() != ')') 418 experr("Bad factor"); 419 return(val); 420 } 421 422 ungetch(); 423 return(constant()); 424 } 425 426 /* 427 * constant: num | 'char' 428 * 429 */ 430 constant() 431 { 432 /* 433 * Note: constant() handles multi-byte constants 434 */ 435 436 register int i; 437 register int value; 438 register char c; 439 int v[sizeof (int)]; 440 441 if (skipws() != '\'') { 442 ungetch(); 443 return(num()); 444 } 445 for (i = 0; i < sizeof(int); i++) { 446 if ((c = getch()) == '\'') { 447 ungetch(); 448 break; 449 } 450 if (c == '\\') { 451 switch (c = getch()) { 452 case '0': 453 case '1': 454 case '2': 455 case '3': 456 case '4': 457 case '5': 458 case '6': 459 case '7': 460 ungetch(); 461 c = num(); 462 break; 463 case 'n': 464 c = 012; 465 break; 466 case 'r': 467 c = 015; 468 break; 469 case 't': 470 c = 011; 471 break; 472 case 'b': 473 c = 010; 474 break; 475 case 'f': 476 c = 014; 477 break; 478 } 479 } 480 v[i] = c; 481 } 482 if (i == 0 || getch() != '\'') 483 experr("Illegal character constant"); 484 for (value = 0; --i >= 0;) { 485 value <<= 8; 486 value += v[i]; 487 } 488 return(value); 489 } 490 491 /* 492 * num : digit | num digit 493 * 494 */ 495 num() 496 { 497 register int rval, c, base; 498 int ndig; 499 500 base = ((c = skipws()) == '0') ? OCTAL : DECIMAL; 501 rval = 0; 502 ndig = 0; 503 while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) { 504 rval *= base; 505 rval += (c - '0'); 506 c = getch(); 507 ndig++; 508 } 509 ungetch(); 510 if (ndig) 511 return(rval); 512 experr("Bad constant"); 513 } 514 515 /* 516 * eqlrel : '=' | '==' | '!=' 517 * 518 */ 519 geteql() 520 { 521 register int c1, c2; 522 523 c1 = skipws(); 524 c2 = getch(); 525 526 switch (c1) { 527 528 case '=': 529 if (c2 != '=') 530 ungetch(); 531 return(EQL); 532 533 case '!': 534 if (c2 == '=') 535 return(NEQ); 536 ungetch(); 537 ungetch(); 538 return(-1); 539 540 default: 541 ungetch(); 542 ungetch(); 543 return(-1); 544 } 545 } 546 547 /* 548 * rel : '<' | '>' | '<=' | '>=' 549 * 550 */ 551 getrel() 552 { 553 register int c1, c2; 554 555 c1 = skipws(); 556 c2 = getch(); 557 558 switch (c1) { 559 560 case '<': 561 if (c2 == '=') 562 return(LEQ); 563 ungetch(); 564 return(LSS); 565 566 case '>': 567 if (c2 == '=') 568 return(GEQ); 569 ungetch(); 570 return(GTR); 571 572 default: 573 ungetch(); 574 ungetch(); 575 return(-1); 576 } 577 } 578 579 /* 580 * Skip over any white space and return terminating char. 581 */ 582 skipws() 583 { 584 register char c; 585 586 while ((c = getch()) <= ' ' && c > EOS) 587 ; 588 return(c); 589 } 590 591 /* 592 * Error handler - resets environment to eval(), prints an error, 593 * and returns FALSE. 594 */ 595 experr(msg) 596 char *msg; 597 { 598 printf("mp: %s\n",msg); 599 longjmp(expjump, -1); /* Force eval() to return FALSE */ 600 } 601