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