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