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