1 /* $OpenBSD: expr.c,v 1.4 1997/06/19 13:58:41 kstailey Exp $ */ 2 3 /* 4 * Korn expression evaluation 5 */ 6 /* 7 * todo: better error handling: if in builtin, should be builtin error, etc. 8 */ 9 10 #include "sh.h" 11 #include <ctype.h> 12 13 14 /* The order of these enums is constrained by the order of opinfo[] */ 15 enum token { 16 /* some (long) unary operators */ 17 O_PLUSPLUS = 0, O_MINUSMINUS, 18 /* binary operators */ 19 O_EQ, O_NE, 20 /* assignments are assumed to be in range O_ASN .. O_BORASN */ 21 O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN, 22 O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN, 23 O_LSHIFT, O_RSHIFT, 24 O_LE, O_GE, O_LT, O_GT, 25 O_LAND, 26 O_LOR, 27 O_TIMES, O_DIV, O_MOD, 28 O_PLUS, O_MINUS, 29 O_BAND, 30 O_BXOR, 31 O_BOR, 32 O_TERN, 33 O_COMMA, 34 /* things after this aren't used as binary operators */ 35 /* unary that are not also binaries */ 36 O_BNOT, O_LNOT, 37 /* misc */ 38 OPEN_PAREN, CLOSE_PAREN, CTERN, 39 /* things that don't appear in the opinfo[] table */ 40 VAR, LIT, END, BAD 41 }; 42 #define IS_BINOP(op) (((int)op) >= O_EQ && ((int)op) <= O_COMMA) 43 #define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN) 44 45 enum prec { 46 P_PRIMARY = 0, /* VAR, LIT, (), ~ ! - + */ 47 P_MULT, /* * / % */ 48 P_ADD, /* + - */ 49 P_SHIFT, /* << >> */ 50 P_RELATION, /* < <= > >= */ 51 P_EQUALITY, /* == != */ 52 P_BAND, /* & */ 53 P_BXOR, /* ^ */ 54 P_BOR, /* | */ 55 P_LAND, /* && */ 56 P_LOR, /* || */ 57 P_TERN, /* ?: */ 58 P_ASSIGN, /* = *= /= %= += -= <<= >>= &= ^= |= */ 59 P_COMMA /* , */ 60 }; 61 #define MAX_PREC P_COMMA 62 63 struct opinfo { 64 char name[4]; 65 int len; /* name length */ 66 enum prec prec; /* precidence: lower is higher */ 67 }; 68 69 /* Tokens in this table must be ordered so the longest are first 70 * (eg, += before +). If you change something, change the order 71 * of enum token too. 72 */ 73 static const struct opinfo opinfo[] = { 74 { "++", 2, P_PRIMARY }, /* before + */ 75 { "--", 2, P_PRIMARY }, /* before - */ 76 { "==", 2, P_EQUALITY }, /* before = */ 77 { "!=", 2, P_EQUALITY }, /* before ! */ 78 { "=", 1, P_ASSIGN }, /* keep assigns in a block */ 79 { "*=", 2, P_ASSIGN }, 80 { "/=", 2, P_ASSIGN }, 81 { "%=", 2, P_ASSIGN }, 82 { "+=", 2, P_ASSIGN }, 83 { "-=", 2, P_ASSIGN }, 84 { "<<=", 3, P_ASSIGN }, 85 { ">>=", 3, P_ASSIGN }, 86 { "&=", 2, P_ASSIGN }, 87 { "^=", 2, P_ASSIGN }, 88 { "|=", 2, P_ASSIGN }, 89 { "<<", 2, P_SHIFT }, 90 { ">>", 2, P_SHIFT }, 91 { "<=", 2, P_RELATION }, 92 { ">=", 2, P_RELATION }, 93 { "<", 1, P_RELATION }, 94 { ">", 1, P_RELATION }, 95 { "&&", 2, P_LAND }, 96 { "||", 2, P_LOR }, 97 { "*", 1, P_MULT }, 98 { "/", 1, P_MULT }, 99 { "%", 1, P_MULT }, 100 { "+", 1, P_ADD }, 101 { "-", 1, P_ADD }, 102 { "&", 1, P_BAND }, 103 { "^", 1, P_BXOR }, 104 { "|", 1, P_BOR }, 105 { "?", 1, P_TERN }, 106 { ",", 1, P_COMMA }, 107 { "~", 1, P_PRIMARY }, 108 { "!", 1, P_PRIMARY }, 109 { "(", 1, P_PRIMARY }, 110 { ")", 1, P_PRIMARY }, 111 { ":", 1, P_PRIMARY }, 112 { "", 0, P_PRIMARY } /* end of table */ 113 }; 114 115 116 typedef struct expr_state Expr_state; 117 struct expr_state { 118 const char *expression; /* expression being evaluated */ 119 const char *tokp; /* lexical position */ 120 enum token tok; /* token from token() */ 121 int noassign; /* don't do assigns (for ?:,&&,||) */ 122 struct tbl *val; /* value from token() */ 123 struct tbl *evaling; /* variable that is being recursively 124 * expanded (EXPRINEVAL flag set) 125 */ 126 Expr_state *volatile prev; /* previous state */ 127 }; 128 129 enum error_type { ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE, 130 ET_LVALUE, ET_RDONLY, ET_STR }; 131 132 static Expr_state *es; 133 134 static void evalerr ARGS((enum error_type type, const char *str)) 135 GCC_FUNC_ATTR(noreturn); 136 static struct tbl *evalexpr ARGS((enum prec prec)); 137 static void token ARGS((void)); 138 static struct tbl *do_ppmm ARGS((enum token op, struct tbl *vasn, 139 bool_t is_prefix)); 140 static void assign_check ARGS((enum token op, struct tbl *vasn)); 141 static struct tbl *tempvar ARGS((void)); 142 static struct tbl *intvar ARGS((struct tbl *vp)); 143 144 /* 145 * parse and evalute expression 146 */ 147 int 148 evaluate(expr, rval, error_ok) 149 const char *expr; 150 long *rval; 151 int error_ok; 152 { 153 struct tbl v; 154 int ret; 155 156 v.flag = DEFINED|INTEGER; 157 v.type = 0; 158 ret = v_evaluate(&v, expr, error_ok); 159 *rval = v.val.i; 160 return ret; 161 } 162 163 /* 164 * parse and evalute expression, storing result in vp. 165 */ 166 int 167 v_evaluate(vp, expr, error_ok) 168 struct tbl *vp; 169 const char *expr; 170 volatile int error_ok; 171 { 172 struct tbl *v; 173 Expr_state curstate; 174 int i; 175 176 /* save state to allow recursive calls */ 177 curstate.expression = curstate.tokp = expr; 178 curstate.noassign = 0; 179 curstate.prev = es; 180 curstate.evaling = (struct tbl *) 0; 181 es = &curstate; 182 183 newenv(E_ERRH); 184 i = ksh_sigsetjmp(e->jbuf, 0); 185 if (i) { 186 /* Clear EXPRINEVAL in of any variables we were playing with */ 187 if (curstate.evaling) 188 curstate.evaling->flag &= ~EXPRINEVAL; 189 quitenv(); 190 es = curstate.prev; 191 if (i == LAEXPR) { 192 if (error_ok) 193 return 0; 194 errorf(null); 195 } 196 unwind(i); 197 /*NOTREACHED*/ 198 } 199 200 token(); 201 #if 1 /* ifdef-out to disallow empty expressions to be treated as 0 */ 202 if (es->tok == END) { 203 es->tok = LIT; 204 es->val = tempvar(); 205 } 206 #endif /* 0 */ 207 v = intvar(evalexpr(MAX_PREC)); 208 209 if (es->tok != END) 210 evalerr(ET_UNEXPECTED, (char *) 0); 211 212 if (vp->flag & INTEGER) 213 setint_v(vp, v); 214 else 215 setstr(vp, str_val(v)); 216 217 es = curstate.prev; 218 quitenv(); 219 220 return 1; 221 } 222 223 static void 224 evalerr(type, str) 225 enum error_type type; 226 const char *str; 227 { 228 char tbuf[2]; 229 const char *s; 230 231 switch (type) { 232 case ET_UNEXPECTED: 233 switch (es->tok) { 234 case VAR: 235 s = es->val->name; 236 break; 237 case LIT: 238 s = str_val(es->val); 239 break; 240 case END: 241 s = "end of expression"; 242 break; 243 case BAD: 244 tbuf[0] = *es->tokp; 245 tbuf[1] = '\0'; 246 s = tbuf; 247 break; 248 default: 249 s = opinfo[(int)es->tok].name; 250 } 251 warningf(TRUE, "%s: unexpected `%s'", es->expression, s); 252 break; 253 254 case ET_BADLIT: 255 warningf(TRUE, "%s: bad number `%s'", es->expression, str); 256 break; 257 258 case ET_RECURSIVE: 259 warningf(TRUE, "%s: expression recurses on parameter `%s'", 260 es->expression, str); 261 break; 262 263 case ET_LVALUE: 264 warningf(TRUE, "%s: %s requires lvalue", 265 es->expression, str); 266 break; 267 268 case ET_RDONLY: 269 warningf(TRUE, "%s: %s applied to read only variable", 270 es->expression, str); 271 break; 272 273 default: /* keep gcc happy */ 274 case ET_STR: 275 warningf(TRUE, "%s: %s", es->expression, str); 276 break; 277 } 278 unwind(LAEXPR); 279 } 280 281 static struct tbl * 282 evalexpr(prec) 283 enum prec prec; 284 { 285 register struct tbl *vl, UNINITIALIZED(*vr), *vasn; 286 register enum token op; 287 long UNINITIALIZED(res); 288 289 if (prec == P_PRIMARY) { 290 op = es->tok; 291 if (op == O_BNOT || op == O_LNOT || op == O_MINUS 292 || op == O_PLUS) 293 { 294 token(); 295 vl = intvar(evalexpr(P_PRIMARY)); 296 if (op == O_BNOT) 297 vl->val.i = ~vl->val.i; 298 else if (op == O_LNOT) 299 vl->val.i = !vl->val.i; 300 else if (op == O_MINUS) 301 vl->val.i = -vl->val.i; 302 /* op == O_PLUS is a no-op */ 303 } else if (op == OPEN_PAREN) { 304 token(); 305 vl = evalexpr(MAX_PREC); 306 if (es->tok != CLOSE_PAREN) 307 evalerr(ET_STR, "missing )"); 308 token(); 309 } else if (op == O_PLUSPLUS || op == O_MINUSMINUS) { 310 token(); 311 vl = do_ppmm(op, es->val, TRUE); 312 token(); 313 } else if (op == VAR || op == LIT) { 314 vl = es->val; 315 token(); 316 } else { 317 evalerr(ET_UNEXPECTED, (char *) 0); 318 /*NOTREACHED*/ 319 } 320 if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) { 321 vl = do_ppmm(es->tok, vl, FALSE); 322 token(); 323 } 324 return vl; 325 } 326 vl = evalexpr(((int) prec) - 1); 327 for (op = es->tok; IS_BINOP(op) && opinfo[(int) op].prec == prec; 328 op = es->tok) 329 { 330 token(); 331 vasn = vl; 332 if (op != O_ASN) /* vl may not have a value yet */ 333 vl = intvar(vl); 334 if (IS_ASSIGNOP(op)) { 335 assign_check(op, vasn); 336 vr = intvar(evalexpr(P_ASSIGN)); 337 } else if (op != O_TERN && op != O_LAND && op != O_LOR) 338 vr = intvar(evalexpr(((int) prec) - 1)); 339 if ((op == O_DIV || op == O_MOD || op == O_DIVASN 340 || op == O_MODASN) && vr->val.i == 0) 341 { 342 if (es->noassign) 343 vr->val.i = 1; 344 else 345 evalerr(ET_STR, "zero divisor"); 346 } 347 switch ((int) op) { 348 case O_TIMES: 349 case O_TIMESASN: 350 res = vl->val.i * vr->val.i; 351 break; 352 case O_DIV: 353 case O_DIVASN: 354 res = vl->val.i / vr->val.i; 355 break; 356 case O_MOD: 357 case O_MODASN: 358 res = vl->val.i % vr->val.i; 359 break; 360 case O_PLUS: 361 case O_PLUSASN: 362 res = vl->val.i + vr->val.i; 363 break; 364 case O_MINUS: 365 case O_MINUSASN: 366 res = vl->val.i - vr->val.i; 367 break; 368 case O_LSHIFT: 369 case O_LSHIFTASN: 370 res = vl->val.i << vr->val.i; 371 break; 372 case O_RSHIFT: 373 case O_RSHIFTASN: 374 res = vl->val.i >> vr->val.i; 375 break; 376 case O_LT: 377 res = vl->val.i < vr->val.i; 378 break; 379 case O_LE: 380 res = vl->val.i <= vr->val.i; 381 break; 382 case O_GT: 383 res = vl->val.i > vr->val.i; 384 break; 385 case O_GE: 386 res = vl->val.i >= vr->val.i; 387 break; 388 case O_EQ: 389 res = vl->val.i == vr->val.i; 390 break; 391 case O_NE: 392 res = vl->val.i != vr->val.i; 393 break; 394 case O_BAND: 395 case O_BANDASN: 396 res = vl->val.i & vr->val.i; 397 break; 398 case O_BXOR: 399 case O_BXORASN: 400 res = vl->val.i ^ vr->val.i; 401 break; 402 case O_BOR: 403 case O_BORASN: 404 res = vl->val.i | vr->val.i; 405 break; 406 case O_LAND: 407 if (!vl->val.i) 408 es->noassign++; 409 vr = intvar(evalexpr(((int) prec) - 1)); 410 res = vl->val.i && vr->val.i; 411 if (!vl->val.i) 412 es->noassign--; 413 break; 414 case O_LOR: 415 if (vl->val.i) 416 es->noassign++; 417 vr = intvar(evalexpr(((int) prec) - 1)); 418 res = vl->val.i || vr->val.i; 419 if (vl->val.i) 420 es->noassign--; 421 break; 422 case O_TERN: 423 { 424 int e = vl->val.i != 0; 425 if (!e) 426 es->noassign++; 427 vl = evalexpr(MAX_PREC); 428 if (!e) 429 es->noassign--; 430 if (es->tok != CTERN) 431 evalerr(ET_STR, "missing :"); 432 token(); 433 if (e) 434 es->noassign++; 435 vr = evalexpr(P_TERN); 436 if (e) 437 es->noassign--; 438 vl = e ? vl : vr; 439 } 440 break; 441 case O_ASN: 442 res = vr->val.i; 443 break; 444 case O_COMMA: 445 res = vr->val.i; 446 break; 447 } 448 if (IS_ASSIGNOP(op)) { 449 vr->val.i = res; 450 if (vasn->flag & INTEGER) 451 setint_v(vasn, vr); 452 else 453 setint(vasn, res); 454 vl = vr; 455 } else if (op != O_TERN) 456 vl->val.i = res; 457 } 458 return vl; 459 } 460 461 static void 462 token() 463 { 464 register const char *cp; 465 register int c; 466 char *tvar; 467 468 /* skip white space */ 469 for (cp = es->tokp; (c = *cp), isspace(c); cp++) 470 ; 471 es->tokp = cp; 472 473 if (c == '\0') 474 es->tok = END; 475 else if (letter(c)) { 476 for (; letnum(c); c = *cp) 477 cp++; 478 if (c == '[') { 479 int len; 480 481 len = array_ref_len(cp); 482 if (len == 0) 483 evalerr(ET_STR, "missing ]"); 484 cp += len; 485 } 486 if (es->noassign) { 487 es->val = tempvar(); 488 es->val->flag |= EXPRLVALUE; 489 } else { 490 tvar = str_nsave(es->tokp, cp - es->tokp, ATEMP); 491 es->val = global(tvar); 492 afree(tvar, ATEMP); 493 } 494 es->tok = VAR; 495 } else if (digit(c)) { 496 for (; c != '_' && (letnum(c) || c == '#'); c = *cp++) 497 ; 498 tvar = str_nsave(es->tokp, --cp - es->tokp, ATEMP); 499 es->val = tempvar(); 500 es->val->flag &= ~INTEGER; 501 es->val->type = 0; 502 es->val->val.s = tvar; 503 if (setint_v(es->val, es->val) == NULL) 504 evalerr(ET_BADLIT, tvar); 505 afree(tvar, ATEMP); 506 es->tok = LIT; 507 } else { 508 int i, n0; 509 510 for (i = 0; (n0 = opinfo[i].name[0]); i++) 511 if (c == n0 512 && strncmp(cp, opinfo[i].name, opinfo[i].len) == 0) 513 { 514 es->tok = (enum token) i; 515 cp += opinfo[i].len; 516 break; 517 } 518 if (!n0) 519 es->tok = BAD; 520 } 521 es->tokp = cp; 522 } 523 524 /* Do a ++ or -- operation */ 525 static struct tbl * 526 do_ppmm(op, vasn, is_prefix) 527 enum token op; 528 struct tbl *vasn; 529 bool_t is_prefix; 530 { 531 struct tbl *vl; 532 int oval; 533 534 assign_check(op, vasn); 535 536 vl = intvar(vasn); 537 oval = op == O_PLUSPLUS ? vl->val.i++ : vl->val.i--; 538 if (vasn->flag & INTEGER) 539 setint_v(vasn, vl); 540 else 541 setint(vasn, vl->val.i); 542 if (!is_prefix) /* undo the inc/dec */ 543 vl->val.i = oval; 544 545 return vl; 546 } 547 548 static void 549 assign_check(op, vasn) 550 enum token op; 551 struct tbl *vasn; 552 { 553 if (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE)) 554 evalerr(ET_LVALUE, opinfo[op].name); 555 else if (vasn->flag & RDONLY) 556 evalerr(ET_RDONLY, opinfo[op].name); 557 } 558 559 static struct tbl * 560 tempvar() 561 { 562 register struct tbl *vp; 563 564 vp = (struct tbl*) alloc(sizeof(struct tbl), ATEMP); 565 vp->flag = ISSET|INTEGER; 566 vp->type = 0; 567 vp->areap = ATEMP; 568 vp->val.i = 0; 569 vp->name[0] = '\0'; 570 return vp; 571 } 572 573 /* cast (string) variable to temporary integer variable */ 574 static struct tbl * 575 intvar(vp) 576 register struct tbl *vp; 577 { 578 register struct tbl *vq; 579 580 /* try to avoid replacing a temp var with another temp var */ 581 if (vp->name[0] == '\0' 582 && (vp->flag & (ISSET|INTEGER|EXPRLVALUE)) == (ISSET|INTEGER)) 583 return vp; 584 585 vq = tempvar(); 586 if (setint_v(vq, vp) == NULL) { 587 if (vp->flag & EXPRINEVAL) 588 evalerr(ET_RECURSIVE, vp->name); 589 es->evaling = vp; 590 vp->flag |= EXPRINEVAL; 591 v_evaluate(vq, str_val(vp), FALSE); 592 vp->flag &= ~EXPRINEVAL; 593 es->evaling = (struct tbl *) 0; 594 } 595 return vq; 596 } 597