xref: /csrg-svn/usr.bin/pascal/src/stat.c (revision 11854)
1773Speter /* Copyright (c) 1979 Regents of the University of California */
2773Speter 
3*11854Speter static char sccsid[] = "@(#)stat.c 1.11 04/06/83";
4773Speter 
5773Speter #include "whoami.h"
6773Speter #include "0.h"
7773Speter #include "tree.h"
8773Speter #include "objfmt.h"
9773Speter #ifdef PC
10773Speter #   include "pcops.h"
11773Speter #   include "pc.h"
12773Speter #endif PC
1311330Speter #include "tmps.h"
14773Speter 
15773Speter int cntstat;
16773Speter short cnts = 3;
17773Speter #include "opcode.h"
18773Speter 
19773Speter /*
20773Speter  * Statement list
21773Speter  */
22773Speter statlist(r)
23773Speter 	int *r;
24773Speter {
25773Speter 	register *sl;
26773Speter 
27773Speter 	for (sl=r; sl != NIL; sl=sl[2])
28773Speter 		statement(sl[1]);
29773Speter }
30773Speter 
31773Speter /*
32773Speter  * Statement
33773Speter  */
34773Speter statement(r)
35773Speter 	int *r;
36773Speter {
37773Speter 	register *s;
38773Speter 	register struct nl *snlp;
393228Smckusic 	struct tmps soffset;
40773Speter 
41773Speter 	s = r;
42773Speter 	snlp = nlp;
433228Smckusic 	soffset = sizes[cbn].curtmps;
44773Speter top:
45773Speter 	if (cntstat) {
46773Speter 		cntstat = 0;
47773Speter 		putcnt();
48773Speter 	}
49773Speter 	if (s == NIL)
50773Speter 		return;
51773Speter 	line = s[1];
52773Speter 	if (s[0] == T_LABEL) {
53773Speter 		labeled(s[2]);
54773Speter 		s = s[3];
55773Speter 		noreach = 0;
56773Speter 		cntstat = 1;
57773Speter 		goto top;
58773Speter 	}
59773Speter 	if (noreach) {
60773Speter 		noreach = 0;
61773Speter 		warning();
62773Speter 		error("Unreachable statement");
63773Speter 	}
64773Speter 	switch (s[0]) {
65773Speter 		case T_PCALL:
66773Speter 			putline();
67773Speter #			ifdef OBJ
68773Speter 			    proc(s);
69773Speter #			endif OBJ
70773Speter #			ifdef PC
71773Speter 			    pcproc( s );
72773Speter #			endif PC
73773Speter 			break;
74773Speter 		case T_ASGN:
75773Speter 			putline();
76773Speter 			asgnop(s);
77773Speter 			break;
78773Speter 		case T_GOTO:
79773Speter 			putline();
80773Speter 			gotoop(s[2]);
81773Speter 			noreach = 1;
82773Speter 			cntstat = 1;
83773Speter 			break;
84773Speter 		default:
85773Speter 			level++;
86773Speter 			switch (s[0]) {
87773Speter 				default:
88773Speter 					panic("stat");
89773Speter 				case T_IF:
90773Speter 				case T_IFEL:
91773Speter 					ifop(s);
92773Speter 					break;
93773Speter 				case T_WHILE:
94773Speter 					whilop(s);
95773Speter 					noreach = 0;
96773Speter 					break;
97773Speter 				case T_REPEAT:
98773Speter 					repop(s);
99773Speter 					break;
100773Speter 				case T_FORU:
101773Speter 				case T_FORD:
1022185Smckusic 				        forop(s);
103773Speter 					noreach = 0;
104773Speter 					break;
105773Speter 				case T_BLOCK:
106773Speter 					statlist(s[2]);
107773Speter 					break;
108773Speter 				case T_CASE:
109773Speter 					putline();
110773Speter #					ifdef OBJ
111773Speter 					    caseop(s);
112773Speter #					endif OBJ
113773Speter #					ifdef PC
114773Speter 					    pccaseop( s );
115773Speter #					endif PC
116773Speter 					break;
117773Speter 				case T_WITH:
118773Speter 					withop(s);
119773Speter 					break;
120773Speter 			}
121773Speter 			--level;
122773Speter 			if (gotos[cbn])
123773Speter 				ungoto();
124773Speter 			break;
125773Speter 	}
126773Speter 	/*
127773Speter 	 * Free the temporary name list entries defined in
128773Speter 	 * expressions, e.g. STRs, and WITHPTRs from withs.
129773Speter 	 */
130773Speter 	nlfree(snlp);
131773Speter 	    /*
132773Speter 	     *	free any temporaries allocated for this statement
133773Speter 	     *	these come from strings and sets.
134773Speter 	     */
1353228Smckusic 	tmpfree(&soffset);
136773Speter }
137773Speter 
138773Speter ungoto()
139773Speter {
140773Speter 	register struct nl *p;
141773Speter 
142773Speter 	for (p = gotos[cbn]; p != NIL; p = p->chain)
143773Speter 		if ((p->nl_flags & NFORWD) != 0) {
144773Speter 			if (p->value[NL_GOLEV] != NOTYET)
145773Speter 				if (p->value[NL_GOLEV] > level)
146773Speter 					p->value[NL_GOLEV] = level;
147773Speter 		} else
148773Speter 			if (p->value[NL_GOLEV] != DEAD)
149773Speter 				if (p->value[NL_GOLEV] > level)
150773Speter 					p->value[NL_GOLEV] = DEAD;
151773Speter }
152773Speter 
153773Speter putcnt()
154773Speter {
155773Speter 
156773Speter 	if (monflg == 0) {
157773Speter 		return;
158773Speter 	}
159773Speter 	inccnt( getcnt() );
160773Speter }
161773Speter 
162773Speter int
163773Speter getcnt()
164773Speter     {
165773Speter 
166773Speter 	return ++cnts;
167773Speter     }
168773Speter 
169773Speter inccnt( counter )
170773Speter     int	counter;
171773Speter     {
172773Speter 
173773Speter #	ifdef OBJ
1743079Smckusic 	    put(2, O_COUNT, counter );
175773Speter #	endif OBJ
176773Speter #	ifdef PC
1773835Speter 	    putRV( PCPCOUNT , 0 , counter * sizeof (long) , NGLOBAL , P2INT );
178773Speter 	    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
179773Speter 	    putop( P2ASG P2PLUS , P2INT );
180773Speter 	    putdot( filename , line );
181773Speter #	endif PC
182773Speter     }
183773Speter 
184773Speter putline()
185773Speter {
186773Speter 
187773Speter #	ifdef OBJ
188773Speter 	    if (opt('p') != 0)
1893079Smckusic 		    put(2, O_LINO, line);
1905654Slinton 
1915654Slinton 	    /*
1925654Slinton 	     * put out line number information for pdx
1935654Slinton 	     */
1945654Slinton 	    lineno(line);
1955654Slinton 
196773Speter #	endif OBJ
197773Speter #	ifdef PC
198773Speter 	    static lastline;
199773Speter 
200773Speter 	    if ( line != lastline ) {
201773Speter 		stabline( line );
202773Speter 		lastline = line;
203773Speter 	    }
204773Speter 	    if ( opt( 'p' ) ) {
205773Speter 		if ( opt('t') ) {
206773Speter 		    putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
207773Speter 			    , "_LINO" );
208773Speter 		    putop( P2UNARY P2CALL , P2INT );
209773Speter 		    putdot( filename , line );
210773Speter 		} else {
2113835Speter 		    putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT );
212773Speter 		    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
213773Speter 		    putop( P2ASG P2PLUS , P2INT );
214773Speter 		    putdot( filename , line );
215773Speter 		}
216773Speter 	    }
217773Speter #	endif PC
218773Speter }
219773Speter 
220773Speter /*
221773Speter  * With varlist do stat
222773Speter  *
223773Speter  * With statement requires an extra word
224773Speter  * in automatic storage for each level of withing.
225773Speter  * These indirect pointers are initialized here, and
226773Speter  * the scoping effect of the with statement occurs
227773Speter  * because lookup examines the field names of the records
228773Speter  * associated with the WITHPTRs on the withlist.
229773Speter  */
230773Speter withop(s)
231773Speter 	int *s;
232773Speter {
233773Speter 	register *p;
234773Speter 	register struct nl *r;
2353835Speter 	struct nl	*tempnlp;
236773Speter 	int *swl;
237773Speter 
238773Speter 	putline();
239773Speter 	swl = withlist;
240773Speter 	for (p = s[2]; p != NIL; p = p[2]) {
2413835Speter 		tempnlp = tmpalloc(sizeof(int *), INT_TYP, REGOK);
242773Speter #		ifdef OBJ
2433835Speter 		    put(2, O_LV | cbn <<8+INDX, tempnlp -> value[ NL_OFFS ] );
244773Speter #		endif OBJ
245773Speter #		ifdef PC
2463835Speter 		    putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
2473835Speter 			    tempnlp -> extra_flags , P2PTR|P2STRTY );
248773Speter #		endif PC
249773Speter 		r = lvalue(p[1], MOD , LREQ );
250773Speter 		if (r == NIL)
251773Speter 			continue;
252773Speter 		if (r->class != RECORD) {
253773Speter 			error("Variable in with statement refers to %s, not to a record", nameof(r));
254773Speter 			continue;
255773Speter 		}
2563835Speter 		r = defnl(0, WITHPTR, r, tempnlp -> value[ NL_OFFS ] );
2573835Speter #		ifdef PC
2583835Speter 		    r -> extra_flags |= tempnlp -> extra_flags;
2593835Speter #		endif PC
260773Speter 		r->nl_next = withlist;
261773Speter 		withlist = r;
262773Speter #		ifdef OBJ
263773Speter 		    put(1, PTR_AS);
264773Speter #		endif OBJ
265773Speter #		ifdef PC
266773Speter 		    putop( P2ASSIGN , P2PTR|P2STRTY );
267773Speter 		    putdot( filename , line );
268773Speter #		endif PC
269773Speter 	}
270773Speter 	statement(s[3]);
271773Speter 	withlist = swl;
272773Speter }
273773Speter 
274773Speter extern	flagwas;
275773Speter /*
276773Speter  * var := expr
277773Speter  */
278773Speter asgnop(r)
279773Speter 	int *r;
280773Speter {
281773Speter 	register struct nl *p;
282773Speter 	register *av;
283773Speter 
284773Speter 	if (r == NIL)
285773Speter 		return (NIL);
286773Speter 	/*
287773Speter 	 * Asgnop's only function is
288773Speter 	 * to handle function variable
289773Speter 	 * assignments.  All other assignment
290773Speter 	 * stuff is handled by asgnop1.
291773Speter 	 * the if below checks for unqualified lefthandside:
292773Speter 	 * necessary for fvars.
293773Speter 	 */
294773Speter 	av = r[2];
295773Speter 	if (av != NIL && av[0] == T_VAR && av[3] == NIL) {
296773Speter 		p = lookup1(av[2]);
297773Speter 		if (p != NIL)
298773Speter 			p->nl_flags = flagwas;
299773Speter 		if (p != NIL && p->class == FVAR) {
300773Speter 			/*
301773Speter 			 * Give asgnop1 the func
302773Speter 			 * which is the chain of
303773Speter 			 * the FVAR.
304773Speter 			 */
305773Speter 			p->nl_flags |= NUSED|NMOD;
306773Speter 			p = p->chain;
307773Speter 			if (p == NIL) {
308773Speter 				rvalue(r[3], NIL , RREQ );
309773Speter 				return;
310773Speter 			}
311773Speter #			ifdef OBJ
3123079Smckusic 			    put(2, O_LV | bn << 8+INDX, (int)p->value[NL_OFFS]);
313773Speter 			    if (isa(p->type, "i") && width(p->type) == 1)
314773Speter 				    asgnop1(r, nl+T2INT);
315773Speter 			    else
316773Speter 				    asgnop1(r, p->type);
317773Speter #			endif OBJ
318773Speter #			ifdef PC
319773Speter 				/*
320773Speter 				 * this should be the lvalue of the fvar,
321773Speter 				 * but since the second pass knows to use
322773Speter 				 * the address of the left operand of an
323773Speter 				 * assignment, what i want here is an rvalue.
324773Speter 				 * see note in funchdr about fvar allocation.
325773Speter 				 */
326773Speter 			    p = p -> ptr[ NL_FVAR ];
3273835Speter 			    putRV( p -> symbol , bn , p -> value[ NL_OFFS ] ,
3283835Speter 				    p -> extra_flags , p2type( p -> type ) );
329773Speter 			    asgnop1( r , p -> type );
330773Speter #			endif PC
331773Speter 			return;
332773Speter 		}
333773Speter 	}
334773Speter 	asgnop1(r, NIL);
335773Speter }
336773Speter 
337773Speter /*
338773Speter  * Asgnop1 handles all assignments.
339773Speter  * If p is not nil then we are assigning
340773Speter  * to a function variable, otherwise
341773Speter  * we look the variable up ourselves.
342773Speter  */
343773Speter struct nl *
344773Speter asgnop1(r, p)
345773Speter 	int *r;
346773Speter 	register struct nl *p;
347773Speter {
348773Speter 	register struct nl *p1;
3493079Smckusic 	int w;
350773Speter 
351773Speter 	if (r == NIL)
352773Speter 		return (NIL);
353773Speter 	if (p == NIL) {
354773Speter #	    ifdef OBJ
355773Speter 		p = lvalue(r[2], MOD|ASGN|NOUSE , LREQ );
3563079Smckusic 		w = width(p);
357773Speter #	    endif OBJ
358773Speter #	    ifdef PC
359773Speter 		    /*
360773Speter 		     * since the second pass knows that it should reference
361773Speter 		     * the lefthandside of asignments, what i need here is
362773Speter 		     * an rvalue.
363773Speter 		     */
364773Speter 		p = lvalue( r[2] , MOD|ASGN|NOUSE , RREQ );
365773Speter #	    endif PC
366773Speter 	    if ( p == NIL ) {
367773Speter 		rvalue( r[3] , NIL , RREQ );
368773Speter 		return NIL;
369773Speter 	    }
370773Speter 	}
371773Speter #	ifdef OBJ
3723079Smckusic 	    /*
3733079Smckusic 	     * assigning to the return value, which is at least
3743079Smckusic 	     * of width two since it resides on the stack
3753079Smckusic 	     */
3763079Smckusic 	    else {
3773079Smckusic 		w = width(p);
3783079Smckusic 		if (w < 2)
3793079Smckusic 		    w = 2;
3803079Smckusic 	    }
381773Speter 	    p1 = rvalue(r[3], p , RREQ );
382773Speter #	endif OBJ
383773Speter #	ifdef PC
384773Speter 		/*
385773Speter 		 *	if this is a scalar assignment,
386773Speter 		 *	    then i want to rvalue the righthandside.
387773Speter 		 *	if this is a structure assignment,
388773Speter 		 *	    then i want an lvalue to the righthandside.
389773Speter 		 *  that's what the intermediate form sez.
390773Speter 		 */
391773Speter 	    switch ( classify( p ) ) {
392773Speter 		case TINT:
393773Speter 		case TCHAR:
394773Speter 		case TBOOL:
395773Speter 		case TSCAL:
396773Speter 		    precheck( p , "_RANG4" , "_RSNG4" );
397773Speter 		case TDOUBLE:
398773Speter 		case TPTR:
399773Speter 		    p1 = rvalue( r[3] , p , RREQ );
400773Speter 		    break;
401773Speter 		default:
402773Speter 		    p1 = rvalue( r[3] , p , LREQ );
403773Speter 		    break;
404773Speter 	    }
405773Speter #	endif PC
406773Speter 	if (p1 == NIL)
407773Speter 		return (NIL);
408773Speter 	if (incompat(p1, p, r[3])) {
409773Speter 		cerror("Type of expression clashed with type of variable in assignment");
410773Speter 		return (NIL);
411773Speter 	}
4128758Speter #	ifdef OBJ
4138758Speter 	    switch (classify(p)) {
4148758Speter 		    case TINT:
4158758Speter 		    case TBOOL:
4168758Speter 		    case TCHAR:
4178758Speter 		    case TSCAL:
418773Speter 			    rangechk(p, p1);
4198758Speter 			    gen(O_AS2, O_AS2, w, width(p1));
4208758Speter 			    break;
4218758Speter 		    case TDOUBLE:
4228758Speter 		    case TPTR:
4238758Speter 			    gen(O_AS2, O_AS2, w, width(p1));
4248758Speter 			    break;
4258758Speter 		    default:
4268758Speter 			    put(2, O_AS, w);
4278758Speter 			    break;
4288758Speter 	    }
4298758Speter #	endif OBJ
4308758Speter #	ifdef PC
4318758Speter 	    switch (classify(p)) {
4328758Speter 		    case TINT:
4338758Speter 		    case TBOOL:
4348758Speter 		    case TCHAR:
4358758Speter 		    case TSCAL:
43610362Smckusick 			    postcheck(p, p1);
43710362Smckusick 			    sconv(p2type(p1), p2type(p));
438773Speter 			    putop( P2ASSIGN , p2type( p ) );
439773Speter 			    putdot( filename , line );
4408758Speter 			    break;
4418758Speter 		    case TPTR:
4428758Speter 			    putop( P2ASSIGN , p2type( p ) );
4438758Speter 			    putdot( filename , line );
4448758Speter 			    break;
4458758Speter 		    case TDOUBLE:
44610362Smckusick 			    sconv(p2type(p1), p2type(p));
4478758Speter 			    putop( P2ASSIGN , p2type( p ) );
4488758Speter 			    putdot( filename , line );
4498758Speter 			    break;
4508758Speter 		    default:
451*11854Speter 			    putstrop(P2STASG, ADDTYPE(p2type(p), P2PTR),
452*11854Speter 					lwidth(p), align(p));
453773Speter 			    putdot( filename , line );
4548758Speter 			    break;
4558758Speter 	    }
4568758Speter #	endif PC
457773Speter 	return (p);	/* Used by for statement */
458773Speter }
459773Speter 
460773Speter /*
461773Speter  * if expr then stat [ else stat ]
462773Speter  */
463773Speter ifop(r)
464773Speter 	int *r;
465773Speter {
466773Speter 	register struct nl *p;
467773Speter 	register l1, l2;	/* l1 is start of else, l2 is end of else */
4683079Smckusic 	int goc;
4693079Smckusic 	bool nr;
470773Speter 
471773Speter 	goc = gocnt;
472773Speter 	if (r == NIL)
473773Speter 		return;
474773Speter 	putline();
475773Speter 	p = rvalue(r[2], NIL , RREQ );
476773Speter 	if (p == NIL) {
477773Speter 		statement(r[3]);
478773Speter 		noreach = 0;
479773Speter 		statement(r[4]);
480773Speter 		noreach = 0;
481773Speter 		return;
482773Speter 	}
483773Speter 	if (isnta(p, "b")) {
484773Speter 		error("Type of expression in if statement must be Boolean, not %s", nameof(p));
485773Speter 		statement(r[3]);
486773Speter 		noreach = 0;
487773Speter 		statement(r[4]);
488773Speter 		noreach = 0;
489773Speter 		return;
490773Speter 	}
491773Speter #	ifdef OBJ
4923079Smckusic 	    l1 = put(2, O_IF, getlab());
493773Speter #	endif OBJ
494773Speter #	ifdef PC
495773Speter 	    l1 = getlab();
496773Speter 	    putleaf( P2ICON , l1 , 0 , P2INT , 0 );
497773Speter 	    putop( P2CBRANCH , P2INT );
498773Speter 	    putdot( filename , line );
499773Speter #	endif PC
500773Speter 	putcnt();
501773Speter 	statement(r[3]);
502773Speter 	nr = noreach;
503773Speter 	if (r[4] != NIL) {
504773Speter 		/*
505773Speter 		 * else stat
506773Speter 		 */
507773Speter 		--level;
508773Speter 		ungoto();
509773Speter 		++level;
510773Speter #		ifdef OBJ
5113079Smckusic 		    l2 = put(2, O_TRA, getlab());
512773Speter #		endif OBJ
513773Speter #		ifdef PC
514773Speter 		    l2 = getlab();
515773Speter 		    putjbr( l2 );
516773Speter #		endif PC
517773Speter 		patch(l1);
518773Speter 		noreach = 0;
519773Speter 		statement(r[4]);
5203079Smckusic 		noreach = (noreach && nr);
521773Speter 		l1 = l2;
522773Speter 	} else
523773Speter 		noreach = 0;
524773Speter 	patch(l1);
525773Speter 	if (goc != gocnt)
526773Speter 		putcnt();
527773Speter }
528773Speter 
529773Speter /*
530773Speter  * while expr do stat
531773Speter  */
532773Speter whilop(r)
533773Speter 	int *r;
534773Speter {
535773Speter 	register struct nl *p;
536773Speter 	register l1, l2;
537773Speter 	int goc;
538773Speter 
539773Speter 	goc = gocnt;
540773Speter 	if (r == NIL)
541773Speter 		return;
542773Speter 	putlab(l1 = getlab());
543773Speter 	putline();
544773Speter 	p = rvalue(r[2], NIL , RREQ );
545773Speter 	if (p == NIL) {
546773Speter 		statement(r[3]);
547773Speter 		noreach = 0;
548773Speter 		return;
549773Speter 	}
550773Speter 	if (isnta(p, "b")) {
551773Speter 		error("Type of expression in while statement must be Boolean, not %s", nameof(p));
552773Speter 		statement(r[3]);
553773Speter 		noreach = 0;
554773Speter 		return;
555773Speter 	}
556773Speter 	l2 = getlab();
557773Speter #	ifdef OBJ
5583079Smckusic 	    put(2, O_IF, l2);
559773Speter #	endif OBJ
560773Speter #	ifdef PC
561773Speter 	    putleaf( P2ICON , l2 , 0 , P2INT , 0 );
562773Speter 	    putop( P2CBRANCH , P2INT );
563773Speter 	    putdot( filename , line );
564773Speter #	endif PC
565773Speter 	putcnt();
566773Speter 	statement(r[3]);
567773Speter #	ifdef OBJ
5683079Smckusic 	    put(2, O_TRA, l1);
569773Speter #	endif OBJ
570773Speter #	ifdef PC
571773Speter 	    putjbr( l1 );
572773Speter #	endif PC
573773Speter 	patch(l2);
574773Speter 	if (goc != gocnt)
575773Speter 		putcnt();
576773Speter }
577773Speter 
578773Speter /*
579773Speter  * repeat stat* until expr
580773Speter  */
581773Speter repop(r)
582773Speter 	int *r;
583773Speter {
584773Speter 	register struct nl *p;
585773Speter 	register l;
586773Speter 	int goc;
587773Speter 
588773Speter 	goc = gocnt;
589773Speter 	if (r == NIL)
590773Speter 		return;
591773Speter 	l = putlab(getlab());
592773Speter 	putcnt();
593773Speter 	statlist(r[2]);
594773Speter 	line = r[1];
595773Speter 	p = rvalue(r[3], NIL , RREQ );
596773Speter 	if (p == NIL)
597773Speter 		return;
598773Speter 	if (isnta(p,"b")) {
599773Speter 		error("Until expression type must be Boolean, not %s, in repeat statement", nameof(p));
600773Speter 		return;
601773Speter 	}
602773Speter #	ifdef OBJ
6033079Smckusic 	    put(2, O_IF, l);
604773Speter #	endif OBJ
605773Speter #	ifdef PC
606773Speter 	    putleaf( P2ICON , l , 0 , P2INT , 0 );
607773Speter 	    putop( P2CBRANCH , P2INT );
608773Speter 	    putdot( filename , line );
609773Speter #	endif PC
610773Speter 	if (goc != gocnt)
611773Speter 		putcnt();
612773Speter }
613