1 #ifndef lint 2 static char sccsid[] = "@(#)expr.c 5.1 (Berkeley) 01/16/89"; 3 #endif 4 5 /* 6 * adb - expression parser 7 */ 8 9 #include "defs.h" 10 #include <ctype.h> 11 12 extern char BADSYM[]; /* "symbol not found" */ 13 extern char BADVAR[]; /* "bad variable" */ 14 extern char BADSYN[]; /* "syntax error" */ 15 extern char NOCFN[]; /* "c routine not found" */ 16 extern char NOADR[]; /* "address expected" */ 17 extern char BADLOC[]; /* "automatic variable not found" */ 18 extern char NOPCS[]; /* "no process" */ 19 20 struct nlist *xxxsym; /* last symbol found due to expression */ 21 /* change this name back to cursym AFTER testing!... */ 22 struct activation curframe; /* current stack frame (for local vars) */ 23 24 /* 25 * This file implements a small recursive descent expression parser. 26 * The syntax is (in YACC terms): 27 * 28 * expr : expr1 29 * | (empty) 30 * ; 31 * 32 * expr1 : term 33 * | term dyadic expr1 34 * ; 35 * 36 * dyadic : '+' (addition) 37 * | '-' (subtraction) 38 * | '#' (roundup) 39 * | '*' (multiplication) 40 * | '%' (division) 41 * | '&' (bitwise and) 42 * | '|' (bitwise or) 43 * ; 44 * 45 * term : item 46 * | monadic term 47 * | '(' expr ')' 48 * ; 49 * 50 * monadic : '*' (contents of core, or SP_DATA) 51 * | '@' (contents of a.out, or SP_INSTR) 52 * | '-' (negation) 53 * | '~' (bitwise not) 54 * | '#' (logical not) 55 * ; 56 * 57 * item : number (current radix; 0o,0t,0x; or float) 58 * | name (value from symbol table) 59 * | rtn '.' name (address of name in routine rtn) 60 * | rtn '.' (???) 61 * | '.' name (???) 62 * | '.' (value of dot) 63 * | '+' (dot + current increment) 64 * | '^' (dot - current increment) 65 * | '"' (last address typed) 66 * | '<' var (value of variable var) 67 * | '<' register (value in register) 68 * | '\'' ch '\'' (character(s)) 69 * ; 70 * 71 * The empty string handling is actually done in `item', but callers 72 * can simply assume that expr() returns 1 if it finds an expression, 73 * or 0 if not, and that rexpr() errors out if there is no expression. 74 * 75 * The routines symchar() and getsym() handle `name's and `rtn's. 76 * The routine getnum(), with helper getfloat(), handles `number's. 77 */ 78 79 /* flags for symchar() */ 80 #define SYMCH_READ 1 /* call readchar() first */ 81 #define SYMCH_DIGITS 2 /* allow digits */ 82 83 /* 84 * Return true if the next (how & SYMCH_READ) or current character 85 * is a symbol character; allow digits if (how & SYMCH_DIGITS). 86 */ 87 static int 88 symchar(how) 89 int how; 90 { 91 92 if (how & SYMCH_READ) 93 (void) readchar(); 94 if (lastc == '\\') { 95 (void) readchar(); 96 return (1); 97 } 98 if (isalpha(lastc) || lastc == '_') 99 return (1); 100 return ((how & SYMCH_DIGITS) && isdigit(lastc)); 101 } 102 103 /* 104 * Read a symbol into the given buffer. The first character is 105 * assumed already to have been read. 106 */ 107 static 108 getsym(symbuf, symlen) 109 register char *symbuf; 110 register int symlen; 111 { 112 113 do { 114 if (--symlen > 0) 115 *symbuf++ = lastc; 116 } while (symchar(SYMCH_READ | SYMCH_DIGITS)); 117 *symbuf = 0; 118 } 119 120 /* 121 * Read a number. The converted value is stored in expv. 122 * The caller has already determined that there is at least one digit. 123 */ 124 static 125 getnum() 126 { 127 register int base, c; 128 129 expv = 0; 130 if ((base = radix) < 0) 131 base = -base; 132 if (lastc == '0') { 133 switch (readchar()) { 134 case 'x': case 'X': 135 base = 16; 136 (void) readchar(); 137 break; 138 case 't': case 'T': 139 base = 10; 140 (void) readchar(); 141 break; 142 case 'o': case 'O': 143 base = 8; 144 (void) readchar(); 145 } 146 } 147 for (c = lastc; isxdigit(c); c = readchar()) { 148 if (isdigit(c)) 149 c -= '0'; 150 else if (base <= 10) 151 break; 152 else 153 c -= isupper(c) ? 'A' - 10 : 'a' - 10; 154 if (c >= base) 155 error(BADSYN); 156 /* since expv is unsigned, the following cannot overflow */ 157 expv = expv * base + c; 158 } 159 if (lastc == '.' && (base == 10 || expv == 0)) 160 getfloat(); 161 unreadc(); 162 } 163 164 /* 165 * Read a float. The integer part is already in expv. Set expv 166 * to the integer bit pattern that corresponds to the float. 167 * 168 * The following routine could be improved, but at least it will 169 * not crash on input such as 0.999999999999999999999999999999, 170 * as did the original. 171 */ 172 getfloat() 173 { 174 register int i; 175 register char *p; 176 /* THE FOLLOWING ASSUMES sizeof(float)==sizeof(expr_t) */ 177 /* PERHAPS THIS SHOULD BE MOVED TO MACHINE DEPENDENT CODE */ 178 union { 179 float r; 180 expr_t e; 181 } gross; 182 /* end machine dependent */ 183 char hackbuf[50]; 184 double atof(); 185 186 for (i = sizeof(hackbuf), p = hackbuf; isdigit(readchar());) 187 if (--i > 0) 188 *p++ = lastc; 189 *p = 0; 190 gross.r = expv + atof(hackbuf); 191 expv = gross.e; 192 } 193 194 /* 195 * item : number | name [ '.' local ] | '.' local | '.' | '+' | '^' | '"' | 196 * '<' var | '<' register | '\'' char(s) '\'' ; 197 * 198 * item returns 1 if it finds an item, or 0 if it resolves to 199 * the empty string. 200 */ 201 static int 202 item(allownil) 203 int allownil; 204 { 205 register int i, c; 206 struct reglist *reg; 207 208 c = readchar(); 209 if (isdigit(c)) { 210 getnum(); 211 return (1); 212 } 213 if (symchar(0)) { 214 ev_name(); 215 return (1); 216 } 217 switch (c) { 218 219 case '.': 220 if (symchar(SYMCH_READ)) 221 ev_local(); /* SHOULD RESET xxxsym FIRST? */ 222 else 223 expv = dot; 224 unreadc(); 225 return (1); 226 227 case '"': 228 expv = ditto; 229 return (1); 230 231 case '+': 232 expv = inkdot(dotinc); 233 return (1); 234 235 case '^': 236 expv = inkdot(-dotinc); 237 return (1); 238 239 case '<': 240 if ((reg = reglookup()) != NULL) { 241 expv = getreg(reg); 242 return (1); 243 } 244 else if ((i = varlookup(rdc())) != -1) 245 expv = var[i]; 246 else 247 error(BADVAR); 248 return (1); 249 250 case '\'': 251 i = sizeof(expr_t) / sizeof(char); 252 for (expv = 0;; expv = (expv << NBBY) | c) { 253 if ((c = readchar()) == '\\') { 254 if ((c = readchar()) == 0) 255 break; 256 } else if (c == '\'') 257 break; 258 if (--i < 0) 259 error(BADSYN); 260 } 261 return (1); 262 } 263 if (!allownil) 264 error(NOADR); 265 unreadc(); 266 return (0); 267 } 268 269 /* 270 * term : item | monadic_op term | '(' expr ')' ; 271 */ 272 term(allownil) 273 int allownil; 274 { 275 276 switch (readchar()) { 277 278 case '*': 279 case '@': 280 (void) term(0); 281 (void) adbread(lastc == '@' ? SP_INSTR : SP_DATA, 282 (addr_t)expv, (caddr_t)&expv, sizeof(expv)); 283 checkerr(); 284 return (1); 285 286 case '-': 287 (void) term(0); 288 expv = -expv; 289 return (1); 290 291 case '~': 292 (void) term(0); 293 expv = ~expv; 294 return (1); 295 296 case '#': 297 (void) term(0); 298 expv = !expv; 299 return (1); 300 301 case '(': 302 (void) iexpr(0); 303 if (readchar() != ')') 304 error(BADSYN); 305 return (1); 306 307 default: 308 unreadc(); 309 return (item(allownil)); 310 } 311 } 312 313 /* 314 * expr : term | term dyadic expr | ; 315 * (internal version, which passes on the allow-nil flag) 316 */ 317 static int 318 iexpr(allownil) 319 int allownil; 320 { 321 register expr_t lhs, t; 322 323 (void) rdc(); 324 unreadc(); 325 if (!term(allownil)) 326 return (0); 327 for (;;) { 328 lhs = expv; 329 switch (readchar()) { 330 331 case '+': 332 (void) term(0); 333 expv += lhs; 334 break; 335 336 case '-': 337 (void) term(0); 338 expv = lhs - expv; 339 break; 340 341 case '#': 342 (void) term(0); 343 if (expv == 0) 344 error("# by 0"); 345 /* roundup(lhs, expv), but careful about overflow */ 346 t = lhs / expv; 347 t *= expv; 348 expv = t == lhs ? t : t + expv; 349 break; 350 351 case '*': 352 (void) term(0); 353 expv *= lhs; 354 break; 355 356 case '%': 357 (void) term(0); 358 expv = lhs / expv; 359 break; 360 361 case '&': 362 (void) term(0); 363 expv &= lhs; 364 break; 365 366 case '|': 367 (void) term(0); 368 expv |= lhs; 369 break; 370 371 default: 372 unreadc(); 373 return (1); 374 } 375 } 376 } 377 378 int 379 oexpr() 380 { 381 382 return (iexpr(1)); 383 } 384 385 expr_t 386 rexpr() 387 { 388 389 (void) iexpr(0); 390 return (expv); 391 } 392 393 /* 394 * Evaluate a name, or a name '.' localname. 395 */ 396 static 397 ev_name() 398 { 399 struct nlist *symp; 400 char symbuf[SYMLEN]; 401 402 /* name [ . localname ] */ 403 getsym(symbuf, sizeof(symbuf)); 404 if (lastc == '.') /* name . local */ 405 find_frame(symbuf); 406 else if ((symp = lookup(symbuf)) != NULL) 407 expv = (xxxsym = symp)->n_value; 408 else 409 error(BADSYM); 410 unreadc(); 411 } 412 413 /* 414 * Backtrack through the call stack to find the symbol in symbuf. 415 * Save the result, and if there is another name, look for it within 416 * that frame. Otherwise the value of the expression is the address 417 * of the found frame. 418 */ 419 static 420 find_frame(symbuf) 421 char *symbuf; 422 { 423 struct activation a; 424 addr_t dummy; /* for findsym() to scribble on */ 425 426 if (pid == 0) 427 error(NOPCS); 428 for (a_init(&a); a.a_valid; a_back(&a)) { 429 checkerr(); 430 if ((xxxsym = findsym(a.a_pc, SP_INSTR, &dummy)) == NULL) 431 break; 432 if (eqsym(xxxsym->n_un.n_name, symbuf, '_')) { 433 curframe = a; 434 if (symchar(SYMCH_READ)) 435 ev_local(); 436 else 437 expv = a.a_fp; 438 return; 439 } 440 } 441 error(NOCFN); 442 /* NOTREACHED */ 443 } 444 445 /* 446 * Linear search (ugh) for a symbol in the current stack frame. 447 */ 448 static 449 ev_local() 450 { 451 register struct nlist *sp; 452 register char *a, *b; 453 char symbuf[SYMLEN]; 454 455 if (pid == 0) 456 error(NOPCS); 457 if (!curframe.a_valid || (sp = xxxsym) == NULL) 458 error(NOCFN); 459 getsym(symbuf, SYMLEN); 460 while ((sp = nextlocal(sp)) != NULL) { 461 /* 462 * Local and parameter symbols (as generated by .stabs) 463 * end with ':', not '\0'; here we allow both. 464 */ 465 if (*(a = sp->n_un.n_name) != *(b = symbuf)) 466 continue; 467 while (*a == *b++) 468 if (*a++ == 0 || *a == ':') { 469 expv = eval_localsym(sp, &curframe); 470 xxxsym = sp; /* ??? */ 471 return; 472 } 473 } 474 error(BADLOC); 475 } 476 477 #ifndef inkdot 478 /* 479 * Function version of inkdot(). Compute the new dot, and check for 480 * address wrap-around. 481 */ 482 addr_t 483 inkdot(incr) 484 int incr; 485 { 486 addr_t newdot = dot + incr; 487 488 if (ADDRESS_WRAP(dot, newdot)) 489 error(ADWRAP); 490 return (newdot); 491 } 492 #endif 493