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