xref: /csrg-svn/old/adb/common_source/expr.c (revision 47822)
1*47822Sbostic /*-
2*47822Sbostic  * Copyright (c) 1991 The Regents of the University of California.
3*47822Sbostic  * All rights reserved.
4*47822Sbostic  *
5*47822Sbostic  * %sccs.include.proprietary.c%
6*47822Sbostic  */
7*47822Sbostic 
836559Sbostic #ifndef lint
9*47822Sbostic static char sccsid[] = "@(#)expr.c	5.2 (Berkeley) 04/04/91";
10*47822Sbostic #endif /* not lint */
1136559Sbostic 
1236559Sbostic /*
1336559Sbostic  * adb - expression parser
1436559Sbostic  */
1536559Sbostic 
1636559Sbostic #include "defs.h"
1736559Sbostic #include <ctype.h>
1836559Sbostic 
1936559Sbostic extern char BADSYM[];		/* "symbol not found" */
2036559Sbostic extern char BADVAR[];		/* "bad variable" */
2136559Sbostic extern char BADSYN[];		/* "syntax error" */
2236559Sbostic extern char NOCFN[];		/* "c routine not found" */
2336559Sbostic extern char NOADR[];		/* "address expected" */
2436559Sbostic extern char BADLOC[];		/* "automatic variable not found" */
2536559Sbostic extern char NOPCS[];		/* "no process" */
2636559Sbostic 
2736559Sbostic struct	nlist *xxxsym;		/* last symbol found due to expression */
2836559Sbostic 	/* change this name back to cursym AFTER testing!... */
2936559Sbostic struct	activation curframe;	/* current stack frame (for local vars) */
3036559Sbostic 
3136559Sbostic /*
3236559Sbostic  * This file implements a small recursive descent expression parser.
3336559Sbostic  * The syntax is (in YACC terms):
3436559Sbostic  *
3536559Sbostic  *	expr	: expr1
3636559Sbostic  *		|		(empty)
3736559Sbostic  *		;
3836559Sbostic  *
3936559Sbostic  *	expr1	: term
4036559Sbostic  *		| term dyadic expr1
4136559Sbostic  *		;
4236559Sbostic  *
4336559Sbostic  *	dyadic	: '+'		(addition)
4436559Sbostic  *		| '-'		(subtraction)
4536559Sbostic  *		| '#'		(roundup)
4636559Sbostic  *		| '*'		(multiplication)
4736559Sbostic  *		| '%'		(division)
4836559Sbostic  *		| '&'		(bitwise and)
4936559Sbostic  *		| '|'		(bitwise or)
5036559Sbostic  *		;
5136559Sbostic  *
5236559Sbostic  *	term	: item
5336559Sbostic  *		| monadic term
5436559Sbostic  *		| '(' expr ')'
5536559Sbostic  *		;
5636559Sbostic  *
5736559Sbostic  *	monadic	: '*'		(contents of core, or SP_DATA)
5836559Sbostic  *		| '@'		(contents of a.out, or SP_INSTR)
5936559Sbostic  *		| '-'		(negation)
6036559Sbostic  *		| '~'		(bitwise not)
6136559Sbostic  *		| '#'		(logical not)
6236559Sbostic  *		;
6336559Sbostic  *
6436559Sbostic  *	item	: number	(current radix; 0o,0t,0x; or float)
6536559Sbostic  *		| name		(value from symbol table)
6636559Sbostic  *		| rtn '.' name	(address of name in routine rtn)
6736559Sbostic  *		| rtn '.'	(???)
6836559Sbostic  *		| '.' name	(???)
6936559Sbostic  *		| '.'		(value of dot)
7036559Sbostic  *		| '+'		(dot + current increment)
7136559Sbostic  *		| '^'		(dot - current increment)
7236559Sbostic  *		| '"'		(last address typed)
7336559Sbostic  *		| '<' var	(value of variable var)
7436559Sbostic  *		| '<' register	(value in register)
7536559Sbostic  *		| '\'' ch '\''	(character(s))
7636559Sbostic  *		;
7736559Sbostic  *
7836559Sbostic  * The empty string handling is actually done in `item', but callers
7936559Sbostic  * can simply assume that expr() returns 1 if it finds an expression,
8036559Sbostic  * or 0 if not, and that rexpr() errors out if there is no expression.
8136559Sbostic  *
8236559Sbostic  * The routines symchar() and getsym() handle `name's and `rtn's.
8336559Sbostic  * The routine getnum(), with helper getfloat(), handles `number's.
8436559Sbostic  */
8536559Sbostic 
8636559Sbostic /* flags for symchar() */
8736559Sbostic #define	SYMCH_READ	1	/* call readchar() first */
8836559Sbostic #define	SYMCH_DIGITS	2	/* allow digits */
8936559Sbostic 
9036559Sbostic /*
9136559Sbostic  * Return true if the next (how & SYMCH_READ) or current character
9236559Sbostic  * is a symbol character; allow digits if (how & SYMCH_DIGITS).
9336559Sbostic  */
9436559Sbostic static int
symchar(how)9536559Sbostic symchar(how)
9636559Sbostic 	int how;
9736559Sbostic {
9836559Sbostic 
9936559Sbostic 	if (how & SYMCH_READ)
10036559Sbostic 		(void) readchar();
10136559Sbostic 	if (lastc == '\\') {
10236559Sbostic 		(void) readchar();
10336559Sbostic 		return (1);
10436559Sbostic 	}
10536559Sbostic 	if (isalpha(lastc) || lastc == '_')
10636559Sbostic 		return (1);
10736559Sbostic 	return ((how & SYMCH_DIGITS) && isdigit(lastc));
10836559Sbostic }
10936559Sbostic 
11036559Sbostic /*
11136559Sbostic  * Read a symbol into the given buffer.  The first character is
11236559Sbostic  * assumed already to have been read.
11336559Sbostic  */
11436559Sbostic static
getsym(symbuf,symlen)11536559Sbostic getsym(symbuf, symlen)
11636559Sbostic 	register char *symbuf;
11736559Sbostic 	register int symlen;
11836559Sbostic {
11936559Sbostic 
12036559Sbostic 	do {
12136559Sbostic 		if (--symlen > 0)
12236559Sbostic 			*symbuf++ = lastc;
12336559Sbostic 	} while (symchar(SYMCH_READ | SYMCH_DIGITS));
12436559Sbostic 	*symbuf = 0;
12536559Sbostic }
12636559Sbostic 
12736559Sbostic /*
12836559Sbostic  * Read a number.  The converted value is stored in expv.
12936559Sbostic  * The caller has already determined that there is at least one digit.
13036559Sbostic  */
13136559Sbostic static
getnum()13236559Sbostic getnum()
13336559Sbostic {
13436559Sbostic 	register int base, c;
13536559Sbostic 
13636559Sbostic 	expv = 0;
13736559Sbostic 	if ((base = radix) < 0)
13836559Sbostic 		base = -base;
13936559Sbostic 	if (lastc == '0') {
14036559Sbostic 		switch (readchar()) {
14136559Sbostic 		case 'x': case 'X':
14236559Sbostic 			base = 16;
14336559Sbostic 			(void) readchar();
14436559Sbostic 			break;
14536559Sbostic 		case 't': case 'T':
14636559Sbostic 			base = 10;
14736559Sbostic 			(void) readchar();
14836559Sbostic 			break;
14936559Sbostic 		case 'o': case 'O':
15036559Sbostic 			base = 8;
15136559Sbostic 			(void) readchar();
15236559Sbostic 		}
15336559Sbostic 	}
15436559Sbostic 	for (c = lastc; isxdigit(c); c = readchar()) {
15536559Sbostic 		if (isdigit(c))
15636559Sbostic 			c -= '0';
15736559Sbostic 		else if (base <= 10)
15836559Sbostic 			break;
15936559Sbostic 		else
16036559Sbostic 			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
16136559Sbostic 		if (c >= base)
16236559Sbostic 			error(BADSYN);
16336559Sbostic 		/* since expv is unsigned, the following cannot overflow */
16436559Sbostic 		expv = expv * base + c;
16536559Sbostic 	}
16636559Sbostic 	if (lastc == '.' && (base == 10 || expv == 0))
16736559Sbostic 		getfloat();
16836559Sbostic 	unreadc();
16936559Sbostic }
17036559Sbostic 
17136559Sbostic /*
17236559Sbostic  * Read a float.  The integer part is already in expv.  Set expv
17336559Sbostic  * to the integer bit pattern that corresponds to the float.
17436559Sbostic  *
17536559Sbostic  * The following routine could be improved, but at least it will
17636559Sbostic  * not crash on input such as 0.999999999999999999999999999999,
17736559Sbostic  * as did the original.
17836559Sbostic  */
getfloat()17936559Sbostic getfloat()
18036559Sbostic {
18136559Sbostic 	register int i;
18236559Sbostic 	register char *p;
18336559Sbostic  /* THE FOLLOWING ASSUMES sizeof(float)==sizeof(expr_t) */
18436559Sbostic  /* PERHAPS THIS SHOULD BE MOVED TO MACHINE DEPENDENT CODE */
18536559Sbostic 	union {
18636559Sbostic 		float r;
18736559Sbostic 		expr_t e;
18836559Sbostic 	} gross;
18936559Sbostic  /* end machine dependent */
19036559Sbostic 	char hackbuf[50];
19136559Sbostic 	double atof();
19236559Sbostic 
19336559Sbostic 	for (i = sizeof(hackbuf), p = hackbuf; isdigit(readchar());)
19436559Sbostic 		if (--i > 0)
19536559Sbostic 			*p++ = lastc;
19636559Sbostic 	*p = 0;
19736559Sbostic 	gross.r = expv + atof(hackbuf);
19836559Sbostic 	expv = gross.e;
19936559Sbostic }
20036559Sbostic 
20136559Sbostic /*
20236559Sbostic  * item : number | name [ '.' local ] | '.' local | '.' | '+' | '^' | '"' |
20336559Sbostic  *	  '<' var | '<' register | '\'' char(s) '\'' ;
20436559Sbostic  *
20536559Sbostic  * item returns 1 if it finds an item, or 0 if it resolves to
20636559Sbostic  * the empty string.
20736559Sbostic  */
20836559Sbostic static int
item(allownil)20936559Sbostic item(allownil)
21036559Sbostic 	int allownil;
21136559Sbostic {
21236559Sbostic 	register int i, c;
21336559Sbostic 	struct reglist *reg;
21436559Sbostic 
21536559Sbostic 	c = readchar();
21636559Sbostic 	if (isdigit(c)) {
21736559Sbostic 		getnum();
21836559Sbostic 		return (1);
21936559Sbostic 	}
22036559Sbostic 	if (symchar(0)) {
22136559Sbostic 		ev_name();
22236559Sbostic 		return (1);
22336559Sbostic 	}
22436559Sbostic 	switch (c) {
22536559Sbostic 
22636559Sbostic 	case '.':
22736559Sbostic 		if (symchar(SYMCH_READ))
22836559Sbostic 			ev_local();	/* SHOULD RESET xxxsym FIRST? */
22936559Sbostic 		else
23036559Sbostic 			expv = dot;
23136559Sbostic 		unreadc();
23236559Sbostic 		return (1);
23336559Sbostic 
23436559Sbostic 	case '"':
23536559Sbostic 		expv = ditto;
23636559Sbostic 		return (1);
23736559Sbostic 
23836559Sbostic 	case '+':
23936559Sbostic 		expv = inkdot(dotinc);
24036559Sbostic 		return (1);
24136559Sbostic 
24236559Sbostic 	case '^':
24336559Sbostic 		expv = inkdot(-dotinc);
24436559Sbostic 		return (1);
24536559Sbostic 
24636559Sbostic 	case '<':
24736559Sbostic 		if ((reg = reglookup()) != NULL) {
24836559Sbostic 			expv = getreg(reg);
24936559Sbostic 			return (1);
25036559Sbostic 		}
25136559Sbostic 		else if ((i = varlookup(rdc())) != -1)
25236559Sbostic 			expv = var[i];
25336559Sbostic 		else
25436559Sbostic 			error(BADVAR);
25536559Sbostic 		return (1);
25636559Sbostic 
25736559Sbostic 	case '\'':
25836559Sbostic 		i = sizeof(expr_t) / sizeof(char);
25936559Sbostic 		for (expv = 0;; expv = (expv << NBBY) | c) {
26036559Sbostic 			if ((c = readchar()) == '\\') {
26136559Sbostic 				if ((c = readchar()) == 0)
26236559Sbostic 					break;
26336559Sbostic 			} else if (c == '\'')
26436559Sbostic 				break;
26536559Sbostic 			if (--i < 0)
26636559Sbostic 				error(BADSYN);
26736559Sbostic 		}
26836559Sbostic 		return (1);
26936559Sbostic 	}
27036559Sbostic 	if (!allownil)
27136559Sbostic 		error(NOADR);
27236559Sbostic 	unreadc();
27336559Sbostic 	return (0);
27436559Sbostic }
27536559Sbostic 
27636559Sbostic /*
27736559Sbostic  * term : item | monadic_op term | '(' expr ')' ;
27836559Sbostic  */
term(allownil)27936559Sbostic term(allownil)
28036559Sbostic 	int allownil;
28136559Sbostic {
28236559Sbostic 
28336559Sbostic 	switch (readchar()) {
28436559Sbostic 
28536559Sbostic 	case '*':
28636559Sbostic 	case '@':
28736559Sbostic 		(void) term(0);
28836559Sbostic 		(void) adbread(lastc == '@' ? SP_INSTR : SP_DATA,
28936559Sbostic 		    (addr_t)expv, (caddr_t)&expv, sizeof(expv));
29036559Sbostic 		checkerr();
29136559Sbostic 		return (1);
29236559Sbostic 
29336559Sbostic 	case '-':
29436559Sbostic 		(void) term(0);
29536559Sbostic 		expv = -expv;
29636559Sbostic 		return (1);
29736559Sbostic 
29836559Sbostic 	case '~':
29936559Sbostic 		(void) term(0);
30036559Sbostic 		expv = ~expv;
30136559Sbostic 		return (1);
30236559Sbostic 
30336559Sbostic 	case '#':
30436559Sbostic 		(void) term(0);
30536559Sbostic 		expv = !expv;
30636559Sbostic 		return (1);
30736559Sbostic 
30836559Sbostic 	case '(':
30936559Sbostic 		(void) iexpr(0);
31036559Sbostic 		if (readchar() != ')')
31136559Sbostic 			error(BADSYN);
31236559Sbostic 		return (1);
31336559Sbostic 
31436559Sbostic 	default:
31536559Sbostic 		unreadc();
31636559Sbostic 		return (item(allownil));
31736559Sbostic 	}
31836559Sbostic }
31936559Sbostic 
32036559Sbostic /*
32136559Sbostic  * expr : term | term dyadic expr | ;
32236559Sbostic  * (internal version, which passes on the allow-nil flag)
32336559Sbostic  */
32436559Sbostic static int
iexpr(allownil)32536559Sbostic iexpr(allownil)
32636559Sbostic 	int allownil;
32736559Sbostic {
32836559Sbostic 	register expr_t lhs, t;
32936559Sbostic 
33036559Sbostic 	(void) rdc();
33136559Sbostic 	unreadc();
33236559Sbostic 	if (!term(allownil))
33336559Sbostic 		return (0);
33436559Sbostic 	for (;;) {
33536559Sbostic 		lhs = expv;
33636559Sbostic 		switch (readchar()) {
33736559Sbostic 
33836559Sbostic 		case '+':
33936559Sbostic 			(void) term(0);
34036559Sbostic 			expv += lhs;
34136559Sbostic 			break;
34236559Sbostic 
34336559Sbostic 		case '-':
34436559Sbostic 			(void) term(0);
34536559Sbostic 			expv = lhs - expv;
34636559Sbostic 			break;
34736559Sbostic 
34836559Sbostic 		case '#':
34936559Sbostic 			(void) term(0);
35036559Sbostic 			if (expv == 0)
35136559Sbostic 				error("# by 0");
35236559Sbostic 			/* roundup(lhs, expv), but careful about overflow */
35336559Sbostic 			t = lhs / expv;
35436559Sbostic 			t *= expv;
35536559Sbostic 			expv = t == lhs ? t : t + expv;
35636559Sbostic 			break;
35736559Sbostic 
35836559Sbostic 		case '*':
35936559Sbostic 			(void) term(0);
36036559Sbostic 			expv *= lhs;
36136559Sbostic 			break;
36236559Sbostic 
36336559Sbostic 		case '%':
36436559Sbostic 			(void) term(0);
36536559Sbostic 			expv = lhs / expv;
36636559Sbostic 			break;
36736559Sbostic 
36836559Sbostic 		case '&':
36936559Sbostic 			(void) term(0);
37036559Sbostic 			expv &= lhs;
37136559Sbostic 			break;
37236559Sbostic 
37336559Sbostic 		case '|':
37436559Sbostic 			(void) term(0);
37536559Sbostic 			expv |= lhs;
37636559Sbostic 			break;
37736559Sbostic 
37836559Sbostic 		default:
37936559Sbostic 			unreadc();
38036559Sbostic 			return (1);
38136559Sbostic 		}
38236559Sbostic 	}
38336559Sbostic }
38436559Sbostic 
38536559Sbostic int
oexpr()38636559Sbostic oexpr()
38736559Sbostic {
38836559Sbostic 
38936559Sbostic 	return (iexpr(1));
39036559Sbostic }
39136559Sbostic 
39236559Sbostic expr_t
rexpr()39336559Sbostic rexpr()
39436559Sbostic {
39536559Sbostic 
39636559Sbostic 	(void) iexpr(0);
39736559Sbostic 	return (expv);
39836559Sbostic }
39936559Sbostic 
40036559Sbostic /*
40136559Sbostic  * Evaluate a name, or a name '.' localname.
40236559Sbostic  */
40336559Sbostic static
ev_name()40436559Sbostic ev_name()
40536559Sbostic {
40636559Sbostic 	struct nlist *symp;
40736559Sbostic 	char symbuf[SYMLEN];
40836559Sbostic 
40936559Sbostic 	/* name [ . localname ] */
41036559Sbostic 	getsym(symbuf, sizeof(symbuf));
41136559Sbostic 	if (lastc == '.')	/* name . local */
41236559Sbostic 		find_frame(symbuf);
41336559Sbostic 	else if ((symp = lookup(symbuf)) != NULL)
41436559Sbostic 		expv = (xxxsym = symp)->n_value;
41536559Sbostic 	else
41636559Sbostic 		error(BADSYM);
41736559Sbostic 	unreadc();
41836559Sbostic }
41936559Sbostic 
42036559Sbostic /*
42136559Sbostic  * Backtrack through the call stack to find the symbol in symbuf.
42236559Sbostic  * Save the result, and if there is another name, look for it within
42336559Sbostic  * that frame.  Otherwise the value of the expression is the address
42436559Sbostic  * of the found frame.
42536559Sbostic  */
42636559Sbostic static
find_frame(symbuf)42736559Sbostic find_frame(symbuf)
42836559Sbostic 	char *symbuf;
42936559Sbostic {
43036559Sbostic 	struct activation a;
43136559Sbostic 	addr_t dummy;		/* for findsym() to scribble on */
43236559Sbostic 
43336559Sbostic 	if (pid == 0)
43436559Sbostic 		error(NOPCS);
43536559Sbostic 	for (a_init(&a); a.a_valid; a_back(&a)) {
43636559Sbostic 		checkerr();
43736559Sbostic 		if ((xxxsym = findsym(a.a_pc, SP_INSTR, &dummy)) == NULL)
43836559Sbostic 			break;
43936559Sbostic 		if (eqsym(xxxsym->n_un.n_name, symbuf, '_')) {
44036559Sbostic 			curframe = a;
44136559Sbostic 			if (symchar(SYMCH_READ))
44236559Sbostic 				ev_local();
44336559Sbostic 			else
44436559Sbostic 				expv = a.a_fp;
44536559Sbostic 			return;
44636559Sbostic 		}
44736559Sbostic 	}
44836559Sbostic 	error(NOCFN);
44936559Sbostic 	/* NOTREACHED */
45036559Sbostic }
45136559Sbostic 
45236559Sbostic /*
45336559Sbostic  * Linear search (ugh) for a symbol in the current stack frame.
45436559Sbostic  */
45536559Sbostic static
ev_local()45636559Sbostic ev_local()
45736559Sbostic {
45836559Sbostic 	register struct nlist *sp;
45936559Sbostic 	register char *a, *b;
46036559Sbostic 	char symbuf[SYMLEN];
46136559Sbostic 
46236559Sbostic 	if (pid == 0)
46336559Sbostic 		error(NOPCS);
46436559Sbostic 	if (!curframe.a_valid || (sp = xxxsym) == NULL)
46536559Sbostic 		error(NOCFN);
46636559Sbostic 	getsym(symbuf, SYMLEN);
46736559Sbostic 	while ((sp = nextlocal(sp)) != NULL) {
46836559Sbostic 		/*
46936559Sbostic 		 * Local and parameter symbols (as generated by .stabs)
47036559Sbostic 		 * end with ':', not '\0'; here we allow both.
47136559Sbostic 		 */
47236559Sbostic 		if (*(a = sp->n_un.n_name) != *(b = symbuf))
47336559Sbostic 			continue;
47436559Sbostic 		while (*a == *b++)
47536559Sbostic 			if (*a++ == 0 || *a == ':') {
47636559Sbostic 				expv = eval_localsym(sp, &curframe);
47736559Sbostic 				xxxsym = sp;	/* ??? */
47836559Sbostic 				return;
47936559Sbostic 			}
48036559Sbostic 	}
48136559Sbostic 	error(BADLOC);
48236559Sbostic }
48336559Sbostic 
48436559Sbostic #ifndef inkdot
48536559Sbostic /*
48636559Sbostic  * Function version of inkdot().  Compute the new dot, and check for
48736559Sbostic  * address wrap-around.
48836559Sbostic  */
48936559Sbostic addr_t
inkdot(incr)49036559Sbostic inkdot(incr)
49136559Sbostic 	int incr;
49236559Sbostic {
49336559Sbostic 	addr_t newdot = dot + incr;
49436559Sbostic 
49536559Sbostic 	if (ADDRESS_WRAP(dot, newdot))
49636559Sbostic 		error(ADWRAP);
49736559Sbostic 	return (newdot);
49836559Sbostic }
49936559Sbostic #endif
500