xref: /plan9-contrib/sys/src/cmd/db/expr.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
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 vlong	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 	WORD e;
133 
134 	switch ((int)readchar()) {
135 
136 	case '*':
137 		term(a|1);
138 		if (get4(cormap, (ADDR)expv, &e) < 0)
139 			error("%r");
140 		expv = e;
141 		return(1);
142 
143 	case '@':
144 		term(a|1);
145 		if (get4(symmap, (ADDR)expv, &e) < 0)
146 			error("%r");
147 		expv = e;
148 		return(1);
149 
150 	case '-':
151 		term(a|1);
152 		expv = -expv;
153 		return(1);
154 
155 	case '~':
156 		term(a|1);
157 		expv = ~expv;
158 		return(1);
159 
160 	case '(':
161 		expr(2);
162 		if (readchar()!=')')
163 			error("syntax error: `)' expected");
164 		return(1);
165 
166 	default:
167 		reread();
168 		return(item(a));
169 	}
170 }
171 
172 item(int a)
173 {	/* name [ . local ] | number | . | ^  | <register | 'x | | */
174 	char	*base;
175 	char	savc;
176 	WORD e;
177 	Symbol s;
178 	char gsym[MAXSYM], lsym[MAXSYM];
179 
180 	readchar();
181 	if (isfileref()) {
182 		readfname(gsym);
183 		rdc();			/* skip white space */
184 		if (lastc == ':') {	/* it better be */
185 			rdc();		/* skip white space */
186 			if (!getnum(readchar))
187 				error("bad number");
188 			if (expv == 0)
189 				expv = 1;	/* file begins at line 1 */
190 			expv = file2pc(gsym, expv);
191 			if (expv == -1)
192 				error("%r");
193 			return 1;
194 		}
195 		error("bad file location");
196 	} else if (symchar(0)) {
197 		readsym(gsym);
198 		if (lastc=='.') {
199 			readchar();	/* ugh */
200 			if (lastc == '.') {
201 				lsym[0] = '.';
202 				readchar();
203 				readsym(lsym+1);
204 			} else if (symchar(0)) {
205 				readsym(lsym);
206 			} else
207 				lsym[0] = 0;
208 			if (localaddr(cormap, gsym, lsym, &e, rget) < 0)
209 				error("%r");
210 			expv = e;
211 		}
212 		else {
213 			if (lookup(0, gsym, &s) == 0)
214 				error("symbol not found");
215 			expv = s.value;
216 		}
217 		reread();
218 	} else if (getnum(readchar)) {
219 		;
220 	} else if (lastc=='.') {
221 		readchar();
222 		if (!symchar(0) && lastc != '.') {
223 			expv = dot;
224 		} else {
225 			if (findsym(rget(cormap, mach->pc), CTEXT, &s) == 0)
226 				error("no current function");
227 			if (lastc == '.') {
228 				lsym[0] = '.';
229 				readchar();
230 				readsym(lsym+1);
231 			} else
232 				readsym(lsym);
233 			if (localaddr(cormap, s.name, lsym, &e, rget) < 0)
234 				error("%r");
235 			expv = e;
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