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