xref: /plan9/sys/src/cmd/db/expr.c (revision 4de34a7edde43207e841ec91ecd12e6cf5f5ebe7)
1 /*
2  *
3  *	debugger
4  *
5  */
6 
7 #include "defs.h"
8 #include "fns.h"
9 
10 static long	round(long, long);
11 
12 extern	ADDR	ditto;
13 uvlong	expv;
14 
15 static WORD
ascval(void)16 ascval(void)
17 {
18 	Rune r;
19 
20 	if (readchar() == 0)
21 		return (0);
22 	r = lastc;
23 	while(quotchar())	/*discard chars to ending quote */
24 		;
25 	return((WORD) r);
26 }
27 
28 /*
29  * read a floating point number
30  * the result must fit in a WORD
31  */
32 
33 static WORD
fpin(char * buf)34 fpin(char *buf)
35 {
36 	union {
37 		WORD w;
38 		float f;
39 	} x;
40 
41 	x.f = atof(buf);
42 	return (x.w);
43 }
44 
45 WORD
defval(WORD w)46 defval(WORD w)
47 {
48 	if (expr(0))
49 		return (expv);
50 	else
51 		return (w);
52 }
53 
expr(int a)54 expr(int a)
55 {	/* term | term dyadic expr |  */
56 	int	rc;
57 	WORD	lhs;
58 
59 	rdc();
60 	reread();
61 	rc=term(a);
62 	while (rc) {
63 		lhs = expv;
64 		switch ((int)readchar()) {
65 
66 		case '+':
67 			term(a|1);
68 			expv += lhs;
69 			break;
70 
71 		case '-':
72 			term(a|1);
73 			expv = lhs - expv;
74 			break;
75 
76 		case '#':
77 			term(a|1);
78 			expv = round(lhs,expv);
79 			break;
80 
81 		case '*':
82 			term(a|1);
83 			expv *= lhs;
84 			break;
85 
86 		case '%':
87 			term(a|1);
88 			if(expv != 0)
89 				expv = lhs/expv;
90 			else{
91 				if(lhs)
92 					expv = 1;
93 				else
94 					expv = 0;
95 			}
96 			break;
97 
98 		case '&':
99 			term(a|1);
100 			expv &= lhs;
101 			break;
102 
103 		case '|':
104 			term(a|1);
105 			expv |= lhs;
106 			break;
107 
108 		case ')':
109 			if ((a&2)==0)
110 				error("unexpected `)'");
111 
112 		default:
113 			reread();
114 			return(rc);
115 		}
116 	}
117 	return(rc);
118 }
119 
term(int a)120 term(int a)
121 {	/* item | monadic item | (expr) | */
122 	ADDR e;
123 
124 	switch ((int)readchar()) {
125 
126 	case '*':
127 		term(a|1);
128 		if (geta(cormap, expv, &e) < 0)
129 			error("%r");
130 		expv = e;
131 		return(1);
132 
133 	case '@':
134 		term(a|1);
135 		if (geta(symmap, expv, &e) < 0)
136 			error("%r");
137 		expv = e;
138 		return(1);
139 
140 	case '-':
141 		term(a|1);
142 		expv = -expv;
143 		return(1);
144 
145 	case '~':
146 		term(a|1);
147 		expv = ~expv;
148 		return(1);
149 
150 	case '(':
151 		expr(2);
152 		if (readchar()!=')')
153 			error("syntax error: `)' expected");
154 		return(1);
155 
156 	default:
157 		reread();
158 		return(item(a));
159 	}
160 }
161 
item(int a)162 item(int a)
163 {	/* name [ . local ] | number | . | ^  | <register | 'x | | */
164 	char	*base;
165 	char	savc;
166 	uvlong e;
167 	Symbol s;
168 	char gsym[MAXSYM], lsym[MAXSYM];
169 
170 	readchar();
171 	if (isfileref()) {
172 		readfname(gsym);
173 		rdc();			/* skip white space */
174 		if (lastc == ':') {	/* it better be */
175 			rdc();		/* skip white space */
176 			if (!getnum(readchar))
177 				error("bad number");
178 			if (expv == 0)
179 				expv = 1;	/* file begins at line 1 */
180 			expv = file2pc(gsym, expv);
181 			if (expv == -1)
182 				error("%r");
183 			return 1;
184 		}
185 		error("bad file location");
186 	} else if (symchar(0)) {
187 		readsym(gsym);
188 		if (lastc=='.') {
189 			readchar();	/* ugh */
190 			if (lastc == '.') {
191 				lsym[0] = '.';
192 				readchar();
193 				readsym(lsym+1);
194 			} else if (symchar(0)) {
195 				readsym(lsym);
196 			} else
197 				lsym[0] = 0;
198 			if (localaddr(cormap, gsym, lsym, &e, rget) < 0)
199 				error("%r");
200 			expv = e;
201 		}
202 		else {
203 			if (lookup(0, gsym, &s) == 0)
204 				error("symbol not found");
205 			expv = s.value;
206 		}
207 		reread();
208 	} else if (getnum(readchar)) {
209 		;
210 	} else if (lastc=='.') {
211 		readchar();
212 		if (!symchar(0) && lastc != '.') {
213 			expv = dot;
214 		} else {
215 			if (findsym(rget(cormap, mach->pc), CTEXT, &s) == 0)
216 				error("no current function");
217 			if (lastc == '.') {
218 				lsym[0] = '.';
219 				readchar();
220 				readsym(lsym+1);
221 			} else
222 				readsym(lsym);
223 			if (localaddr(cormap, s.name, lsym, &e, rget) < 0)
224 				error("%r");
225 			expv = e;
226 		}
227 		reread();
228 	} else if (lastc=='"') {
229 		expv=ditto;
230 	} else if (lastc=='+') {
231 		expv=inkdot(dotinc);
232 	} else if (lastc=='^') {
233 		expv=inkdot(-dotinc);
234 	} else if (lastc=='<') {
235 		savc=rdc();
236 		base = regname(savc);
237 		expv = rget(cormap, base);
238 	}
239 	else if (lastc=='\'')
240 		expv = ascval();
241 	else if (a)
242 		error("address expected");
243 	else {
244 		reread();
245 		return(0);
246 	}
247 	return(1);
248 }
249 
250 #define	MAXBASE	16
251 
252 /* service routines for expression reading */
getnum(int (* rdf)(void))253 getnum(int (*rdf)(void))
254 {
255 	char *cp;
256 	int base, d;
257 	BOOL fpnum;
258 	char num[MAXLIN];
259 
260 	base = 0;
261 	fpnum = FALSE;
262 	if (lastc == '#') {
263 		base = 16;
264 		(*rdf)();
265 	}
266 	if (convdig(lastc) >= MAXBASE)
267 		return (0);
268 	if (lastc == '0')
269 		switch ((*rdf)()) {
270 		case 'x':
271 		case 'X':
272 			base = 16;
273 			(*rdf)();
274 			break;
275 
276 		case 't':
277 		case 'T':
278 			base = 10;
279 			(*rdf)();
280 			break;
281 
282 		case 'o':
283 		case 'O':
284 			base = 8;
285 			(*rdf)();
286 			break;
287 		default:
288 			if (base == 0)
289 				base = 8;
290 			break;
291 		}
292 	if (base == 0)
293 		base = 10;
294 	expv = 0;
295 	for (cp = num, *cp = lastc; ;(*rdf)()) {
296 		if ((d = convdig(lastc)) < base) {
297 			expv *= base;
298 			expv += d;
299 			*cp++ = lastc;
300 		}
301 		else if (lastc == '.') {
302 			fpnum = TRUE;
303 			*cp++ = lastc;
304 		} else {
305 			reread();
306 			break;
307 		}
308 	}
309 	if (fpnum)
310 		expv = fpin(num);
311 	return (1);
312 }
313 
314 void
readsym(char * isymbol)315 readsym(char *isymbol)
316 {
317 	char	*p;
318 	Rune r;
319 
320 	p = isymbol;
321 	do {
322 		if (p < &isymbol[MAXSYM-UTFmax-1]){
323 			r = lastc;
324 			p += runetochar(p, &r);
325 		}
326 		readchar();
327 	} while (symchar(1));
328 	*p = 0;
329 }
330 
331 void
readfname(char * filename)332 readfname(char *filename)
333 {
334 	char	*p;
335 	Rune	c;
336 
337 	/* snarf chars until un-escaped char in terminal char set */
338 	p = filename;
339 	do {
340 		if ((c = lastc) != '\\' && p < &filename[MAXSYM-UTFmax-1])
341 			p += runetochar(p, &c);
342 		readchar();
343 	} while (c == '\\' || strchr(CMD_VERBS, lastc) == 0);
344 	*p = 0;
345 	reread();
346 }
347 
convdig(int c)348 convdig(int c)
349 {
350 	if (isdigit(c))
351 		return(c-'0');
352 	else if (!isxdigit(c))
353 		return(MAXBASE);
354 	else if (isupper(c))
355 		return(c-'A'+10);
356 	else
357 		return(c-'a'+10);
358 }
359 
symchar(int dig)360 symchar(int dig)
361 {
362 	if (lastc=='\\') {
363 		readchar();
364 		return(TRUE);
365 	}
366 	return(isalpha(lastc) || lastc>0x80 || lastc=='_' || dig && isdigit(lastc));
367 }
368 
369 static long
round(long a,long b)370 round(long a, long b)
371 {
372 	long w;
373 
374 	w = (a/b)*b;
375 	if (a!=w)
376 		w += b;
377 	return(w);
378 }
379