xref: /csrg-svn/old/adb/common_source/expr.c (revision 36559)
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