1 /* File : expr.c 2 Authors: Mike Lutz & Bob Harper 3 Editors: Ozan Yigit & Richard A. O'Keefe 4 Updated: %G% 5 Purpose: arithmetic expression evaluator. 6 7 expr() performs a standard recursive descent parse to evaluate any 8 expression permitted byf the following grammar: 9 10 expr : query EOS 11 query : lor 12 | lor "?" query ":" query 13 lor : land { "||" land } or OR, for Pascal 14 land : bor { "&&" bor } or AND, for Pascal 15 bor : bxor { "|" bxor } 16 bxor : band { "^" band } 17 band : eql { "&" eql } 18 eql : relat { eqrel relat } 19 relat : shift { rel shift } 20 shift : primary { shop primary } 21 primary : term { addop term } 22 term : unary { mulop unary } 23 unary : factor 24 | unop unary 25 factor : constant 26 | "(" query ")" 27 constant: num 28 | "'" CHAR "'" or '"' CHAR '"' 29 num : DIGIT full ANSI C syntax 30 | DIGIT num 31 shop : "<<" 32 | ">>" 33 eqlrel : "=" 34 | "==" 35 | "!=" 36 rel : "<" or <>, Pascal not-equal 37 | ">" 38 | "<=" or =<, for Prolog users. 39 | ">=" 40 41 This expression evaluator was lifted from a public-domain 42 C Pre-Processor included with the DECUS C Compiler distribution. 43 It has been hacked somewhat to be suitable for m4. 44 45 26-Mar-1993 Changed to work in any of EBCDIC, ASCII, DEC MNCS, 46 or ISO 8859/n. 47 48 26-Mar-1993 Changed to use "long int" rather than int, so that 49 we get the same 32-bit arithmetic on a PC as on a Sun. 50 It isn't fully portable, of course, but then on a 64- 51 bit machine we _want_ 64-bit arithmetic... 52 Shifting rewritten (using LONG_BIT) to give signed 53 shifts even when (long) >> (long) is unsigned. 54 55 26-Mar-1993 I finally got sick of the fact that &&, ||, and ?: 56 don't do conditional evaluation. What is the good 57 of having eval(0&&(1/0)) crash and dump core? Now 58 every function has a doit? argument. 59 60 26-Mar-1993 charcon() didn't actually accept 'abcd', which it 61 should have. Fixed it. 62 63 20-Apr-1993 eval(1/0) and eval(1%0) dumped core and crashed. 64 This is also true of the System V r 3.2 m4, but 65 it isn't good enough for ours! Changed it so that 66 x % 0 => x as per Concrete Mathematics 67 x / 0 => error and return 0 from expr(). 68 */ 69 70 #ifndef lint 71 static char rcsid[] = "$Id: expr.c,v 1.3 1993/08/02 17:54:38 mycroft Exp $"; 72 #endif /* not lint */ 73 74 #define FALSE 0 75 #define TRUE 1 76 77 #include <stdio.h> 78 #include <setjmp.h> 79 static jmp_buf expjump; /* Error exit point for expr() */ 80 81 static unsigned char *nxtchr; /* Parser scan pointer */ 82 83 #define deblank0 while ((unsigned)(*nxtchr-1) < ' ') nxtchr++ 84 #define deblank1 while ((unsigned)(*++nxtchr - 1) < ' ') 85 #define deblank2 nxtchr++; deblank1 86 87 #include "ourlims.h" 88 static char digval[1+UCHAR_MAX]; 89 90 /* This file should work in any C implementation that doesn't have too 91 many characters to fit in one table. We use a table to convert 92 (unsigned) characters to numeric codes: 93 0 to 9 for '0' to '9' 94 10 to 35 for 'a' to 'z' 95 10 to 35 for 'A' to 'Z' 96 36 for '_' 97 Instead of asking whether tolower(c) == 'a' we ask whether 98 digval[c] == DIGIT_A, and so on. This essentially duplicates the 99 chtype[] table in main.c; we should use just one table. 100 */ 101 #define DIGIT_A 10 102 #define DIGIT_B 11 103 #define DIGIT_C 12 104 #define DIGIT_D 13 105 #define DIGIT_E 14 106 #define DIGIT_F 15 107 #define DIGIT_G 16 108 #define DIGIT_H 17 109 #define DIGIT_I 18 110 #define DIGIT_J 19 111 #define DIGIT_K 20 112 #define DIGIT_L 21 113 #define DIGIT_M 22 114 #define DIGIT_N 23 115 #define DIGIT_O 24 116 #define DIGIT_P 25 117 #define DIGIT_Q 26 118 #define DIGIT_R 27 119 #define DIGIT_S 28 120 #define DIGIT_T 29 121 #define DIGIT_U 30 122 #define DIGIT_V 31 123 #define DIGIT_W 32 124 #define DIGIT_X 33 125 #define DIGIT_Y 34 126 #define DIGIT_Z 35 127 128 129 #ifdef __STDC__ 130 static long int query(int); 131 #else 132 static long int query(); 133 #endif 134 135 136 /* experr(msg) 137 prints an error message, resets environment to expr(), and 138 forces expr() to return FALSE. 139 */ 140 void experr(msg) 141 char *msg; 142 { 143 (void) fprintf(stderr, "m4: %s\n", msg); 144 longjmp(expjump, -1); /* Force expr() to return FALSE */ 145 } 146 147 148 /* <numcon> ::= '0x' <hex> | '0X' <hex> | '0' <oct> | <dec> 149 For ANSI C, an integer may be followed by u, l, ul, or lu, 150 in any mix of cases. We accept and ignore those letters; 151 all the numbers are treated as long. 152 */ 153 static long int numcon(doit) 154 int doit; 155 { 156 register long int v; /* current value */ 157 register int b; /* base (radix) */ 158 register int c; /* character or digit value */ 159 160 if (!doit) { 161 do nxtchr++; while (digval[*nxtchr] <= 36); 162 deblank0; 163 return 0; 164 } 165 166 v = digval[*nxtchr++]; /* We already know it's a digit */ 167 if (v != 0) { 168 b = 10; /* decimal number */ 169 } else 170 if (digval[*nxtchr] == DIGIT_X) { 171 nxtchr++; 172 b = 16; /* hexadecimal number */ 173 } else { 174 b = 8; /* octal number */ 175 } 176 do { 177 while (digval[c = *nxtchr++] < b) v = v*b + digval[c]; 178 } while (c == '_'); 179 while (digval[c] == DIGIT_L || digval[c] == DIGIT_U) c = *nxtchr++; 180 nxtchr--; /* unread c */ 181 if ((unsigned)(c-1) < ' ') { deblank1; } 182 return v; 183 } 184 185 186 /* <charcon> ::= <qt> { <char> } <qt> 187 Note: multibyte constants are accepted. 188 Note: BEL (\a) and ESC (\e) have the same values in EBCDIC and ASCII. 189 */ 190 static long int charcon(doit) 191 int doit; 192 { 193 register int i; 194 long int value; 195 register int c; 196 int q; 197 int v[sizeof value]; 198 199 q = *nxtchr++; /* the quote character */ 200 for (i = 0; ; i++) { 201 c = *nxtchr++; 202 if (c == q) { /* end of literal, or doubled quote */ 203 if (*nxtchr != c) break; 204 nxtchr++; /* doubled quote stands for one quote */ 205 } 206 if (i == sizeof value) experr("Unterminated character constant"); 207 if (c == '\\') { 208 switch (c = *nxtchr++) { 209 case '0': case '1': case '2': case '3': 210 case '4': case '5': case '6': case '7': 211 c -= '0'; 212 if ((unsigned)(*nxtchr - '0') < 8) 213 c = (c << 3) | (*nxtchr++ - '0'); 214 if ((unsigned)(*nxtchr - '0') < 8) 215 c = (c << 3) | (*nxtchr++ - '0'); 216 break; 217 case 'n': case 'N': c = '\n'; break; 218 case 'r': case 'R': c = '\r'; break; 219 case 't': case 'T': c = '\t'; break; 220 case 'b': case 'B': c = '\b'; break; 221 case 'f': case 'F': c = '\f'; break; 222 case 'a': case 'A': c = 007; break; 223 case 'e': case 'E': c = 033; break; 224 #if ' ' == 64 225 case 'd': case 'D': c = 045; break; /*EBCDIC DEL */ 226 #else 227 case 'd': case 'D': c = 127; break; /* ASCII DEL */ 228 #endif 229 default : break; 230 } 231 } 232 v[i] = c; 233 } 234 deblank0; 235 if (!doit) return 0; 236 for (value = 0; --i >= 0; ) value = (value << CHAR_BIT) | v[i]; 237 return value; 238 } 239 240 241 /* <unary> ::= <unop> <unary> | <factor> 242 <unop> ::= '!' || '~' | '-' 243 <factor> ::= '(' <query> ')' | <'> <char> <'> | <"> <char> <"> | <num> 244 */ 245 static long int unary(doit) 246 int doit; 247 { 248 long int v; 249 250 switch (nxtchr[0]) { 251 case 'n': case 'N': 252 if (digval[nxtchr[1]] != DIGIT_O 253 || digval[nxtchr[2]] != DIGIT_T) 254 experr("Bad 'not'"); 255 nxtchr += 2; 256 case '!': deblank1; return !unary(doit); 257 case '~': deblank1; return ~unary(doit); 258 case '-': deblank1; return -unary(doit); 259 case '+': deblank1; return unary(doit); 260 case '(': deblank1; v = query(doit); 261 if (nxtchr[0] != ')') experr("Bad factor"); 262 deblank1; return v; 263 case '\'': 264 case '\"': return charcon(doit); 265 case '0': case '1': case '2': 266 case '3': case '4': case '5': 267 case '6': case '7': case '8': 268 case '9': return numcon(doit); 269 default : experr("Bad constant"); 270 } 271 return 0; /*NOTREACHED*/ 272 } 273 274 275 /* <term> ::= <unary> { <mulop> <unary> } 276 <mulop> ::= '*' | '/' || '%' 277 */ 278 static long int term(doit) 279 int doit; 280 { 281 register long int vl, vr; 282 283 vl = unary(doit); 284 for (;;) 285 switch (nxtchr[0]) { 286 case '*': 287 deblank1; 288 vr = unary(doit); 289 if (doit) vl *= vr; 290 break; 291 case 'd': case 'D': 292 if (digval[nxtchr[1]] != DIGIT_I 293 || digval[nxtchr[2]] != DIGIT_V) 294 experr("Bad 'div'"); 295 nxtchr += 2; 296 /*FALLTHROUGH*/ 297 case '/': 298 deblank1; 299 vr = unary(doit); 300 if (doit) { 301 if (vr == 0) experr("Division by 0"); 302 vl /= vr; 303 } 304 break; 305 case 'm': case 'M': 306 if (digval[nxtchr[1]] != DIGIT_O 307 || digval[nxtchr[2]] != DIGIT_D) 308 experr("Bad 'mod'"); 309 nxtchr += 2; 310 /*FALLTHROUGH*/ 311 case '%': 312 deblank1; 313 vr = unary(doit); 314 if (doit) { 315 if (vr != 0) vl %= vr; 316 } 317 break; 318 default: 319 return vl; 320 } 321 /*NOTREACHED*/ 322 } 323 324 /* <primary> ::= <term> { <addop> <term> } 325 <addop> ::= '+' | '-' 326 */ 327 static long int primary(doit) 328 int doit; 329 { 330 register long int vl; 331 332 vl = term(doit); 333 for (;;) 334 if (nxtchr[0] == '+') { 335 deblank1; 336 if (doit) vl += term(doit); else (void)term(doit); 337 } else 338 if (nxtchr[0] == '-') { 339 deblank1; 340 if (doit) vl -= term(doit); else (void)term(doit); 341 } else 342 return vl; 343 /*NOTREACHED*/ 344 } 345 346 347 /* <shift> ::= <primary> { <shop> <primary> } 348 <shop> ::= '<<' | '>>' 349 */ 350 static long int shift(doit) 351 int doit; 352 { 353 register long int vl, vr; 354 355 vl = primary(doit); 356 for (;;) { 357 if (nxtchr[0] == '<' && nxtchr[1] == '<') { 358 deblank2; 359 vr = primary(doit); 360 } else 361 if (nxtchr[0] == '>' && nxtchr[1] == '>') { 362 deblank2; 363 vr = -primary(doit); 364 } else { 365 return vl; 366 } 367 /* The following code implements shifts portably */ 368 /* Shifts are signed shifts, and the shift count */ 369 /* acts like repeated one-bit shifts, not modulo anything */ 370 if (doit) { 371 if (vr >= LONG_BIT) { 372 vl = 0; 373 } else 374 if (vr <= -LONG_BIT) { 375 vl = -(vl < 0); 376 } else 377 if (vr > 0) { 378 vl <<= vr; 379 } else 380 if (vr < 0) { 381 vl = (vl >> -vr) | (-(vl < 0) << (LONG_BIT + vr)); 382 } 383 } 384 } 385 /*NOTREACHED*/ 386 } 387 388 389 /* <relat> ::= <shift> { <rel> <shift> } 390 <rel> ::= '<=' | '>=' | '=<' | '=>' | '<' | '>' 391 Here I rely on the fact that '<<' and '>>' are swallowed by <shift> 392 */ 393 static long int relat(doit) 394 int doit; 395 { 396 register long int vl; 397 398 vl = shift(doit); 399 for (;;) 400 switch (nxtchr[0]) { 401 case '=': 402 switch (nxtchr[1]) { 403 case '<': /* =<, take as <= */ 404 deblank2; 405 vl = vl <= shift(doit); 406 break; 407 case '>': /* =>, take as >= */ 408 deblank2; 409 vl = vl >= shift(doit); 410 break; 411 default: /* == or =; OOPS */ 412 return vl; 413 } 414 break; 415 case '<': 416 if (nxtchr[1] == '=') { /* <= */ 417 deblank2; 418 vl = vl <= shift(doit); 419 } else 420 if (nxtchr[1] == '>') { /* <> (Pascal) */ 421 deblank2; 422 vl = vl != shift(doit); 423 } else { /* < */ 424 deblank1; 425 vl = vl < shift(doit); 426 } 427 break; 428 case '>': 429 if (nxtchr[1] == '=') { /* >= */ 430 deblank2; 431 vl = vl >= shift(doit); 432 } else { /* > */ 433 deblank1; 434 vl = vl > shift(doit); 435 } 436 break; 437 default: 438 return vl; 439 } 440 /*NOTREACHED*/ 441 } 442 443 444 /* <eql> ::= <relat> { <eqrel> <relat> } 445 <eqlrel> ::= '!=' | '==' | '=' 446 */ 447 static long int eql(doit) 448 int doit; 449 { 450 register long int vl; 451 452 vl = relat(doit); 453 for (;;) 454 if (nxtchr[0] == '!' && nxtchr[1] == '=') { 455 deblank2; 456 vl = vl != relat(doit); 457 } else 458 if (nxtchr[0] == '=' && nxtchr[1] == '=') { 459 deblank2; 460 vl = vl == relat(doit); 461 } else 462 if (nxtchr[0] == '=') { 463 deblank1; 464 vl = vl == relat(doit); 465 } else 466 return vl; 467 /*NOTREACHED*/ 468 } 469 470 471 /* <band> ::= <eql> { '&' <eql> } 472 */ 473 static long int band(doit) 474 int doit; 475 { 476 register long int vl; 477 478 vl = eql(doit); 479 while (nxtchr[0] == '&' && nxtchr[1] != '&') { 480 deblank1; 481 if (doit) vl &= eql(doit); else (void)eql(doit); 482 } 483 return vl; 484 } 485 486 487 /* <bxor> ::= <band> { '^' <band> } 488 */ 489 static long int bxor(doit) 490 int doit; 491 { 492 register long int vl; 493 494 vl = band(doit); 495 while (nxtchr[0] == '^') { 496 deblank1; 497 if (doit) vl ^= band(doit); else (void)band(doit); 498 } 499 return vl; 500 } 501 502 503 /* <bor> ::= <bxor> { '|' <bxor> } 504 */ 505 static long int bor(doit) 506 int doit; 507 { 508 register long int vl; 509 510 vl = bxor(doit); 511 while (nxtchr[0] == '|' && nxtchr[1] != '|') { 512 deblank1; 513 if (doit) vl |= bxor(doit); else (void)bxor(doit); 514 } 515 return vl; 516 } 517 518 519 /* <land> ::= <bor> { '&&' <bor> } 520 */ 521 static long int land(doit) 522 int doit; 523 { 524 register long int vl; 525 526 vl = bor(doit); 527 for (;;) { 528 if (nxtchr[0] == '&') { 529 if (nxtchr[1] != '&') break; 530 deblank2; 531 } else 532 if (digval[nxtchr[0]] == DIGIT_A) { 533 if (digval[nxtchr[1]] != DIGIT_N) break; 534 if (digval[nxtchr[2]] != DIGIT_D) break; 535 nxtchr += 2; deblank1; 536 } else { 537 /* neither && nor and */ 538 break; 539 } 540 vl = bor(doit && vl) != 0; 541 } 542 return vl; 543 } 544 545 546 /* <lor> ::= <land> { '||' <land> } 547 */ 548 static long int lor(doit) 549 int doit; 550 { 551 register long int vl; 552 553 vl = land(doit); 554 for (;;) { 555 if (nxtchr[0] == '|') { 556 if (nxtchr[1] != '|') break; 557 } else 558 if (digval[nxtchr[0]] == DIGIT_O) { 559 if (digval[nxtchr[1]] != DIGIT_R) break; 560 } else { 561 /* neither || nor or */ 562 break; 563 } 564 deblank2; 565 vl = land(doit && !vl) != 0; 566 } 567 return vl; 568 } 569 570 571 /* <query> ::= <lor> [ '?' <query> ':' <query> ] 572 */ 573 static long int query(doit) 574 int doit; 575 { 576 register long int bool, true_val, false_val; 577 578 bool = lor(doit); 579 if (*nxtchr != '?') return bool; 580 deblank1; 581 true_val = query(doit && bool); 582 if (*nxtchr != ':') experr("Bad query"); 583 deblank1; 584 false_val = query(doit && !bool); 585 return bool ? true_val : false_val; 586 } 587 588 589 static void initialise_digval() 590 { 591 register unsigned char *s; 592 register int c; 593 594 for (c = 0; c <= UCHAR_MAX; c++) digval[c] = 99; 595 for (c = 0, s = (unsigned char *)"0123456789"; 596 /*while*/ *s; 597 /*doing*/ digval[*s++] = c++) /* skip */; 598 for (c = 10, s = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 599 /*while*/ *s; 600 /*doing*/ digval[*s++] = c++) /* skip */; 601 for (c = 10, s = (unsigned char *)"abcdefghijklmnopqrstuvwxyz"; 602 /*while*/ *s; 603 /*doing*/ digval[*s++] = c++) /* skip */; 604 digval['_'] = 36; 605 } 606 607 608 long int expr(expbuf) 609 char *expbuf; 610 { 611 register int rval; 612 613 if (digval['1'] == 0) initialise_digval(); 614 nxtchr = (unsigned char *)expbuf; 615 deblank0; 616 if (setjmp(expjump) != 0) return FALSE; 617 rval = query(TRUE); 618 if (*nxtchr) experr("Ill-formed expression"); 619 return rval; 620 } 621 622