|
|
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.