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