|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)expr.c 5.1 (Berkeley) 1/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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.