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
symchar(how)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
getsym(symbuf,symlen)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
getnum()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 */
getfloat()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
item(allownil)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 */
term(allownil)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
iexpr(allownil)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
oexpr()386 oexpr()
387 {
388
389 return (iexpr(1));
390 }
391
392 expr_t
rexpr()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
ev_name()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
find_frame(symbuf)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
ev_local()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
inkdot(incr)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