xref: /plan9/sys/src/cmd/db/expr.c (revision 4de34a7edde43207e841ec91ecd12e6cf5f5ebe7)
13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier  *
33e12c5d1SDavid du Colombier  *	debugger
43e12c5d1SDavid du Colombier  *
53e12c5d1SDavid du Colombier  */
63e12c5d1SDavid du Colombier 
73e12c5d1SDavid du Colombier #include "defs.h"
83e12c5d1SDavid du Colombier #include "fns.h"
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier static long	round(long, long);
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier extern	ADDR	ditto;
13*4de34a7eSDavid du Colombier uvlong	expv;
14219b2ee8SDavid du Colombier 
15219b2ee8SDavid du Colombier static WORD
ascval(void)16219b2ee8SDavid du Colombier ascval(void)
17219b2ee8SDavid du Colombier {
18219b2ee8SDavid du Colombier 	Rune r;
19219b2ee8SDavid du Colombier 
20219b2ee8SDavid du Colombier 	if (readchar() == 0)
21219b2ee8SDavid du Colombier 		return (0);
229a747e4fSDavid du Colombier 	r = lastc;
23219b2ee8SDavid du Colombier 	while(quotchar())	/*discard chars to ending quote */
24219b2ee8SDavid du Colombier 		;
25219b2ee8SDavid du Colombier 	return((WORD) r);
26219b2ee8SDavid du Colombier }
27219b2ee8SDavid du Colombier 
28219b2ee8SDavid du Colombier /*
29219b2ee8SDavid du Colombier  * read a floating point number
30219b2ee8SDavid du Colombier  * the result must fit in a WORD
31219b2ee8SDavid du Colombier  */
32219b2ee8SDavid du Colombier 
33219b2ee8SDavid du Colombier static WORD
fpin(char * buf)34219b2ee8SDavid du Colombier fpin(char *buf)
35219b2ee8SDavid du Colombier {
36219b2ee8SDavid du Colombier 	union {
37219b2ee8SDavid du Colombier 		WORD w;
38219b2ee8SDavid du Colombier 		float f;
39219b2ee8SDavid du Colombier 	} x;
40219b2ee8SDavid du Colombier 
41219b2ee8SDavid du Colombier 	x.f = atof(buf);
42219b2ee8SDavid du Colombier 	return (x.w);
43219b2ee8SDavid du Colombier }
443e12c5d1SDavid du Colombier 
453e12c5d1SDavid du Colombier WORD
defval(WORD w)463e12c5d1SDavid du Colombier defval(WORD w)
473e12c5d1SDavid du Colombier {
483e12c5d1SDavid du Colombier 	if (expr(0))
493e12c5d1SDavid du Colombier 		return (expv);
503e12c5d1SDavid du Colombier 	else
513e12c5d1SDavid du Colombier 		return (w);
523e12c5d1SDavid du Colombier }
533e12c5d1SDavid du Colombier 
expr(int a)543e12c5d1SDavid du Colombier expr(int a)
553e12c5d1SDavid du Colombier {	/* term | term dyadic expr |  */
563e12c5d1SDavid du Colombier 	int	rc;
573e12c5d1SDavid du Colombier 	WORD	lhs;
583e12c5d1SDavid du Colombier 
593e12c5d1SDavid du Colombier 	rdc();
603e12c5d1SDavid du Colombier 	reread();
613e12c5d1SDavid du Colombier 	rc=term(a);
623e12c5d1SDavid du Colombier 	while (rc) {
633e12c5d1SDavid du Colombier 		lhs = expv;
643e12c5d1SDavid du Colombier 		switch ((int)readchar()) {
653e12c5d1SDavid du Colombier 
663e12c5d1SDavid du Colombier 		case '+':
673e12c5d1SDavid du Colombier 			term(a|1);
683e12c5d1SDavid du Colombier 			expv += lhs;
693e12c5d1SDavid du Colombier 			break;
703e12c5d1SDavid du Colombier 
713e12c5d1SDavid du Colombier 		case '-':
723e12c5d1SDavid du Colombier 			term(a|1);
733e12c5d1SDavid du Colombier 			expv = lhs - expv;
743e12c5d1SDavid du Colombier 			break;
753e12c5d1SDavid du Colombier 
763e12c5d1SDavid du Colombier 		case '#':
773e12c5d1SDavid du Colombier 			term(a|1);
783e12c5d1SDavid du Colombier 			expv = round(lhs,expv);
793e12c5d1SDavid du Colombier 			break;
803e12c5d1SDavid du Colombier 
813e12c5d1SDavid du Colombier 		case '*':
823e12c5d1SDavid du Colombier 			term(a|1);
833e12c5d1SDavid du Colombier 			expv *= lhs;
843e12c5d1SDavid du Colombier 			break;
853e12c5d1SDavid du Colombier 
863e12c5d1SDavid du Colombier 		case '%':
873e12c5d1SDavid du Colombier 			term(a|1);
883e12c5d1SDavid du Colombier 			if(expv != 0)
893e12c5d1SDavid du Colombier 				expv = lhs/expv;
903e12c5d1SDavid du Colombier 			else{
913e12c5d1SDavid du Colombier 				if(lhs)
923e12c5d1SDavid du Colombier 					expv = 1;
933e12c5d1SDavid du Colombier 				else
943e12c5d1SDavid du Colombier 					expv = 0;
953e12c5d1SDavid du Colombier 			}
963e12c5d1SDavid du Colombier 			break;
973e12c5d1SDavid du Colombier 
983e12c5d1SDavid du Colombier 		case '&':
993e12c5d1SDavid du Colombier 			term(a|1);
1003e12c5d1SDavid du Colombier 			expv &= lhs;
1013e12c5d1SDavid du Colombier 			break;
1023e12c5d1SDavid du Colombier 
1033e12c5d1SDavid du Colombier 		case '|':
1043e12c5d1SDavid du Colombier 			term(a|1);
1053e12c5d1SDavid du Colombier 			expv |= lhs;
1063e12c5d1SDavid du Colombier 			break;
1073e12c5d1SDavid du Colombier 
1083e12c5d1SDavid du Colombier 		case ')':
1093e12c5d1SDavid du Colombier 			if ((a&2)==0)
1103e12c5d1SDavid du Colombier 				error("unexpected `)'");
1113e12c5d1SDavid du Colombier 
1123e12c5d1SDavid du Colombier 		default:
1133e12c5d1SDavid du Colombier 			reread();
1143e12c5d1SDavid du Colombier 			return(rc);
1153e12c5d1SDavid du Colombier 		}
1163e12c5d1SDavid du Colombier 	}
1173e12c5d1SDavid du Colombier 	return(rc);
1183e12c5d1SDavid du Colombier }
1193e12c5d1SDavid du Colombier 
term(int a)1203e12c5d1SDavid du Colombier term(int a)
1213e12c5d1SDavid du Colombier {	/* item | monadic item | (expr) | */
122*4de34a7eSDavid du Colombier 	ADDR e;
1233e12c5d1SDavid du Colombier 
1243e12c5d1SDavid du Colombier 	switch ((int)readchar()) {
1253e12c5d1SDavid du Colombier 
1263e12c5d1SDavid du Colombier 	case '*':
1273e12c5d1SDavid du Colombier 		term(a|1);
128*4de34a7eSDavid du Colombier 		if (geta(cormap, expv, &e) < 0)
129219b2ee8SDavid du Colombier 			error("%r");
1307dd7cddfSDavid du Colombier 		expv = e;
1313e12c5d1SDavid du Colombier 		return(1);
1323e12c5d1SDavid du Colombier 
1333e12c5d1SDavid du Colombier 	case '@':
1343e12c5d1SDavid du Colombier 		term(a|1);
135*4de34a7eSDavid du Colombier 		if (geta(symmap, expv, &e) < 0)
136219b2ee8SDavid du Colombier 			error("%r");
1377dd7cddfSDavid du Colombier 		expv = e;
1383e12c5d1SDavid du Colombier 		return(1);
1393e12c5d1SDavid du Colombier 
1403e12c5d1SDavid du Colombier 	case '-':
1413e12c5d1SDavid du Colombier 		term(a|1);
1423e12c5d1SDavid du Colombier 		expv = -expv;
1433e12c5d1SDavid du Colombier 		return(1);
1443e12c5d1SDavid du Colombier 
1453e12c5d1SDavid du Colombier 	case '~':
1463e12c5d1SDavid du Colombier 		term(a|1);
1473e12c5d1SDavid du Colombier 		expv = ~expv;
1483e12c5d1SDavid du Colombier 		return(1);
1493e12c5d1SDavid du Colombier 
1503e12c5d1SDavid du Colombier 	case '(':
1513e12c5d1SDavid du Colombier 		expr(2);
1523e12c5d1SDavid du Colombier 		if (readchar()!=')')
1533e12c5d1SDavid du Colombier 			error("syntax error: `)' expected");
1543e12c5d1SDavid du Colombier 		return(1);
1553e12c5d1SDavid du Colombier 
1563e12c5d1SDavid du Colombier 	default:
1573e12c5d1SDavid du Colombier 		reread();
1583e12c5d1SDavid du Colombier 		return(item(a));
1593e12c5d1SDavid du Colombier 	}
1603e12c5d1SDavid du Colombier }
1613e12c5d1SDavid du Colombier 
item(int a)1623e12c5d1SDavid du Colombier item(int a)
163219b2ee8SDavid du Colombier {	/* name [ . local ] | number | . | ^  | <register | 'x | | */
164219b2ee8SDavid du Colombier 	char	*base;
1653e12c5d1SDavid du Colombier 	char	savc;
166*4de34a7eSDavid du Colombier 	uvlong e;
1673e12c5d1SDavid du Colombier 	Symbol s;
1683e12c5d1SDavid du Colombier 	char gsym[MAXSYM], lsym[MAXSYM];
1693e12c5d1SDavid du Colombier 
1703e12c5d1SDavid du Colombier 	readchar();
1713e12c5d1SDavid du Colombier 	if (isfileref()) {
1723e12c5d1SDavid du Colombier 		readfname(gsym);
1733e12c5d1SDavid du Colombier 		rdc();			/* skip white space */
1743e12c5d1SDavid du Colombier 		if (lastc == ':') {	/* it better be */
1753e12c5d1SDavid du Colombier 			rdc();		/* skip white space */
1763e12c5d1SDavid du Colombier 			if (!getnum(readchar))
1773e12c5d1SDavid du Colombier 				error("bad number");
1783e12c5d1SDavid du Colombier 			if (expv == 0)
1793e12c5d1SDavid du Colombier 				expv = 1;	/* file begins at line 1 */
1803e12c5d1SDavid du Colombier 			expv = file2pc(gsym, expv);
1813e12c5d1SDavid du Colombier 			if (expv == -1)
182219b2ee8SDavid du Colombier 				error("%r");
1833e12c5d1SDavid du Colombier 			return 1;
1843e12c5d1SDavid du Colombier 		}
1853e12c5d1SDavid du Colombier 		error("bad file location");
1863e12c5d1SDavid du Colombier 	} else if (symchar(0)) {
1873e12c5d1SDavid du Colombier 		readsym(gsym);
1883e12c5d1SDavid du Colombier 		if (lastc=='.') {
1893e12c5d1SDavid du Colombier 			readchar();	/* ugh */
190219b2ee8SDavid du Colombier 			if (lastc == '.') {
191219b2ee8SDavid du Colombier 				lsym[0] = '.';
192219b2ee8SDavid du Colombier 				readchar();
193219b2ee8SDavid du Colombier 				readsym(lsym+1);
194219b2ee8SDavid du Colombier 			} else if (symchar(0)) {
1953e12c5d1SDavid du Colombier 				readsym(lsym);
196219b2ee8SDavid du Colombier 			} else
197219b2ee8SDavid du Colombier 				lsym[0] = 0;
1987dd7cddfSDavid du Colombier 			if (localaddr(cormap, gsym, lsym, &e, rget) < 0)
199219b2ee8SDavid du Colombier 				error("%r");
2007dd7cddfSDavid du Colombier 			expv = e;
2013e12c5d1SDavid du Colombier 		}
2023e12c5d1SDavid du Colombier 		else {
2033e12c5d1SDavid du Colombier 			if (lookup(0, gsym, &s) == 0)
2043e12c5d1SDavid du Colombier 				error("symbol not found");
2053e12c5d1SDavid du Colombier 			expv = s.value;
2063e12c5d1SDavid du Colombier 		}
2073e12c5d1SDavid du Colombier 		reread();
2083e12c5d1SDavid du Colombier 	} else if (getnum(readchar)) {
2093e12c5d1SDavid du Colombier 		;
2103e12c5d1SDavid du Colombier 	} else if (lastc=='.') {
2113e12c5d1SDavid du Colombier 		readchar();
212219b2ee8SDavid du Colombier 		if (!symchar(0) && lastc != '.') {
2133e12c5d1SDavid du Colombier 			expv = dot;
2143e12c5d1SDavid du Colombier 		} else {
215219b2ee8SDavid du Colombier 			if (findsym(rget(cormap, mach->pc), CTEXT, &s) == 0)
216219b2ee8SDavid du Colombier 				error("no current function");
217219b2ee8SDavid du Colombier 			if (lastc == '.') {
218219b2ee8SDavid du Colombier 				lsym[0] = '.';
219219b2ee8SDavid du Colombier 				readchar();
220219b2ee8SDavid du Colombier 				readsym(lsym+1);
221219b2ee8SDavid du Colombier 			} else
2223e12c5d1SDavid du Colombier 				readsym(lsym);
2237dd7cddfSDavid du Colombier 			if (localaddr(cormap, s.name, lsym, &e, rget) < 0)
224219b2ee8SDavid du Colombier 				error("%r");
2257dd7cddfSDavid du Colombier 			expv = e;
2263e12c5d1SDavid du Colombier 		}
2273e12c5d1SDavid du Colombier 		reread();
2283e12c5d1SDavid du Colombier 	} else if (lastc=='"') {
2293e12c5d1SDavid du Colombier 		expv=ditto;
2303e12c5d1SDavid du Colombier 	} else if (lastc=='+') {
2313e12c5d1SDavid du Colombier 		expv=inkdot(dotinc);
2323e12c5d1SDavid du Colombier 	} else if (lastc=='^') {
2333e12c5d1SDavid du Colombier 		expv=inkdot(-dotinc);
2343e12c5d1SDavid du Colombier 	} else if (lastc=='<') {
2353e12c5d1SDavid du Colombier 		savc=rdc();
236219b2ee8SDavid du Colombier 		base = regname(savc);
237219b2ee8SDavid du Colombier 		expv = rget(cormap, base);
2383e12c5d1SDavid du Colombier 	}
2393e12c5d1SDavid du Colombier 	else if (lastc=='\'')
2403e12c5d1SDavid du Colombier 		expv = ascval();
2413e12c5d1SDavid du Colombier 	else if (a)
2423e12c5d1SDavid du Colombier 		error("address expected");
2433e12c5d1SDavid du Colombier 	else {
2443e12c5d1SDavid du Colombier 		reread();
2453e12c5d1SDavid du Colombier 		return(0);
2463e12c5d1SDavid du Colombier 	}
2473e12c5d1SDavid du Colombier 	return(1);
2483e12c5d1SDavid du Colombier }
2493e12c5d1SDavid du Colombier 
2503e12c5d1SDavid du Colombier #define	MAXBASE	16
2513e12c5d1SDavid du Colombier 
2523e12c5d1SDavid du Colombier /* service routines for expression reading */
getnum(int (* rdf)(void))2533e12c5d1SDavid du Colombier getnum(int (*rdf)(void))
2543e12c5d1SDavid du Colombier {
2553e12c5d1SDavid du Colombier 	char *cp;
2563e12c5d1SDavid du Colombier 	int base, d;
2573e12c5d1SDavid du Colombier 	BOOL fpnum;
2583e12c5d1SDavid du Colombier 	char num[MAXLIN];
2593e12c5d1SDavid du Colombier 
2603e12c5d1SDavid du Colombier 	base = 0;
2613e12c5d1SDavid du Colombier 	fpnum = FALSE;
2623e12c5d1SDavid du Colombier 	if (lastc == '#') {
2633e12c5d1SDavid du Colombier 		base = 16;
2643e12c5d1SDavid du Colombier 		(*rdf)();
2653e12c5d1SDavid du Colombier 	}
2663e12c5d1SDavid du Colombier 	if (convdig(lastc) >= MAXBASE)
2673e12c5d1SDavid du Colombier 		return (0);
2683e12c5d1SDavid du Colombier 	if (lastc == '0')
2693e12c5d1SDavid du Colombier 		switch ((*rdf)()) {
2703e12c5d1SDavid du Colombier 		case 'x':
2713e12c5d1SDavid du Colombier 		case 'X':
2723e12c5d1SDavid du Colombier 			base = 16;
2733e12c5d1SDavid du Colombier 			(*rdf)();
2743e12c5d1SDavid du Colombier 			break;
2753e12c5d1SDavid du Colombier 
2763e12c5d1SDavid du Colombier 		case 't':
2773e12c5d1SDavid du Colombier 		case 'T':
2783e12c5d1SDavid du Colombier 			base = 10;
2793e12c5d1SDavid du Colombier 			(*rdf)();
2803e12c5d1SDavid du Colombier 			break;
2813e12c5d1SDavid du Colombier 
2823e12c5d1SDavid du Colombier 		case 'o':
2833e12c5d1SDavid du Colombier 		case 'O':
2843e12c5d1SDavid du Colombier 			base = 8;
2853e12c5d1SDavid du Colombier 			(*rdf)();
2863e12c5d1SDavid du Colombier 			break;
2873e12c5d1SDavid du Colombier 		default:
2883e12c5d1SDavid du Colombier 			if (base == 0)
2893e12c5d1SDavid du Colombier 				base = 8;
2903e12c5d1SDavid du Colombier 			break;
2913e12c5d1SDavid du Colombier 		}
2923e12c5d1SDavid du Colombier 	if (base == 0)
2933e12c5d1SDavid du Colombier 		base = 10;
2943e12c5d1SDavid du Colombier 	expv = 0;
2953e12c5d1SDavid du Colombier 	for (cp = num, *cp = lastc; ;(*rdf)()) {
2963e12c5d1SDavid du Colombier 		if ((d = convdig(lastc)) < base) {
2973e12c5d1SDavid du Colombier 			expv *= base;
2983e12c5d1SDavid du Colombier 			expv += d;
2993e12c5d1SDavid du Colombier 			*cp++ = lastc;
3003e12c5d1SDavid du Colombier 		}
3013e12c5d1SDavid du Colombier 		else if (lastc == '.') {
3023e12c5d1SDavid du Colombier 			fpnum = TRUE;
3033e12c5d1SDavid du Colombier 			*cp++ = lastc;
3043e12c5d1SDavid du Colombier 		} else {
3053e12c5d1SDavid du Colombier 			reread();
3063e12c5d1SDavid du Colombier 			break;
3073e12c5d1SDavid du Colombier 		}
3083e12c5d1SDavid du Colombier 	}
3093e12c5d1SDavid du Colombier 	if (fpnum)
3103e12c5d1SDavid du Colombier 		expv = fpin(num);
3113e12c5d1SDavid du Colombier 	return (1);
3123e12c5d1SDavid du Colombier }
3133e12c5d1SDavid du Colombier 
3143e12c5d1SDavid du Colombier void
readsym(char * isymbol)3153e12c5d1SDavid du Colombier readsym(char *isymbol)
3163e12c5d1SDavid du Colombier {
3173e12c5d1SDavid du Colombier 	char	*p;
3189a747e4fSDavid du Colombier 	Rune r;
3193e12c5d1SDavid du Colombier 
3203e12c5d1SDavid du Colombier 	p = isymbol;
3213e12c5d1SDavid du Colombier 	do {
3229a747e4fSDavid du Colombier 		if (p < &isymbol[MAXSYM-UTFmax-1]){
3239a747e4fSDavid du Colombier 			r = lastc;
3249a747e4fSDavid du Colombier 			p += runetochar(p, &r);
3259a747e4fSDavid du Colombier 		}
3263e12c5d1SDavid du Colombier 		readchar();
3273e12c5d1SDavid du Colombier 	} while (symchar(1));
3283e12c5d1SDavid du Colombier 	*p = 0;
3293e12c5d1SDavid du Colombier }
3303e12c5d1SDavid du Colombier 
3313e12c5d1SDavid du Colombier void
readfname(char * filename)3323e12c5d1SDavid du Colombier readfname(char *filename)
3333e12c5d1SDavid du Colombier {
3343e12c5d1SDavid du Colombier 	char	*p;
3359a747e4fSDavid du Colombier 	Rune	c;
3363e12c5d1SDavid du Colombier 
3373e12c5d1SDavid du Colombier 	/* snarf chars until un-escaped char in terminal char set */
3383e12c5d1SDavid du Colombier 	p = filename;
3393e12c5d1SDavid du Colombier 	do {
3409a747e4fSDavid du Colombier 		if ((c = lastc) != '\\' && p < &filename[MAXSYM-UTFmax-1])
3419a747e4fSDavid du Colombier 			p += runetochar(p, &c);
3423e12c5d1SDavid du Colombier 		readchar();
3433e12c5d1SDavid du Colombier 	} while (c == '\\' || strchr(CMD_VERBS, lastc) == 0);
3443e12c5d1SDavid du Colombier 	*p = 0;
3453e12c5d1SDavid du Colombier 	reread();
3463e12c5d1SDavid du Colombier }
3473e12c5d1SDavid du Colombier 
convdig(int c)3483e12c5d1SDavid du Colombier convdig(int c)
3493e12c5d1SDavid du Colombier {
3503e12c5d1SDavid du Colombier 	if (isdigit(c))
3513e12c5d1SDavid du Colombier 		return(c-'0');
3523e12c5d1SDavid du Colombier 	else if (!isxdigit(c))
3533e12c5d1SDavid du Colombier 		return(MAXBASE);
3543e12c5d1SDavid du Colombier 	else if (isupper(c))
3553e12c5d1SDavid du Colombier 		return(c-'A'+10);
3563e12c5d1SDavid du Colombier 	else
3573e12c5d1SDavid du Colombier 		return(c-'a'+10);
3583e12c5d1SDavid du Colombier }
3593e12c5d1SDavid du Colombier 
symchar(int dig)3603e12c5d1SDavid du Colombier symchar(int dig)
3613e12c5d1SDavid du Colombier {
3623e12c5d1SDavid du Colombier 	if (lastc=='\\') {
3633e12c5d1SDavid du Colombier 		readchar();
3643e12c5d1SDavid du Colombier 		return(TRUE);
3653e12c5d1SDavid du Colombier 	}
3669a747e4fSDavid du Colombier 	return(isalpha(lastc) || lastc>0x80 || lastc=='_' || dig && isdigit(lastc));
3673e12c5d1SDavid du Colombier }
3683e12c5d1SDavid du Colombier 
3693e12c5d1SDavid du Colombier static long
round(long a,long b)3703e12c5d1SDavid du Colombier round(long a, long b)
3713e12c5d1SDavid du Colombier {
3723e12c5d1SDavid du Colombier 	long w;
3733e12c5d1SDavid du Colombier 
3743e12c5d1SDavid du Colombier 	w = (a/b)*b;
3753e12c5d1SDavid du Colombier 	if (a!=w)
3763e12c5d1SDavid du Colombier 		w += b;
3773e12c5d1SDavid du Colombier 	return(w);
3783e12c5d1SDavid du Colombier }
379