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