xref: /csrg-svn/old/dbx/eval.c (revision 9662)
1*9662Slinton /* Copyright (c) 1982 Regents of the University of California */
2*9662Slinton 
3*9662Slinton static char sccsid[] = "@(#)@(#)eval.c 1.1 12/15/82";
4*9662Slinton 
5*9662Slinton /*
6*9662Slinton  * Tree evaluation.
7*9662Slinton  */
8*9662Slinton 
9*9662Slinton #include "defs.h"
10*9662Slinton #include "tree.h"
11*9662Slinton #include "operators.h"
12*9662Slinton #include "eval.h"
13*9662Slinton #include "events.h"
14*9662Slinton #include "symbols.h"
15*9662Slinton #include "scanner.h"
16*9662Slinton #include "source.h"
17*9662Slinton #include "object.h"
18*9662Slinton #include "mappings.h"
19*9662Slinton #include "process.h"
20*9662Slinton #include "machine.h"
21*9662Slinton #include <signal.h>
22*9662Slinton 
23*9662Slinton #ifndef public
24*9662Slinton 
25*9662Slinton #include "machine.h"
26*9662Slinton 
27*9662Slinton #define STACKSIZE 2000
28*9662Slinton 
29*9662Slinton typedef Char Stack;
30*9662Slinton 
31*9662Slinton #define push(type, value) { \
32*9662Slinton     ((type *) (sp += sizeof(type)))[-1] = (value); \
33*9662Slinton }
34*9662Slinton 
35*9662Slinton #define pop(type) ( \
36*9662Slinton     (*((type *) (sp -= sizeof(type)))) \
37*9662Slinton )
38*9662Slinton 
39*9662Slinton #define alignstack() { \
40*9662Slinton     sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
41*9662Slinton }
42*9662Slinton 
43*9662Slinton #endif
44*9662Slinton 
45*9662Slinton public Stack stack[STACKSIZE];
46*9662Slinton public Stack *sp = &stack[0];
47*9662Slinton 
48*9662Slinton #define chksp() \
49*9662Slinton { \
50*9662Slinton     if (sp < &stack[0]) { \
51*9662Slinton 	panic("stack underflow"); \
52*9662Slinton     } \
53*9662Slinton }
54*9662Slinton 
55*9662Slinton #define poparg(n, r, fr) { \
56*9662Slinton     eval(p->value.arg[n]); \
57*9662Slinton     if (isreal(p->op)) { \
58*9662Slinton 	fr = pop(double); \
59*9662Slinton     } else if (isint(p->op)) { \
60*9662Slinton 	r = popsmall(p->value.arg[n]->nodetype); \
61*9662Slinton     } \
62*9662Slinton }
63*9662Slinton 
64*9662Slinton #define Boolrep char	/* underlying representation type for booleans */
65*9662Slinton 
66*9662Slinton /*
67*9662Slinton  * Evaluate a parse tree leaving the value on the top of the stack.
68*9662Slinton  */
69*9662Slinton 
70*9662Slinton public eval(p)
71*9662Slinton register Node p;
72*9662Slinton {
73*9662Slinton     long r0, r1;
74*9662Slinton     double fr0, fr1;
75*9662Slinton     Address addr;
76*9662Slinton     long i, n;
77*9662Slinton     int len;
78*9662Slinton     Symbol s, f;
79*9662Slinton     Node n1, n2;
80*9662Slinton     Boolean b;
81*9662Slinton     File file;
82*9662Slinton 
83*9662Slinton     checkref(p);
84*9662Slinton     switch (degree(p->op)) {
85*9662Slinton 	case BINARY:
86*9662Slinton 	    poparg(1, r1, fr1);
87*9662Slinton 	    poparg(0, r0, fr0);
88*9662Slinton 	    break;
89*9662Slinton 
90*9662Slinton 	case UNARY:
91*9662Slinton 	    poparg(0, r0, fr0);
92*9662Slinton 	    break;
93*9662Slinton 
94*9662Slinton 	default:
95*9662Slinton 	    /* do nothing */;
96*9662Slinton     }
97*9662Slinton     switch (p->op) {
98*9662Slinton 	case O_SYM:
99*9662Slinton 	    s = p->value.sym;
100*9662Slinton 	    if (s == retaddrsym) {
101*9662Slinton 		push(long, return_addr());
102*9662Slinton 	    } else {
103*9662Slinton 		if (isvariable(s)) {
104*9662Slinton 		    if (s != program and not isactive(container(s))) {
105*9662Slinton 			error("\"%s\" is not active", symname(s));
106*9662Slinton 		    }
107*9662Slinton 		    push(long, address(s, nil));
108*9662Slinton 		} else if (isblock(s)) {
109*9662Slinton 		    push(Symbol, s);
110*9662Slinton 		} else {
111*9662Slinton 		    error("can't evaluate a %s", classname(s));
112*9662Slinton 		}
113*9662Slinton 	    }
114*9662Slinton 	    break;
115*9662Slinton 
116*9662Slinton 	case O_LCON:
117*9662Slinton 	    r0 = p->value.lcon;
118*9662Slinton 	    pushsmall(p->nodetype, r0);
119*9662Slinton 	    break;
120*9662Slinton 
121*9662Slinton 	case O_FCON:
122*9662Slinton 	    push(double, p->value.fcon);
123*9662Slinton 	    break;
124*9662Slinton 
125*9662Slinton 	case O_SCON:
126*9662Slinton 	    len = size(p->nodetype);
127*9662Slinton 	    mov(p->value.scon, sp, len);
128*9662Slinton 	    sp += len;
129*9662Slinton 	    break;
130*9662Slinton 
131*9662Slinton 	case O_INDEX:
132*9662Slinton 	    n = pop(long);
133*9662Slinton 	    i = evalindex(p->value.arg[0]->nodetype,
134*9662Slinton 		popsmall(p->value.arg[1]->nodetype));
135*9662Slinton 	    push(long, n + i*size(p->nodetype));
136*9662Slinton 	    break;
137*9662Slinton 
138*9662Slinton 	case O_DOT:
139*9662Slinton 	    s = p->value.arg[1]->value.sym;
140*9662Slinton 	    n = lval(p->value.arg[0]);
141*9662Slinton 	    push(long, n + (s->symvalue.field.offset div 8));
142*9662Slinton 	    break;
143*9662Slinton 
144*9662Slinton 	/*
145*9662Slinton 	 * Get the value of the expression addressed by the top of the stack.
146*9662Slinton 	 * Push the result back on the stack.
147*9662Slinton 	 */
148*9662Slinton 
149*9662Slinton 	case O_INDIR:
150*9662Slinton 	case O_RVAL:
151*9662Slinton 	    addr = pop(long);
152*9662Slinton 	    if (addr == 0) {
153*9662Slinton 		error("reference through nil pointer");
154*9662Slinton 	    }
155*9662Slinton 	    if (p->op == O_INDIR) {
156*9662Slinton 		len = sizeof(long);
157*9662Slinton 	    } else {
158*9662Slinton 		len = size(p->nodetype);
159*9662Slinton 	    }
160*9662Slinton 	    rpush(addr, len);
161*9662Slinton 	    break;
162*9662Slinton 
163*9662Slinton 	case O_COMMA:
164*9662Slinton 	    break;
165*9662Slinton 
166*9662Slinton 	case O_ITOF:
167*9662Slinton 	    push(double, (double) r0);
168*9662Slinton 	    break;
169*9662Slinton 
170*9662Slinton 	case O_ADD:
171*9662Slinton 	    push(long, r0+r1);
172*9662Slinton 	    break;
173*9662Slinton 
174*9662Slinton 	case O_ADDF:
175*9662Slinton 	    push(double, fr0+fr1);
176*9662Slinton 	    break;
177*9662Slinton 
178*9662Slinton 	case O_SUB:
179*9662Slinton 	    push(long, r0-r1);
180*9662Slinton 	    break;
181*9662Slinton 
182*9662Slinton 	case O_SUBF:
183*9662Slinton 	    push(double, fr0-fr1);
184*9662Slinton 	    break;
185*9662Slinton 
186*9662Slinton 	case O_NEG:
187*9662Slinton 	    push(long, -r0);
188*9662Slinton 	    break;
189*9662Slinton 
190*9662Slinton 	case O_NEGF:
191*9662Slinton 	    push(double, -fr0);
192*9662Slinton 	    break;
193*9662Slinton 
194*9662Slinton 	case O_MUL:
195*9662Slinton 	    push(long, r0*r1);
196*9662Slinton 	    break;
197*9662Slinton 
198*9662Slinton 	case O_MULF:
199*9662Slinton 	    push(double, fr0*fr1);
200*9662Slinton 	    break;
201*9662Slinton 
202*9662Slinton 	case O_DIVF:
203*9662Slinton 	    if (fr1 == 0) {
204*9662Slinton 		error("error: division by 0");
205*9662Slinton 	    }
206*9662Slinton 	    push(double, fr0 / fr1);
207*9662Slinton 	    break;
208*9662Slinton 
209*9662Slinton 	case O_DIV:
210*9662Slinton 	    if (r1 == 0) {
211*9662Slinton 		error("error: div by 0");
212*9662Slinton 	    }
213*9662Slinton 	    push(long, r0 div r1);
214*9662Slinton 	    break;
215*9662Slinton 
216*9662Slinton 	case O_MOD:
217*9662Slinton 	    if (r1 == 0) {
218*9662Slinton 		error("error: mod by 0");
219*9662Slinton 	    }
220*9662Slinton 	    push(long, r0 mod r1);
221*9662Slinton 	    break;
222*9662Slinton 
223*9662Slinton 	case O_LT:
224*9662Slinton 	    push(Boolrep, r0 < r1);
225*9662Slinton 	    break;
226*9662Slinton 
227*9662Slinton 	case O_LTF:
228*9662Slinton 	    push(Boolrep, fr0 < fr1);
229*9662Slinton 	    break;
230*9662Slinton 
231*9662Slinton 	case O_LE:
232*9662Slinton 	    push(Boolrep, r0 <= r1);
233*9662Slinton 	    break;
234*9662Slinton 
235*9662Slinton 	case O_LEF:
236*9662Slinton 	    push(Boolrep, fr0 <= fr1);
237*9662Slinton 	    break;
238*9662Slinton 
239*9662Slinton 	case O_GT:
240*9662Slinton 	    push(Boolrep, r0 > r1);
241*9662Slinton 	    break;
242*9662Slinton 
243*9662Slinton 	case O_GTF:
244*9662Slinton 	    push(Boolrep, fr0 > fr1);
245*9662Slinton 	    break;
246*9662Slinton 
247*9662Slinton 	case O_EQ:
248*9662Slinton 	    push(Boolrep, r0 == r1);
249*9662Slinton 	    break;
250*9662Slinton 
251*9662Slinton 	case O_EQF:
252*9662Slinton 	    push(Boolrep, fr0 == fr1);
253*9662Slinton 	    break;
254*9662Slinton 
255*9662Slinton 	case O_NE:
256*9662Slinton 	    push(Boolrep, r0 != r1);
257*9662Slinton 	    break;
258*9662Slinton 
259*9662Slinton 	case O_NEF:
260*9662Slinton 	    push(Boolrep, fr0 != fr1);
261*9662Slinton 	    break;
262*9662Slinton 
263*9662Slinton 	case O_AND:
264*9662Slinton 	    push(Boolrep, r0 and r1);
265*9662Slinton 	    break;
266*9662Slinton 
267*9662Slinton 	case O_OR:
268*9662Slinton 	    push(Boolrep, r0 or r1);
269*9662Slinton 	    break;
270*9662Slinton 
271*9662Slinton 	case O_ASSIGN:
272*9662Slinton 	    assign(p->value.arg[0], p->value.arg[1]);
273*9662Slinton 	    break;
274*9662Slinton 
275*9662Slinton 	case O_CHFILE:
276*9662Slinton 	    if (p->value.scon == nil) {
277*9662Slinton 		printf("%s\n", cursource);
278*9662Slinton 	    } else {
279*9662Slinton 		file = opensource(p->value.scon);
280*9662Slinton 		if (file == nil) {
281*9662Slinton 		    error("can't read \"%s\"", p->value.scon);
282*9662Slinton 		} else {
283*9662Slinton 		    fclose(file);
284*9662Slinton 		    setsource(p->value.scon);
285*9662Slinton 		}
286*9662Slinton 	    }
287*9662Slinton 	    break;
288*9662Slinton 
289*9662Slinton 	case O_CONT:
290*9662Slinton 	    cont();
291*9662Slinton 	    printnews();
292*9662Slinton 	    break;
293*9662Slinton 
294*9662Slinton 	case O_LIST:
295*9662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
296*9662Slinton 		f = p->value.arg[0]->value.sym;
297*9662Slinton 		addr = firstline(f);
298*9662Slinton 		if (addr == NOADDR) {
299*9662Slinton 		    error("no source lines for \"%s\"", symname(f));
300*9662Slinton 		}
301*9662Slinton 		setsource(srcfilename(addr));
302*9662Slinton 		r0 = srcline(addr) - 5;
303*9662Slinton 		r1 = r0 + 10;
304*9662Slinton 		if (r0 < 1) {
305*9662Slinton 		    r0 = 1;
306*9662Slinton 		}
307*9662Slinton 	    } else {
308*9662Slinton 		eval(p->value.arg[0]);
309*9662Slinton 		r0 = pop(long);
310*9662Slinton 		eval(p->value.arg[1]);
311*9662Slinton 		r1 = pop(long);
312*9662Slinton 	    }
313*9662Slinton 	    printlines((Lineno) r0, (Lineno) r1);
314*9662Slinton 	    break;
315*9662Slinton 
316*9662Slinton 	case O_FUNC:
317*9662Slinton 	    if (p->value.arg[0] == nil) {
318*9662Slinton 		printname(stdout, curfunc);
319*9662Slinton 		putchar('\n');
320*9662Slinton 	    } else {
321*9662Slinton 		curfunc = p->value.arg[0]->value.sym;
322*9662Slinton 		addr = codeloc(curfunc);
323*9662Slinton 		if (addr != NOADDR) {
324*9662Slinton 		    setsource(srcfilename(addr));
325*9662Slinton 		    cursrcline = srcline(addr) - 5;
326*9662Slinton 		    if (cursrcline < 1) {
327*9662Slinton 			cursrcline = 1;
328*9662Slinton 		    }
329*9662Slinton 		}
330*9662Slinton 	    }
331*9662Slinton 	    break;
332*9662Slinton 
333*9662Slinton 	case O_EXAMINE:
334*9662Slinton 	    eval(p->value.examine.beginaddr);
335*9662Slinton 	    r0 = pop(long);
336*9662Slinton 	    if (p->value.examine.endaddr == nil) {
337*9662Slinton 		n = p->value.examine.count;
338*9662Slinton 		if (streq(p->value.examine.mode, "i")) {
339*9662Slinton 		    printninst(n, (Address) r0);
340*9662Slinton 		} else {
341*9662Slinton 		    printndata(n, (Address) r0, p->value.examine.mode);
342*9662Slinton 		}
343*9662Slinton 	    } else {
344*9662Slinton 		eval(p->value.examine.endaddr);
345*9662Slinton 		r1 = pop(long);
346*9662Slinton 		if (streq(p->value.examine.mode, "i")) {
347*9662Slinton 		    printinst((Address)r0, (Address)r1);
348*9662Slinton 		} else {
349*9662Slinton 		    printdata((Address)r0, (Address)r1, p->value.examine.mode);
350*9662Slinton 		}
351*9662Slinton 	    }
352*9662Slinton 	    break;
353*9662Slinton 
354*9662Slinton 	case O_PRINT:
355*9662Slinton 	    for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) {
356*9662Slinton 		eval(n1->value.arg[0]);
357*9662Slinton 		printval(n1->value.arg[0]->nodetype);
358*9662Slinton 		putchar(' ');
359*9662Slinton 	    }
360*9662Slinton 	    putchar('\n');
361*9662Slinton 	    break;
362*9662Slinton 
363*9662Slinton 	case O_PSYM:
364*9662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
365*9662Slinton 		psym(p->value.arg[0]->value.sym);
366*9662Slinton 	    } else {
367*9662Slinton 		psym(p->value.arg[0]->nodetype);
368*9662Slinton 	    }
369*9662Slinton 	    break;
370*9662Slinton 
371*9662Slinton 	case O_QLINE:
372*9662Slinton 	    eval(p->value.arg[1]);
373*9662Slinton 	    break;
374*9662Slinton 
375*9662Slinton 	case O_STEP:
376*9662Slinton 	    b = inst_tracing;
377*9662Slinton 	    inst_tracing = (Boolean) (not p->value.step.source);
378*9662Slinton 	    if (p->value.step.skipcalls) {
379*9662Slinton 		next();
380*9662Slinton 	    } else {
381*9662Slinton 		stepc();
382*9662Slinton 	    }
383*9662Slinton 	    inst_tracing = b;
384*9662Slinton 	    printnews();
385*9662Slinton 	    break;
386*9662Slinton 
387*9662Slinton 	case O_WHATIS:
388*9662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
389*9662Slinton 		printdecl(p->value.arg[0]->value.sym);
390*9662Slinton 	    } else {
391*9662Slinton 		printdecl(p->value.arg[0]->nodetype);
392*9662Slinton 	    }
393*9662Slinton 	    break;
394*9662Slinton 
395*9662Slinton 	case O_WHERE:
396*9662Slinton 	    wherecmd();
397*9662Slinton 	    break;
398*9662Slinton 
399*9662Slinton 	case O_WHEREIS:
400*9662Slinton 	    printwhereis(stdout, p->value.arg[0]->value.sym);
401*9662Slinton 	    break;
402*9662Slinton 
403*9662Slinton 	case O_WHICH:
404*9662Slinton 	    printwhich(stdout, p->value.arg[0]->value.sym);
405*9662Slinton 	    putchar('\n');
406*9662Slinton 	    break;
407*9662Slinton 
408*9662Slinton 	case O_ALIAS:
409*9662Slinton 	    n1 = p->value.arg[0];
410*9662Slinton 	    n2 = p->value.arg[1];
411*9662Slinton 	    if (n1 == nil) {
412*9662Slinton 		print_alias(nil);
413*9662Slinton 	    } else if (n2 == nil) {
414*9662Slinton 		print_alias(n1->value.name);
415*9662Slinton 	    } else {
416*9662Slinton 		enter_alias(n1->value.name, n2->value.name);
417*9662Slinton 	    }
418*9662Slinton 	    break;
419*9662Slinton 
420*9662Slinton 	case O_CALL:
421*9662Slinton 	    callproc(p->value.arg[0], p->value.arg[1]);
422*9662Slinton 	    break;
423*9662Slinton 
424*9662Slinton 	case O_CATCH:
425*9662Slinton 	    psigtrace(process, p->value.lcon, true);
426*9662Slinton 	    break;
427*9662Slinton 
428*9662Slinton 	case O_EDIT:
429*9662Slinton 	    edit(p->value.scon);
430*9662Slinton 	    break;
431*9662Slinton 
432*9662Slinton 	case O_DUMP:
433*9662Slinton 	    dump();
434*9662Slinton 	    break;
435*9662Slinton 
436*9662Slinton 	case O_GRIPE:
437*9662Slinton 	    gripe();
438*9662Slinton 	    break;
439*9662Slinton 
440*9662Slinton 	case O_HELP:
441*9662Slinton 	    help();
442*9662Slinton 	    break;
443*9662Slinton 
444*9662Slinton 	case O_IGNORE:
445*9662Slinton 	    psigtrace(process, p->value.lcon, false);
446*9662Slinton 	    break;
447*9662Slinton 
448*9662Slinton 	case O_RUN:
449*9662Slinton 	    run();
450*9662Slinton 	    break;
451*9662Slinton 
452*9662Slinton 	case O_SOURCE:
453*9662Slinton 	    setinput(p->value.scon);
454*9662Slinton 	    break;
455*9662Slinton 
456*9662Slinton 	case O_STATUS:
457*9662Slinton 	    status();
458*9662Slinton 	    break;
459*9662Slinton 
460*9662Slinton 	case O_TRACE:
461*9662Slinton 	case O_TRACEI:
462*9662Slinton 	    trace(p);
463*9662Slinton 	    if (isstdin()) {
464*9662Slinton 		status();
465*9662Slinton 	    }
466*9662Slinton 	    break;
467*9662Slinton 
468*9662Slinton 	case O_STOP:
469*9662Slinton 	case O_STOPI:
470*9662Slinton 	    stop(p);
471*9662Slinton 	    if (isstdin()) {
472*9662Slinton 		status();
473*9662Slinton 	    }
474*9662Slinton 	    break;
475*9662Slinton 
476*9662Slinton 	case O_ADDEVENT:
477*9662Slinton 	    addevent(p->value.event.cond, p->value.event.actions);
478*9662Slinton 	    break;
479*9662Slinton 
480*9662Slinton 	case O_DELETE:
481*9662Slinton 	    delevent((unsigned int) p->value.lcon);
482*9662Slinton 	    break;
483*9662Slinton 
484*9662Slinton 	case O_ENDX:
485*9662Slinton 	    endprogram();
486*9662Slinton 	    break;
487*9662Slinton 
488*9662Slinton 	case O_IF:
489*9662Slinton 	    if (cond(p->value.event.cond)) {
490*9662Slinton 		evalcmdlist(p->value.event.actions);
491*9662Slinton 	    }
492*9662Slinton 	    break;
493*9662Slinton 
494*9662Slinton 	case O_ONCE:
495*9662Slinton 	    event_once(p->value.event.cond, p->value.event.actions);
496*9662Slinton 	    break;
497*9662Slinton 
498*9662Slinton 	case O_PRINTCALL:
499*9662Slinton 	    printcall(p->value.sym, whatblock(return_addr()));
500*9662Slinton 	    break;
501*9662Slinton 
502*9662Slinton 	case O_PRINTIFCHANGED:
503*9662Slinton 	    printifchanged(p->value.arg[0]);
504*9662Slinton 	    break;
505*9662Slinton 
506*9662Slinton 	case O_PRINTRTN:
507*9662Slinton 	    printrtn(p->value.sym);
508*9662Slinton 	    break;
509*9662Slinton 
510*9662Slinton 	case O_PRINTSRCPOS:
511*9662Slinton 	    getsrcpos();
512*9662Slinton 	    if (p->value.arg[0] == nil) {
513*9662Slinton 		printsrcpos();
514*9662Slinton 		putchar('\n');
515*9662Slinton 		printlines(curline, curline);
516*9662Slinton 	    } else if (p->value.arg[0]->op == O_QLINE) {
517*9662Slinton 		if (p->value.arg[0]->value.arg[1]->value.lcon == 0) {
518*9662Slinton 		    printf("tracei: ");
519*9662Slinton 		    printinst(pc, pc);
520*9662Slinton 		} else {
521*9662Slinton 		    printf("trace:  ");
522*9662Slinton 		    printlines(curline, curline);
523*9662Slinton 		}
524*9662Slinton 	    } else {
525*9662Slinton 		printsrcpos();
526*9662Slinton 		printf(": ");
527*9662Slinton 		eval(p->value.arg[0]);
528*9662Slinton 		prtree(stdout, p->value.arg[0]);
529*9662Slinton 		printf(" = ");
530*9662Slinton 		printval(p->value.arg[0]->nodetype);
531*9662Slinton 		putchar('\n');
532*9662Slinton 	    }
533*9662Slinton 	    break;
534*9662Slinton 
535*9662Slinton 	case O_PROCRTN:
536*9662Slinton 	    procreturn(p->value.sym);
537*9662Slinton 	    break;
538*9662Slinton 
539*9662Slinton 	case O_STOPIFCHANGED:
540*9662Slinton 	    stopifchanged(p->value.arg[0]);
541*9662Slinton 	    break;
542*9662Slinton 
543*9662Slinton 	case O_STOPX:
544*9662Slinton 	    isstopped = true;
545*9662Slinton 	    break;
546*9662Slinton 
547*9662Slinton 	case O_TRACEON:
548*9662Slinton 	    traceon(p->value.trace.inst, p->value.trace.event,
549*9662Slinton 		p->value.trace.actions);
550*9662Slinton 	    break;
551*9662Slinton 
552*9662Slinton 	case O_TRACEOFF:
553*9662Slinton 	    traceoff(p->value.lcon);
554*9662Slinton 	    break;
555*9662Slinton 
556*9662Slinton 	default:
557*9662Slinton 	    panic("eval: bad op %d", p->op);
558*9662Slinton     }
559*9662Slinton }
560*9662Slinton 
561*9662Slinton /*
562*9662Slinton  * Evaluate a list of commands.
563*9662Slinton  */
564*9662Slinton 
565*9662Slinton public evalcmdlist(cl)
566*9662Slinton Cmdlist cl;
567*9662Slinton {
568*9662Slinton     Command c;
569*9662Slinton 
570*9662Slinton     foreach (Command, c, cl)
571*9662Slinton 	evalcmd(c);
572*9662Slinton     endfor
573*9662Slinton }
574*9662Slinton 
575*9662Slinton /*
576*9662Slinton  * Push "len" bytes onto the expression stack from address "addr"
577*9662Slinton  * in the process.  If there isn't room on the stack, print an error message.
578*9662Slinton  */
579*9662Slinton 
580*9662Slinton public rpush(addr, len)
581*9662Slinton Address addr;
582*9662Slinton int len;
583*9662Slinton {
584*9662Slinton     if (not canpush(len)) {
585*9662Slinton 	error("expression too large to evaluate");
586*9662Slinton     } else {
587*9662Slinton 	chksp();
588*9662Slinton 	dread(sp, addr, len);
589*9662Slinton 	sp += len;
590*9662Slinton     }
591*9662Slinton }
592*9662Slinton 
593*9662Slinton /*
594*9662Slinton  * Check if the stack has n bytes available.
595*9662Slinton  */
596*9662Slinton 
597*9662Slinton public Boolean canpush(n)
598*9662Slinton Integer n;
599*9662Slinton {
600*9662Slinton     return (Boolean) (sp + n < &stack[STACKSIZE]);
601*9662Slinton }
602*9662Slinton 
603*9662Slinton /*
604*9662Slinton  * Push a small scalar of the given type onto the stack.
605*9662Slinton  */
606*9662Slinton 
607*9662Slinton public pushsmall(t, v)
608*9662Slinton Symbol t;
609*9662Slinton long v;
610*9662Slinton {
611*9662Slinton     register Integer s;
612*9662Slinton 
613*9662Slinton     s = size(t);
614*9662Slinton     switch (s) {
615*9662Slinton 	case sizeof(char):
616*9662Slinton 	    push(char, v);
617*9662Slinton 	    break;
618*9662Slinton 
619*9662Slinton 	case sizeof(short):
620*9662Slinton 	    push(short, v);
621*9662Slinton 	    break;
622*9662Slinton 
623*9662Slinton 	case sizeof(long):
624*9662Slinton 	    push(long, v);
625*9662Slinton 	    break;
626*9662Slinton 
627*9662Slinton 	default:
628*9662Slinton 	    panic("bad size %d in popsmall", s);
629*9662Slinton     }
630*9662Slinton }
631*9662Slinton 
632*9662Slinton /*
633*9662Slinton  * Pop an item of the given type which is assumed to be no larger
634*9662Slinton  * than a long and return it expanded into a long.
635*9662Slinton  */
636*9662Slinton 
637*9662Slinton public long popsmall(t)
638*9662Slinton Symbol t;
639*9662Slinton {
640*9662Slinton     long r;
641*9662Slinton 
642*9662Slinton     switch (size(t)) {
643*9662Slinton 	case sizeof(char):
644*9662Slinton 	    r = (long) pop(char);
645*9662Slinton 	    break;
646*9662Slinton 
647*9662Slinton 	case sizeof(short):
648*9662Slinton 	    r = (long) pop(short);
649*9662Slinton 	    break;
650*9662Slinton 
651*9662Slinton 	case sizeof(long):
652*9662Slinton 	    r = pop(long);
653*9662Slinton 	    break;
654*9662Slinton 
655*9662Slinton 	default:
656*9662Slinton 	    panic("popsmall: size is %d", size(t));
657*9662Slinton     }
658*9662Slinton     return r;
659*9662Slinton }
660*9662Slinton 
661*9662Slinton /*
662*9662Slinton  * Evaluate a conditional expression.
663*9662Slinton  */
664*9662Slinton 
665*9662Slinton public Boolean cond(p)
666*9662Slinton Node p;
667*9662Slinton {
668*9662Slinton     register Boolean b;
669*9662Slinton 
670*9662Slinton     if (p == nil) {
671*9662Slinton 	b = true;
672*9662Slinton     } else {
673*9662Slinton 	eval(p);
674*9662Slinton 	b = pop(Boolean);
675*9662Slinton     }
676*9662Slinton     return b;
677*9662Slinton }
678*9662Slinton 
679*9662Slinton /*
680*9662Slinton  * Return the address corresponding to a given tree.
681*9662Slinton  */
682*9662Slinton 
683*9662Slinton public Address lval(p)
684*9662Slinton Node p;
685*9662Slinton {
686*9662Slinton     if (p->op == O_RVAL) {
687*9662Slinton 	eval(p->value.arg[0]);
688*9662Slinton     } else {
689*9662Slinton 	eval(p);
690*9662Slinton     }
691*9662Slinton     return (Address) (pop(long));
692*9662Slinton }
693*9662Slinton 
694*9662Slinton /*
695*9662Slinton  * Process a trace command, translating into the appropriate events
696*9662Slinton  * and associated actions.
697*9662Slinton  */
698*9662Slinton 
699*9662Slinton public trace(p)
700*9662Slinton Node p;
701*9662Slinton {
702*9662Slinton     Node exp, place, cond;
703*9662Slinton     Node left;
704*9662Slinton 
705*9662Slinton     exp = p->value.arg[0];
706*9662Slinton     place = p->value.arg[1];
707*9662Slinton     cond = p->value.arg[2];
708*9662Slinton     if (exp == nil) {
709*9662Slinton 	traceall(p->op, place, cond);
710*9662Slinton     } else if (exp->op == O_QLINE) {
711*9662Slinton 	traceinst(p->op, exp, cond);
712*9662Slinton     } else if (place != nil and place->op == O_QLINE) {
713*9662Slinton 	traceat(p->op, exp, place, cond);
714*9662Slinton     } else {
715*9662Slinton 	left = (exp->op == O_RVAL) ? exp->value.arg[0] : exp;
716*9662Slinton 	if (left->op == O_SYM and isblock(left->value.sym)) {
717*9662Slinton 	    traceproc(p->op, left->value.sym, place, cond);
718*9662Slinton 	} else {
719*9662Slinton 	    tracedata(p->op, exp, place, cond);
720*9662Slinton 	}
721*9662Slinton     }
722*9662Slinton }
723*9662Slinton 
724*9662Slinton /*
725*9662Slinton  * Set a breakpoint that will turn on tracing.
726*9662Slinton  */
727*9662Slinton 
728*9662Slinton private traceall(op, place, cond)
729*9662Slinton Operator op;
730*9662Slinton Node place;
731*9662Slinton Node cond;
732*9662Slinton {
733*9662Slinton     Symbol s;
734*9662Slinton     Node event;
735*9662Slinton     Command action;
736*9662Slinton 
737*9662Slinton     if (place == nil) {
738*9662Slinton 	s = program;
739*9662Slinton     } else {
740*9662Slinton 	s = place->value.sym;
741*9662Slinton     }
742*9662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
743*9662Slinton     action = build(O_PRINTSRCPOS,
744*9662Slinton 	build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0)));
745*9662Slinton     if (cond != nil) {
746*9662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
747*9662Slinton     }
748*9662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
749*9662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
750*9662Slinton }
751*9662Slinton 
752*9662Slinton /*
753*9662Slinton  * Set up the appropriate breakpoint for tracing an instruction.
754*9662Slinton  */
755*9662Slinton 
756*9662Slinton private traceinst(op, exp, cond)
757*9662Slinton Operator op;
758*9662Slinton Node exp;
759*9662Slinton Node cond;
760*9662Slinton {
761*9662Slinton     Node event;
762*9662Slinton     Command action;
763*9662Slinton 
764*9662Slinton     if (op == O_TRACEI) {
765*9662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), exp);
766*9662Slinton     } else {
767*9662Slinton 	event = build(O_EQ, build(O_SYM, linesym), exp);
768*9662Slinton     }
769*9662Slinton     action = build(O_PRINTSRCPOS, exp);
770*9662Slinton     if (cond) {
771*9662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
772*9662Slinton     }
773*9662Slinton     addevent(event, buildcmdlist(action));
774*9662Slinton }
775*9662Slinton 
776*9662Slinton /*
777*9662Slinton  * Set a breakpoint to print an expression at a given line or address.
778*9662Slinton  */
779*9662Slinton 
780*9662Slinton private traceat(op, exp, place, cond)
781*9662Slinton Operator op;
782*9662Slinton Node exp;
783*9662Slinton Node place;
784*9662Slinton Node cond;
785*9662Slinton {
786*9662Slinton     Node event;
787*9662Slinton     Command action;
788*9662Slinton 
789*9662Slinton     if (op == O_TRACEI) {
790*9662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
791*9662Slinton     } else {
792*9662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
793*9662Slinton     }
794*9662Slinton     action = build(O_PRINTSRCPOS, exp);
795*9662Slinton     if (cond != nil) {
796*9662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
797*9662Slinton     }
798*9662Slinton     addevent(event, buildcmdlist(action));
799*9662Slinton }
800*9662Slinton 
801*9662Slinton /*
802*9662Slinton  * Construct event for tracing a procedure.
803*9662Slinton  *
804*9662Slinton  * What we want here is
805*9662Slinton  *
806*9662Slinton  * 	when $proc = p do
807*9662Slinton  *	    if <condition> then
808*9662Slinton  *	        printcall;
809*9662Slinton  *	        once $pc = $retaddr do
810*9662Slinton  *	            printrtn;
811*9662Slinton  *	        end;
812*9662Slinton  *	    end if;
813*9662Slinton  *	end;
814*9662Slinton  *
815*9662Slinton  * Note that "once" is like "when" except that the event
816*9662Slinton  * deletes itself as part of its associated action.
817*9662Slinton  */
818*9662Slinton 
819*9662Slinton private traceproc(op, p, place, cond)
820*9662Slinton Operator op;
821*9662Slinton Symbol p;
822*9662Slinton Node place;
823*9662Slinton Node cond;
824*9662Slinton {
825*9662Slinton     Node event;
826*9662Slinton     Command action;
827*9662Slinton     Cmdlist actionlist;
828*9662Slinton 
829*9662Slinton     action = build(O_PRINTCALL, p);
830*9662Slinton     actionlist = list_alloc();
831*9662Slinton     cmdlist_append(action, actionlist);
832*9662Slinton     event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym));
833*9662Slinton     action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p)));
834*9662Slinton     cmdlist_append(action, actionlist);
835*9662Slinton     if (cond != nil) {
836*9662Slinton 	actionlist = buildcmdlist(build(O_IF, cond, actionlist));
837*9662Slinton     }
838*9662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
839*9662Slinton     addevent(event, actionlist);
840*9662Slinton }
841*9662Slinton 
842*9662Slinton /*
843*9662Slinton  * Set up breakpoint for tracing data.
844*9662Slinton  */
845*9662Slinton 
846*9662Slinton private tracedata(op, exp, place, cond)
847*9662Slinton Operator op;
848*9662Slinton Node exp;
849*9662Slinton Node place;
850*9662Slinton Node cond;
851*9662Slinton {
852*9662Slinton     Symbol p;
853*9662Slinton     Node event;
854*9662Slinton     Command action;
855*9662Slinton 
856*9662Slinton     p = (place == nil) ? tcontainer(exp) : place->value.sym;
857*9662Slinton     if (p == nil) {
858*9662Slinton 	p = program;
859*9662Slinton     }
860*9662Slinton     action = build(O_PRINTIFCHANGED, exp);
861*9662Slinton     if (cond != nil) {
862*9662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
863*9662Slinton     }
864*9662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
865*9662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
866*9662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
867*9662Slinton }
868*9662Slinton 
869*9662Slinton /*
870*9662Slinton  * Setting and unsetting of stops.
871*9662Slinton  */
872*9662Slinton 
873*9662Slinton public stop(p)
874*9662Slinton Node p;
875*9662Slinton {
876*9662Slinton     Node exp, place, cond;
877*9662Slinton     Symbol s;
878*9662Slinton     Command action;
879*9662Slinton 
880*9662Slinton     exp = p->value.arg[0];
881*9662Slinton     place = p->value.arg[1];
882*9662Slinton     cond = p->value.arg[2];
883*9662Slinton     if (exp != nil) {
884*9662Slinton 	stopvar(p->op, exp, place, cond);
885*9662Slinton     } else if (cond != nil) {
886*9662Slinton 	s = (place == nil) ? program : place->value.sym;
887*9662Slinton 	action = build(O_IF, cond, buildcmdlist(build(O_STOPX)));
888*9662Slinton 	action = build(O_TRACEON, (p->op == O_STOPI), buildcmdlist(action));
889*9662Slinton 	cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
890*9662Slinton 	action->value.trace.event = addevent(cond, buildcmdlist(action));
891*9662Slinton     } else if (place->op == O_SYM) {
892*9662Slinton 	s = place->value.sym;
893*9662Slinton 	cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
894*9662Slinton 	addevent(cond, buildcmdlist(build(O_STOPX)));
895*9662Slinton     } else {
896*9662Slinton 	stopinst(p->op, place, cond);
897*9662Slinton     }
898*9662Slinton }
899*9662Slinton 
900*9662Slinton private stopinst(op, place, cond)
901*9662Slinton Operator op;
902*9662Slinton Node place;
903*9662Slinton Node cond;
904*9662Slinton {
905*9662Slinton     Node event;
906*9662Slinton 
907*9662Slinton     if (op == O_STOP) {
908*9662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
909*9662Slinton     } else {
910*9662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
911*9662Slinton     }
912*9662Slinton     addevent(event, buildcmdlist(build(O_STOPX)));
913*9662Slinton }
914*9662Slinton 
915*9662Slinton /*
916*9662Slinton  * Implement stopping on assignment to a variable by adding it to
917*9662Slinton  * the variable list.
918*9662Slinton  */
919*9662Slinton 
920*9662Slinton private stopvar(op, exp, place, cond)
921*9662Slinton Operator op;
922*9662Slinton Node exp;
923*9662Slinton Node place;
924*9662Slinton Node cond;
925*9662Slinton {
926*9662Slinton     Symbol p;
927*9662Slinton     Node event;
928*9662Slinton     Command action;
929*9662Slinton 
930*9662Slinton     p = (place == nil) ? tcontainer(exp) : place->value.sym;
931*9662Slinton     if (p == nil) {
932*9662Slinton 	p = program;
933*9662Slinton     }
934*9662Slinton     action = build(O_IF, cond, buildcmdlist(build(O_STOPIFCHANGED, exp)));
935*9662Slinton     action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action));
936*9662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
937*9662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
938*9662Slinton }
939*9662Slinton 
940*9662Slinton /*
941*9662Slinton  * Assign the value of an expression to a variable (or term).
942*9662Slinton  */
943*9662Slinton 
944*9662Slinton public assign(var, exp)
945*9662Slinton Node var;
946*9662Slinton Node exp;
947*9662Slinton {
948*9662Slinton     Address addr;
949*9662Slinton     int varsize;
950*9662Slinton     char cvalue;
951*9662Slinton     short svalue;
952*9662Slinton     long lvalue;
953*9662Slinton 
954*9662Slinton     if (not compatible(var->nodetype, exp->nodetype)) {
955*9662Slinton 	error("incompatible types");
956*9662Slinton     }
957*9662Slinton     addr = lval(var);
958*9662Slinton     eval(exp);
959*9662Slinton     varsize = size(var->nodetype);
960*9662Slinton     if (varsize < sizeof(long)) {
961*9662Slinton 	lvalue = pop(long);
962*9662Slinton 	switch (varsize) {
963*9662Slinton 	    case sizeof(char):
964*9662Slinton 		cvalue = lvalue;
965*9662Slinton 		dwrite(&cvalue, addr, varsize);
966*9662Slinton 		break;
967*9662Slinton 
968*9662Slinton 	    case sizeof(short):
969*9662Slinton 		svalue = lvalue;
970*9662Slinton 		dwrite(&svalue, addr, varsize);
971*9662Slinton 		break;
972*9662Slinton 
973*9662Slinton 	    default:
974*9662Slinton 		panic("bad size %d", varsize);
975*9662Slinton 	}
976*9662Slinton     } else {
977*9662Slinton 	sp -= varsize;
978*9662Slinton 	dwrite(sp, addr, varsize);
979*9662Slinton     }
980*9662Slinton }
981*9662Slinton 
982*9662Slinton #define DEF_EDITOR  "vi"
983*9662Slinton 
984*9662Slinton /*
985*9662Slinton  * Invoke an editor on the given file.  Which editor to use might change
986*9662Slinton  * installation to installation.  For now, we use "vi".  In any event,
987*9662Slinton  * the environment variable "EDITOR" overrides any default.
988*9662Slinton  */
989*9662Slinton 
990*9662Slinton public edit(filename)
991*9662Slinton String filename;
992*9662Slinton {
993*9662Slinton     extern String getenv();
994*9662Slinton     String ed, src;
995*9662Slinton     File f;
996*9662Slinton     Symbol s;
997*9662Slinton     Address addr;
998*9662Slinton     char buff[10];
999*9662Slinton 
1000*9662Slinton     ed = getenv("EDITOR");
1001*9662Slinton     if (ed == nil) {
1002*9662Slinton 	ed = DEF_EDITOR;
1003*9662Slinton     }
1004*9662Slinton     if (filename == nil) {
1005*9662Slinton 	call(ed, stdin, stdout, cursource, nil);
1006*9662Slinton     } else {
1007*9662Slinton 	f = fopen(filename, "r");
1008*9662Slinton 	if (f == nil) {
1009*9662Slinton 	    s = which(identname(filename, true));
1010*9662Slinton 	    if (not isblock(s)) {
1011*9662Slinton 		error("can't read \"%s\"", filename);
1012*9662Slinton 	    }
1013*9662Slinton 	    addr = firstline(s);
1014*9662Slinton 	    if (addr == NOADDR) {
1015*9662Slinton 		error("no source for \"%s\"", filename);
1016*9662Slinton 	    }
1017*9662Slinton 	    src = srcfilename(addr);
1018*9662Slinton 	    sprintf(buff, "+%d", srcline(addr));
1019*9662Slinton 	    call(ed, stdin, stdout, buff, src, nil);
1020*9662Slinton 	} else {
1021*9662Slinton 	    fclose(f);
1022*9662Slinton 	    call(ed, stdin, stdout, filename, nil);
1023*9662Slinton 	}
1024*9662Slinton     }
1025*9662Slinton }
1026*9662Slinton 
1027*9662Slinton /*
1028*9662Slinton  * Send some nasty mail to the current support person.
1029*9662Slinton  */
1030*9662Slinton 
1031*9662Slinton public gripe()
1032*9662Slinton {
1033*9662Slinton     typedef Operation();
1034*9662Slinton     Operation *old;
1035*9662Slinton 
1036*9662Slinton     char *maintainer = "linton@ucbarpa";
1037*9662Slinton 
1038*9662Slinton     puts("Type control-D to end your message.  Be sure to include");
1039*9662Slinton     puts("your name and the name of the file you are debugging.");
1040*9662Slinton     putchar('\n');
1041*9662Slinton     old = signal(SIGINT, SIG_DFL);
1042*9662Slinton     call("Mail", stdin, stdout, maintainer, nil);
1043*9662Slinton     signal(SIGINT, old);
1044*9662Slinton     puts("Thank you.");
1045*9662Slinton }
1046*9662Slinton 
1047*9662Slinton /*
1048*9662Slinton  * Give the user some help.
1049*9662Slinton  */
1050*9662Slinton 
1051*9662Slinton public help()
1052*9662Slinton {
1053*9662Slinton     puts("run                    - begin execution of the program");
1054*9662Slinton     puts("cont                   - continue execution");
1055*9662Slinton     puts("step                   - single step one line");
1056*9662Slinton     puts("next                   - step to next line (skip over calls)");
1057*9662Slinton     puts("trace <line#>          - trace execution of the line");
1058*9662Slinton     puts("trace <proc>           - trace calls to the procedure");
1059*9662Slinton     puts("trace <var>            - trace changes to the variable");
1060*9662Slinton     puts("trace <exp> at <line#> - print <exp> when <line> is reached");
1061*9662Slinton     puts("stop at <line>         - suspend execution at the line");
1062*9662Slinton     puts("stop in <proc>         - suspend execution when <proc> is called");
1063*9662Slinton     puts("status                 - print trace/stop's in effect");
1064*9662Slinton     puts("delete <number>        - remove trace or stop of given number");
1065*9662Slinton     puts("call <proc>            - call the procedure");
1066*9662Slinton     puts("where                  - print currently active procedures");
1067*9662Slinton     puts("print <exp>            - print the value of the expression");
1068*9662Slinton     puts("whatis <name>          - print the declaration of the name");
1069*9662Slinton     puts("list <line>, <line>    - list source lines");
1070*9662Slinton     puts("edit <proc>            - edit file containing <proc>");
1071*9662Slinton     puts("gripe                  - send mail to the person in charge of dbx");
1072*9662Slinton     puts("quit                   - exit dbx");
1073*9662Slinton }
1074*9662Slinton 
1075*9662Slinton /*
1076*9662Slinton  * Divert output to the given file name.
1077*9662Slinton  * Cannot redirect to an existing file.
1078*9662Slinton  */
1079*9662Slinton 
1080*9662Slinton private int so_fd;
1081*9662Slinton private Boolean notstdout;
1082*9662Slinton 
1083*9662Slinton public setout(filename)
1084*9662Slinton String filename;
1085*9662Slinton {
1086*9662Slinton     File f;
1087*9662Slinton 
1088*9662Slinton     f = fopen(filename, "r");
1089*9662Slinton     if (f != nil) {
1090*9662Slinton 	fclose(f);
1091*9662Slinton 	error("%s: file already exists", filename);
1092*9662Slinton     } else {
1093*9662Slinton 	so_fd = dup(1);
1094*9662Slinton 	close(1);
1095*9662Slinton 	if (creat(filename, 0666) == nil) {
1096*9662Slinton 	    unsetout();
1097*9662Slinton 	    error("can't create %s", filename);
1098*9662Slinton 	}
1099*9662Slinton 	notstdout = true;
1100*9662Slinton     }
1101*9662Slinton }
1102*9662Slinton 
1103*9662Slinton /*
1104*9662Slinton  * Revert output to standard output.
1105*9662Slinton  */
1106*9662Slinton 
1107*9662Slinton public unsetout()
1108*9662Slinton {
1109*9662Slinton     fflush(stdout);
1110*9662Slinton     close(1);
1111*9662Slinton     if (dup(so_fd) != 1) {
1112*9662Slinton 	panic("standard out dup failed");
1113*9662Slinton     }
1114*9662Slinton     close(so_fd);
1115*9662Slinton     notstdout = false;
1116*9662Slinton }
1117*9662Slinton 
1118*9662Slinton /*
1119*9662Slinton  * Determine is standard output is currently being redirected
1120*9662Slinton  * to a file (as far as we know).
1121*9662Slinton  */
1122*9662Slinton 
1123*9662Slinton public Boolean isredirected()
1124*9662Slinton {
1125*9662Slinton     return notstdout;
1126*9662Slinton }
1127